|
20 | 20 |
|
21 | 21 | #include "bittype.h" |
22 | 22 | #include <string.h> |
| 23 | +#include <ctype.h> |
23 | 24 |
|
24 | 25 |
|
25 | 26 | // Declaration |
@@ -55,6 +56,14 @@ template<size_t Size> size_t strlmove_t(char (&dst)[Size], const char *src); |
55 | 56 | template<size_t Size> size_t strlmcat_t(char (&dst)[Size], const char *src); |
56 | 57 | #endif |
57 | 58 |
|
| 59 | +template<typename T> int strncmp_t(const T *str1, const T *str2, size_t maxcount); |
| 60 | +template<typename T> int strnicmp_t(const T* str1, const T* str2, size_t maxcount); |
| 61 | + |
| 62 | +template<typename T> bool startsWith(const T *str, const T *prefix); |
| 63 | +template<typename T> bool startsWithNoCase(const T *str, const T *prefix); |
| 64 | +template<typename T> bool endsWithNoCase(const T *str, const T *suffix); |
| 65 | +template<typename T> bool endsWithNoCase(const T *str, const T *suffix); |
| 66 | + |
58 | 67 |
|
59 | 68 | // Implementation |
60 | 69 |
|
@@ -182,3 +191,112 @@ template<size_t Size> size_t strlcat_t(char (&dst)[Size], const char *src) { ret |
182 | 191 | template<size_t Size> size_t strlmove_t(char (&dst)[Size], const char *src) { return strlmove_t(dst, src, Size); } |
183 | 192 | template<size_t Size> size_t strlmcat_t(char (&dst)[Size], const char *src) { return strlmcat_t(dst, src, Size); } |
184 | 193 | #endif |
| 194 | + |
| 195 | +// Templated strncmp. |
| 196 | +// Compares up to maxcount chars or a null byte is encountered, whichever comes first. |
| 197 | +// Returns < 0 if str1 is less than str2, 0 is str1 and str2 are equal and > 0 if str2 is greater than str1. |
| 198 | +template<typename T> int strncmp_t(const T *str1, const T *str2, const size_t maxcount) |
| 199 | +{ |
| 200 | + for (size_t i = 0; i < maxcount; ++i) |
| 201 | + { |
| 202 | + const T c1 = str1[i]; |
| 203 | + const T c2 = str2[i]; |
| 204 | + const int diff = (int)c1 - (int)c2; |
| 205 | + if (diff != 0) |
| 206 | + { |
| 207 | + return diff; |
| 208 | + } |
| 209 | + if (c1 == T(0)) // both c1 and c2 are null terminators |
| 210 | + { |
| 211 | + return 0; |
| 212 | + } |
| 213 | + } |
| 214 | + return 0; |
| 215 | +} |
| 216 | + |
| 217 | +// Lower case conversion helpers |
| 218 | +inline char tolower_t(char c) |
| 219 | +{ |
| 220 | + // cast to unsigned char for correct behavior of tolower() |
| 221 | + return (char)tolower((unsigned char)c); |
| 222 | +} |
| 223 | + |
| 224 | +inline wchar_t tolower_t(wchar_t c) |
| 225 | +{ |
| 226 | + return (wchar_t)towlower(c); |
| 227 | +} |
| 228 | + |
| 229 | +// Templated strnicmp. |
| 230 | +// Case insensitively compares up to maxcount chars or a null byte is encountered, whichever comes first. |
| 231 | +// Returns < 0 if str1 is less than str2, 0 is str1 and str2 are equal and > 0 if str2 is greater than str1. |
| 232 | +template<typename T> int strnicmp_t(const T *str1, const T *str2, const size_t maxcount) |
| 233 | +{ |
| 234 | + for (size_t i = 0; i < maxcount; ++i) |
| 235 | + { |
| 236 | + const T c1 = tolower_t(str1[i]); |
| 237 | + const T c2 = tolower_t(str2[i]); |
| 238 | + const int diff = (int)c1 - (int)c2; |
| 239 | + if (diff != 0) |
| 240 | + { |
| 241 | + return diff; |
| 242 | + } |
| 243 | + if (c1 == T(0)) // both c1 and c2 are null terminators |
| 244 | + { |
| 245 | + return 0; |
| 246 | + } |
| 247 | + } |
| 248 | + return 0; |
| 249 | +} |
| 250 | + |
| 251 | +template<typename T> inline bool startsWith(const T *str, const T *prefix) |
| 252 | +{ |
| 253 | + if (*prefix == T(0)) |
| 254 | + return true; // everything starts with the empty string |
| 255 | + |
| 256 | + const size_t strlen = strlen_t(str); |
| 257 | + const size_t prefixlen = strlen_t(prefix); |
| 258 | + if (strlen < prefixlen) |
| 259 | + return false; // prefix must be as long or shorter than str |
| 260 | + |
| 261 | + return strncmp_t(str, prefix, prefixlen) == 0; |
| 262 | +} |
| 263 | + |
| 264 | +template<typename T> inline bool startsWithNoCase(const T *str, const T *prefix) |
| 265 | +{ |
| 266 | + if (*prefix == T(0)) |
| 267 | + return true; // everything starts with the empty string |
| 268 | + |
| 269 | + const size_t strlen = strlen_t(str); |
| 270 | + const size_t prefixlen = strlen_t(prefix); |
| 271 | + if (strlen < prefixlen) |
| 272 | + return false; // prefix must be as long or shorter than str |
| 273 | + |
| 274 | + return strnicmp_t(str, prefix, prefixlen) == 0; |
| 275 | +} |
| 276 | + |
| 277 | +template<typename T> inline bool endsWith(const T *str, const T *suffix) |
| 278 | +{ |
| 279 | + if (*suffix == T(0)) |
| 280 | + return true; // everything ends with the empty string |
| 281 | + |
| 282 | + const size_t strlen = strlen_t(str); |
| 283 | + const size_t suffixlen = strlen_t(suffix); |
| 284 | + if (strlen < suffixlen) |
| 285 | + return false; // suffix must be as long or shorter than str |
| 286 | + |
| 287 | + return strncmp_t(str + strlen - suffixlen, suffix, suffixlen) == 0; |
| 288 | +} |
| 289 | + |
| 290 | +template<typename T> inline bool endsWithNoCase(const T *str, const T *suffix) |
| 291 | +{ |
| 292 | + if (*suffix == T(0)) |
| 293 | + return true; // everything ends with the empty string |
| 294 | + |
| 295 | + const size_t strlen = strlen_t(str); |
| 296 | + const size_t suffixlen = strlen_t(suffix); |
| 297 | + if (strlen < suffixlen) |
| 298 | + return false; // suffix must be as long or shorter than str |
| 299 | + |
| 300 | + return strnicmp_t(str + strlen - suffixlen, suffix, suffixlen) == 0; |
| 301 | +} |
| 302 | + |
0 commit comments