2020
2121#include " bittype.h"
2222#include < string.h>
23+ #include < ctype.h>
2324
2425
2526// Declaration
@@ -55,6 +56,14 @@ template<size_t Size> size_t strlmove_t(char (&dst)[Size], const char *src);
5556template <size_t Size> size_t strlmcat_t (char (&dst)[Size], const char *src);
5657#endif
5758
59+ template <typename CharT> int strncmp_t (const CharT *str1, const CharT *str2, size_t maxcount);
60+ template <typename CharT> int strnicmp_t (const CharT* str1, const CharT* str2, size_t maxcount);
61+
62+ template <typename CharT> bool startsWith (const CharT *str, const CharT *prefix);
63+ template <typename CharT> bool startsWithNoCase (const CharT *str, const CharT *prefix);
64+ template <typename CharT> bool endsWithNoCase (const CharT *str, const CharT *suffix);
65+ template <typename CharT> bool endsWithNoCase (const CharT *str, const CharT *suffix);
66+
5867
5968// Implementation
6069
@@ -183,106 +192,140 @@ template<size_t Size> size_t strlmove_t(char (&dst)[Size], const char *src) { re
183192template <size_t Size> size_t strlmcat_t (char (&dst)[Size], const char *src) { return strlmcat_t (dst, src, Size); }
184193#endif
185194
186- inline bool startsWith (const char *str, const char *prefix)
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 CharT> int strncmp_t (const CharT *str1, const CharT *str2, const size_t maxcount)
187199{
188- if (*prefix == char (0 ))
189- return true ; // everything starts with the empty string
200+ if (str1 == nullptr || str2 == nullptr )
201+ {
202+ switch (str1)
203+ {
204+ case str2:
205+ return 0 ;
206+ case nullptr :
207+ return -1 ;
208+ default :
209+ return 1 ;
210+ }
211+ }
212+ for (size_t i = 0 ; i < maxcount; ++i)
213+ {
214+ CharT c1 = str1[i];
215+ CharT c2 = str2[i];
216+ int diff = c1 - c2;
217+ if (diff != 0 )
218+ {
219+ return diff;
220+ }
221+ if (c1 == CharT (0 )) // both c1 and c2 are null terminators
222+ {
223+ return 0 ;
224+ }
225+ }
226+ return 0 ;
227+ }
190228
191- const size_t strlen = ::strlen (str);
192- const size_t prefixlen = ::strlen (prefix);
193- if (strlen < prefixlen)
194- return false ; // prefix must be as long or shorter than str
229+ // Lower case conversion helpers
230+ inline char tolower_t (char c) {
231+ // cast to unsigned char for correct behavior of tolower()
232+ return (char )::tolower ((unsigned char )c);
233+ }
195234
196- return ::strncmp (str, prefix, prefixlen) == 0 ;
235+ inline wchar_t tolower_t (wchar_t c) {
236+ return (wchar_t )::towlower (c);
197237}
198238
199- inline bool startsWith (const wchar_t *str, const wchar_t *prefix)
239+ // Templated strnicmp.
240+ // Case insensitively compares up to maxcount chars or a null byte is encountered, whichever comes first.
241+ // Returns < 0 if str1 is less than str2, 0 is str1 and str2 are equal and > 0 if str2 is greater than str1.
242+ template <typename CharT> int strnicmp_t (const CharT *str1, const CharT *str2, const size_t maxcount)
200243{
201- if (*prefix == wchar_t (0 ))
202- return true ; // everything starts with the empty string
203-
204- const size_t strlen = ::wcslen (str);
205- const size_t prefixlen = ::wcslen (prefix);
206- if (strlen < prefixlen)
207- return false ; // prefix must be as long or shorter than str
208-
209- return ::wcsncmp (str, prefix, prefixlen) == 0 ;
244+ if (str1 == nullptr || str2 == nullptr )
245+ {
246+ switch (str1)
247+ {
248+ case str2:
249+ return 0 ;
250+ case nullptr :
251+ return -1 ;
252+ default :
253+ return 1 ;
254+ }
255+ }
256+ for (size_t i = 0 ; i < maxcount; ++i)
257+ {
258+ CharT c1 = tolower_t (str1[i]);
259+ CharT c2 = tolower_t (str2[i]);
260+ int diff = c1 - c2;
261+ if (diff != 0 )
262+ {
263+ return diff;
264+ }
265+ if (c1 == CharT (0 )) // both c1 and c2 are null terminators
266+ {
267+ return 0 ;
268+ }
269+ }
270+ return 0 ;
210271}
211272
212- inline bool startsWithNoCase (const char *str, const char *prefix)
273+ inline int strncmp_t (const char *str1, const char *str2, size_t maxcount) { return ::strncmp (str1, str2, maxcount); };
274+ inline int strncmp_t (const wchar_t *str1, const wchar_t *str2, size_t maxcount) { return ::wcsncmp (str1, str2, maxcount); };
275+ #ifdef _WIN32
276+ inline int strnicmp_t (const char *str1, const char *str2, size_t maxcount) { return ::_strnicmp (str1, str2, maxcount); };
277+ inline int strnicmp_t (const wchar_t *str1, const wchar_t *str2, size_t maxcount) { return ::_wcsnicmp (str1, str2, maxcount); };
278+ #endif
279+
280+ template <typename CharT> inline bool startsWith (const CharT *str, const CharT *prefix)
213281{
214- if (*prefix == char (0 ))
282+ if (*prefix == CharT (0 ))
215283 return true ; // everything starts with the empty string
216284
217- const size_t strlen = ::strlen (str);
218- const size_t prefixlen = ::strlen (prefix);
285+ const size_t strlen = ::strlen_t (str);
286+ const size_t prefixlen = ::strlen_t (prefix);
219287 if (strlen < prefixlen)
220288 return false ; // prefix must be as long or shorter than str
221289
222- return :: strnicmp (str, prefix, prefixlen) == 0 ;
290+ return strncmp_t (str, prefix, prefixlen) == 0 ;
223291}
224292
225- inline bool startsWithNoCase (const wchar_t *str, const wchar_t *prefix)
293+ template < typename CharT> inline bool startsWithNoCase (const CharT *str, const CharT *prefix)
226294{
227- if (*prefix == wchar_t (0 ))
295+ if (*prefix == CharT (0 ))
228296 return true ; // everything starts with the empty string
229297
230- const size_t strlen = ::wcslen (str);
231- const size_t prefixlen = ::wcslen (prefix);
298+ const size_t strlen = ::strlen_t (str);
299+ const size_t prefixlen = ::strlen_t (prefix);
232300 if (strlen < prefixlen)
233301 return false ; // prefix must be as long or shorter than str
234302
235- return ::wcsnicmp (str, prefix, prefixlen) == 0 ;
236- }
237-
238- inline bool endsWith (const char *str, const char *suffix)
239- {
240- if (*suffix == char (0 ))
241- return true ; // everything ends with the empty string
242-
243- const size_t strlen = ::strlen (str);
244- const size_t suffixlen = ::strlen (suffix);
245- if (strlen < suffixlen)
246- return false ; // suffix must be as long or shorter than str
247-
248- return ::strncmp (str + strlen - suffixlen, suffix, suffixlen) == 0 ;
303+ return strnicmp_t (str, prefix, prefixlen) == 0 ;
249304}
250305
251- inline bool endsWith (const wchar_t *str, const wchar_t *suffix)
306+ template < typename CharT> inline bool endsWith (const CharT *str, const CharT *suffix)
252307{
253- if (*suffix == wchar_t (0 ))
308+ if (*suffix == CharT (0 ))
254309 return true ; // everything ends with the empty string
255310
256- const size_t strlen = ::wcslen (str);
257- const size_t suffixlen = ::wcslen (suffix);
311+ const size_t strlen = ::strlen_t (str);
312+ const size_t suffixlen = ::strlen_t (suffix);
258313 if (strlen < suffixlen)
259314 return false ; // suffix must be as long or shorter than str
260315
261- return :: wcsncmp (str + strlen - suffixlen, suffix, suffixlen) == 0 ;
316+ return strncmp_t (str + strlen - suffixlen, suffix, suffixlen) == 0 ;
262317}
263318
264- inline bool endsWithNoCase (const char *str, const char *suffix)
319+ template < typename CharT> inline bool endsWithNoCase (const CharT *str, const CharT *suffix)
265320{
266- if (*suffix == char (0 ))
321+ if (*suffix == CharT (0 ))
267322 return true ; // everything ends with the empty string
268323
269- const size_t strlen = ::strlen (str);
270- const size_t suffixlen = ::strlen (suffix);
324+ const size_t strlen = ::strlen_t (str);
325+ const size_t suffixlen = ::strlen_t (suffix);
271326 if (strlen < suffixlen)
272327 return false ; // suffix must be as long or shorter than str
273328
274- return :: strnicmp (str + strlen - suffixlen, suffix, suffixlen) == 0 ;
329+ return strnicmp_t (str + strlen - suffixlen, suffix, suffixlen) == 0 ;
275330}
276331
277- inline bool endsWithNoCase (const wchar_t *str, const wchar_t *suffix)
278- {
279- if (*suffix == wchar_t (0 ))
280- return true ; // everything ends with the empty string
281-
282- const size_t strlen = ::wcslen (str);
283- const size_t suffixlen = ::wcslen (suffix);
284- if (strlen < suffixlen)
285- return false ; // suffix must be as long or shorter than str
286-
287- return ::wcsnicmp (str + strlen - suffixlen, suffix, suffixlen) == 0 ;
288- }
0 commit comments