Torque3D Documentation / _generateds / stringFunctions.cpp

stringFunctions.cpp

Engine/source/core/strings/stringFunctions.cpp

More...

Public Typedefs

char
nat_char 

Public Functions

int
dItoa(int n, char s)
dPrintf(const char * format, ... )
dSprintf(char * buffer, U32 bufferSize, const char * format, ... )
dSscanf(const char * buffer, const char * format, ... )
char *
dStrcatl(char * dst, dsize_t dstSize, ... )
dStrcmp(const UTF16 * str1, const UTF16 * str2)
char *
dStrcpyl(char * dst, dsize_t dstSize, ... )
char *
dStrdup_r(const char * src, const char * fileName, dsize_t lineNumber)
bool
dStrEndsWith(const char * str1, const char * str2)

Check if one string ends with another.

bool
dStrEqual(const char * str1, const char * str2)

Safe form of dStrcmp: checks both strings for NULL before comparing.

char *
dStrichr(char * str, char ch)
const char *
dStrichr(const char * str, char ch)
char *
dStripPath(const char * filename)

Strip the path from the input filename.

char *
dStristr(char * str1, const char * str2)
const char *
dStristr(const char * str1, const char * str2)
dStrlcat(char * dst, const char * src, dsize_t dstSize)
dStrlcpy(char * dst, const char * src, dsize_t dstSize)
char *
dStrlwr(char * str)
int
dStrrev(char * str)
bool
dStrStartsWith(const char * str1, const char * str2)

Check if one string starts with another.

char *
dStrupr(char * str)
dVprintf(const char * format, va_list arglist)
dVsprintf(char * buffer, U32 bufferSize, const char * format, va_list arglist)
strnatcmp0(const nat_char * a, const nat_char * b, S32 fold_case)

Detailed Description

Public Typedefs

typedef char nat_char 

Public Functions

compare_left(const nat_char * a, const nat_char * b)

compare_right(const nat_char * a, const nat_char * b)

dItoa(int n, char s)

dPrintf(const char * format, ... )

dSprintf(char * buffer, U32 bufferSize, const char * format, ... )

dSscanf(const char * buffer, const char * format, ... )

dStrcatl(char * dst, dsize_t dstSize, ... )

dStrcmp(const UTF16 * str1, const UTF16 * str2)

dStrcpyl(char * dst, dsize_t dstSize, ... )

dStrdup_r(const char * src, const char * fileName, dsize_t lineNumber)

dStrEndsWith(const char * str1, const char * str2)

Check if one string ends with another.

dStrEqual(const char * str1, const char * str2)

Safe form of dStrcmp: checks both strings for NULL before comparing.

dStrichr(char * str, char ch)

dStrichr(const char * str, char ch)

dStripPath(const char * filename)

Strip the path from the input filename.

dStristr(char * str1, const char * str2)

dStristr(const char * str1, const char * str2)

dStrlcat(char * dst, const char * src, dsize_t dstSize)

dStrlcpy(char * dst, const char * src, dsize_t dstSize)

dStrlwr(char * str)

dStrnatcasecmp(const nat_char * a, const nat_char * b)

dStrnatcmp(const nat_char * a, const nat_char * b)

dStrrev(char * str)

dStrStartsWith(const char * str1, const char * str2)

Check if one string starts with another.

dStrupr(char * str)

dVprintf(const char * format, va_list arglist)

dVsprintf(char * buffer, U32 bufferSize, const char * format, va_list arglist)

nat_isdigit(nat_char a)

nat_isspace(nat_char a)

nat_toupper(nat_char a)

strnatcmp0(const nat_char * a, const nat_char * b, S32 fold_case)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include <stdarg.h>
 25#include <stdio.h>
 26
 27#include "core/strings/stringFunctions.h"
 28#include "platform/platform.h"
 29
 30
 31#if defined(TORQUE_OS_WIN)
 32// This standard function is not defined when compiling with VC7...
 33#define vsnprintf _vsnprintf
 34#endif
 35
 36
 37//-----------------------------------------------------------------------------
 38
 39// Original code from: http://sourcefrog.net/projects/natsort/
 40// Somewhat altered here.
 41//TODO: proper UTF8 support; currently only working for single-byte characters
 42
 43/* -*- mode: c; c-file-style: "k&r" -*-
 44
 45  strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
 46  Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
 47
 48  This software is provided 'as-is', without any express or implied
 49  warranty.  In no event will the authors be held liable for any damages
 50  arising from the use of this software.
 51
 52  Permission is granted to anyone to use this software for any purpose,
 53  including commercial applications, and to alter it and redistribute it
 54  freely, subject to the following restrictions:
 55
 56  1. The origin of this software must not be misrepresented; you must not
 57     claim that you wrote the original software. If you use this software
 58     in a product, an acknowledgment in the product documentation would be
 59     appreciated but is not required.
 60  2. Altered source versions must be plainly marked as such, and must not be
 61     misrepresented as being the original software.
 62  3. This notice may not be removed or altered from any source distribution.
 63*/
 64
 65
 66/* partial change history:
 67 *
 68 * 2004-10-10 mbp: Lift out character type dependencies into macros.
 69 *
 70 * Eric Sosman pointed out that ctype functions take a parameter whose
 71 * value must be that of an unsigned int, even on platforms that have
 72 * negative chars in their default char type.
 73 */
 74
 75typedef char nat_char;
 76
 77/* These are defined as macros to make it easier to adapt this code to
 78 * different characters types or comparison functions. */
 79static inline int
 80nat_isdigit( nat_char a )
 81{
 82   return dIsdigit( a );
 83}
 84
 85
 86static inline int
 87nat_isspace( nat_char a )
 88{
 89   return dIsspace( a );
 90}
 91
 92
 93static inline nat_char
 94nat_toupper( nat_char a )
 95{
 96   return dToupper( a );
 97}
 98
 99
100
101static S32
102compare_right(const nat_char* a, const nat_char* b)
103{
104   S32 bias = 0;
105
106   /* The longest run of digits wins.  That aside, the greatest
107   value wins, but we can't know that it will until we've scanned
108   both numbers to know that they have the same magnitude, so we
109   remember it in BIAS. */
110   for (;; a++, b++) {
111      if (!nat_isdigit(*a)  &&  !nat_isdigit(*b))
112         break;
113      else if (!nat_isdigit(*a))
114         return -1;
115      else if (!nat_isdigit(*b))
116         return +1;
117      else if (*a < *b) {
118         if (!bias)
119            bias = -1;
120      } else if (*a > *b) {
121         if (!bias)
122            bias = +1;
123      } else if (!*a  &&  !*b)
124         return bias;
125   }
126
127   return bias;
128}
129
130
131static int
132compare_left(const nat_char* a, const nat_char* b)
133{
134   /* Compare two left-aligned numbers: the first to have a
135   different value wins. */
136   for (;; a++, b++) {
137      if (!nat_isdigit(*a)  &&  !nat_isdigit(*b))
138         break;
139      else if (!nat_isdigit(*a))
140         return -1;
141      else if (!nat_isdigit(*b))
142         return +1;
143      else if (*a < *b)
144         return -1;
145      else if (*a > *b)
146         return +1;
147   }
148
149   return 0;
150}
151
152
153static S32 strnatcmp0(const nat_char* a, const nat_char* b, S32 fold_case)
154{
155   S32 ai, bi;
156   nat_char ca, cb;
157   S32 fractional, result;
158
159   ai = bi = 0;
160   while (1) {
161      ca = a[ai]; cb = b[bi];
162
163      /* skip over leading spaces or zeros */
164      while (nat_isspace(ca))
165         ca = a[++ai];
166
167      while (nat_isspace(cb))
168         cb = b[++bi];
169
170      /* process run of digits */
171      if (nat_isdigit(ca)  &&  nat_isdigit(cb)) {
172         fractional = (ca == '0' || cb == '0');
173
174         if (fractional) {
175            if ((result = compare_left(a+ai, b+bi)) != 0)
176               return result;
177         } else {
178            if ((result = compare_right(a+ai, b+bi)) != 0)
179               return result;
180         }
181      }
182
183      if (!ca && !cb) {
184         /* The strings compare the same.  Perhaps the caller
185         will want to call strcmp to break the tie. */
186         return 0;
187      }
188
189      if (fold_case) {
190         ca = nat_toupper(ca);
191         cb = nat_toupper(cb);
192      }
193
194      if (ca < cb)
195         return -1;
196      else if (ca > cb)
197         return +1;
198
199      ++ai; ++bi;
200   }
201}
202
203
204S32 dStrnatcmp(const nat_char* a, const nat_char* b) {
205   return strnatcmp0(a, b, 0);
206}
207
208
209/* Compare, recognizing numeric string and ignoring case. */
210S32 dStrnatcasecmp(const nat_char* a, const nat_char* b) {
211   return strnatcmp0(a, b, 1);
212}
213
214//------------------------------------------------------------------------------
215// non-standard string functions
216
217char *dStrdup_r(const char *src, const char *fileName, dsize_t lineNumber)
218{
219   dsize_t bufferLen = dStrlen(src) + 1;
220   char *buffer = (char *) dMalloc_r(bufferLen, fileName, lineNumber);
221   dStrcpy(buffer, src, bufferLen);
222   return buffer;
223}
224
225char* dStrichr( char* str, char ch )
226{
227   AssertFatal( str != NULL, "dStrichr - NULL string" );
228   
229   if( !ch )
230      return dStrchr( str, ch ); 
231   
232   char c = dToupper( ch );
233   while( *str )
234   {
235      if( dToupper( *str ) == c )
236         return str;
237         
238      ++ str;
239   }
240         
241   return NULL;
242}
243
244const char* dStrichr( const char* str, char ch )
245{
246   AssertFatal( str != NULL, "dStrichr - NULL string" );
247   
248   if( !ch )
249      return dStrchr( str, ch ); 
250
251   char c = dToupper( ch );
252   while( *str )
253   {
254      if( dToupper( *str ) == c )
255         return str;
256         
257      ++ str;
258   }
259      
260   return NULL;
261}
262
263// concatenates a list of src's onto the end of dst
264// the list of src's MUST be terminated by a NULL parameter
265// dStrcatl(dst, sizeof(dst), src1, src2, NULL);
266char* dStrcatl(char *dst, dsize_t dstSize, ...)
267{
268   const char* src = NULL;
269   char *p = dst;
270
271   AssertFatal(dstSize > 0, "dStrcatl: destination size is set zero");
272   dstSize--;  // leave room for string termination
273
274   // find end of dst
275   while (dstSize && *p++)
276      dstSize--;
277
278   va_list args;
279   va_start(args, dstSize);
280
281   // concatenate each src to end of dst
282   while ( (src = va_arg(args, const char*)) != NULL )
283   {
284      while( dstSize && *src )
285      {
286         *p++ = *src++;
287         dstSize--;
288      }
289   }
290
291   va_end(args);
292
293   // make sure the string is terminated
294   *p = 0;
295
296   return dst;
297}
298
299
300// copy a list of src's into dst
301// the list of src's MUST be terminated by a NULL parameter
302// dStrccpyl(dst, sizeof(dst), src1, src2, NULL);
303char* dStrcpyl(char *dst, dsize_t dstSize, ...)
304{
305   const char* src = NULL;
306   char *p = dst;
307
308   AssertFatal(dstSize > 0, "dStrcpyl: destination size is set zero");
309   dstSize--;  // leave room for string termination
310
311   va_list args;
312   va_start(args, dstSize);
313
314   // concatenate each src to end of dst
315   while ( (src = va_arg(args, const char*)) != NULL )
316   {
317      while( dstSize && *src )
318      {
319         *p++ = *src++;
320         dstSize--;
321      }
322   }
323
324   va_end(args);
325
326   // make sure the string is terminated
327   *p = 0;
328
329   return dst;
330}
331
332
333S32 dStrcmp(const UTF16 *str1, const UTF16 *str2)
334{
335#if defined(TORQUE_OS_WIN)
336   return wcscmp( reinterpret_cast<const wchar_t *>( str1 ), reinterpret_cast<const wchar_t *>( str2 ) );
337#else
338   S32 ret;
339   const UTF16 *a, *b;
340   a = str1;
341   b = str2;
342
343   while( ((ret = *a - *b) == 0) && *a && *b )
344      a++, b++;
345
346   return ret;
347#endif
348}  
349
350char* dStrupr(char *str)
351{
352#if defined(TORQUE_OS_WIN)
353   return _strupr(str);
354#else
355   if (str == NULL)
356      return(NULL);
357
358   char* saveStr = str;
359   while (*str)
360   {
361      *str = toupper(*str);
362      str++;
363   }
364   return saveStr;
365#endif
366}
367
368char* dStrlwr(char *str)
369{
370#if defined(TORQUE_OS_WIN)
371   return _strlwr(str);
372#else
373   if (str == NULL)
374      return(NULL);
375
376   char* saveStr = str;
377   while (*str)
378   {
379      *str = tolower(*str);
380      str++;
381   }
382   return saveStr;
383#endif
384}
385
386//------------------------------------------------------------------------------
387
388S32 dStrlcat(char *dst, const char *src, dsize_t dstSize)
389{
390   //TODO: Do other platforms support strlcat in their libc
391#ifdef TORQUE_OS_MAC
392   S32 len = strlcat(dst, src, dstSize);
393
394   AssertWarn(len < dstSize, "Buffer too small in call to dStrlcat!");
395
396   return len;
397#else //TORQUE_OS_MAC
398   S32 dstLen = dStrlen(dst);
399   S32 srcLen = dStrlen(src);
400   S32 copyLen = srcLen;
401
402   //Check for buffer overflow and don't allow it. Warn on debug so we can fix it
403   AssertWarn(dstLen + copyLen < dstSize, "Buffer too small in call to dStrlcat!");
404   if (dstLen + copyLen + 1 > dstSize)
405   {
406      copyLen = dstSize - dstLen - 1;
407   }
408
409   //Copy src after dst and null terminate
410   memcpy(dst + dstLen, src, copyLen);
411   dst[dstLen + copyLen] = 0;
412
413   //Return the length of the string we would have generated
414   return dstLen + srcLen;
415#endif //TORQUE_OS_MAC
416}
417
418S32 dStrlcpy(char *dst, const char *src, dsize_t dstSize)
419{
420   //TODO: Do other platforms support strlcpy in their libc
421#ifdef TORQUE_OS_MAC
422   S32 len = strlcpy(dst, src, dstSize);
423
424   AssertWarn(len < dstSize, "Buffer too small in call to dStrlcpy!");
425
426   return len;
427#else //TORQUE_OS_MAC
428   S32 srcLen = dStrlen(src);
429   S32 copyLen = srcLen;
430
431   //Check for buffer overflow and don't allow it. Warn on debug so we can fix it
432   AssertWarn(copyLen < dstSize, "Buffer too small in call to dStrlcpy!");
433   if (srcLen + 1 > dstSize)
434   {
435      copyLen = dstSize - 1;
436   }
437
438   //Copy src and null terminate
439   memcpy(dst, src, copyLen);
440   dst[copyLen] = 0;
441
442   //Return the length of the string we would have generated
443   return srcLen;
444#endif //TORQUE_OS_MAC
445}
446
447//------------------------------------------------------------------------------
448// standard I/O functions
449
450void dPrintf(const char *format, ...)
451{
452   va_list args;
453   va_start(args, format);
454   vprintf(format, args);
455   va_end(args);
456}
457
458S32 dVprintf(const char *format, va_list arglist)
459{
460   return (S32)vprintf(format, arglist);
461}
462
463S32 dSprintf(char *buffer, U32 bufferSize, const char *format, ...)
464{
465   va_list args;
466   va_start(args, format);
467
468   S32 len = vsnprintf(buffer, bufferSize, format, args);
469   va_end(args);
470
471   AssertWarn( len < bufferSize, "Buffer too small in call to dSprintf!" );
472
473   return (len);
474}
475
476
477S32 dVsprintf(char *buffer, U32 bufferSize, const char *format, va_list arglist)
478{
479   S32 len = vsnprintf(buffer, bufferSize, format, arglist);
480   
481   AssertWarn( len < bufferSize, "Buffer too small in call to dVsprintf!" );
482
483   return (len);
484}
485
486
487S32 dSscanf(const char *buffer, const char *format, ...)
488{
489#if defined(TORQUE_OS_WIN)
490   va_list args;
491   va_start(args, format);
492
493   // Boy is this lame.  We have to scan through the format string, and find out how many
494   //  arguments there are.  We'll store them off as void*, and pass them to the sscanf
495   //  function through specialized calls.  We're going to have to put a cap on the number of args that
496   //  can be passed, 8 for the moment.  Sigh.
497   static void* sVarArgs[20];
498   U32 numArgs = 0;
499
500   for (const char* search = format; *search != '\0'; search++) {
501      if (search[0] == '%' && search[1] != '%')
502         numArgs++;
503   }
504   AssertFatal(numArgs <= 20, "Error, too many arguments to lame implementation of dSscanf.  Fix implmentation");
505
506   // Ok, we have the number of arguments...
507   for (U32 i = 0; i < numArgs; i++)
508      sVarArgs[i] = va_arg(args, void*);
509   va_end(args);
510
511   switch (numArgs) {
512     case 0: return 0;
513     case 1:  return sscanf(buffer, format, sVarArgs[0]);
514     case 2:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1]);
515     case 3:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2]);
516     case 4:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3]);
517     case 5:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4]);
518     case 6:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5]);
519     case 7:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6]);
520     case 8:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7]);
521     case 9:  return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8]);
522     case 10: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9]);
523     case 11: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10]);
524     case 12: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11]);
525     case 13: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12]);
526     case 14: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12], sVarArgs[13]);
527     case 15: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12], sVarArgs[13], sVarArgs[14]);
528     case 16: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12], sVarArgs[13], sVarArgs[14], sVarArgs[15]);
529     case 17: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12], sVarArgs[13], sVarArgs[14], sVarArgs[15], sVarArgs[16]);
530     case 18: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12], sVarArgs[13], sVarArgs[14], sVarArgs[15], sVarArgs[16], sVarArgs[17]);
531     case 19: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12], sVarArgs[13], sVarArgs[14], sVarArgs[15], sVarArgs[16], sVarArgs[17], sVarArgs[18]);
532     case 20: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8], sVarArgs[9], sVarArgs[10], sVarArgs[11], sVarArgs[12], sVarArgs[13], sVarArgs[14], sVarArgs[15], sVarArgs[16], sVarArgs[17], sVarArgs[18], sVarArgs[19]);
533   }
534   return 0;
535#else
536   va_list args;
537   va_start(args, format);
538   S32 res = vsscanf(buffer, format, args);
539   va_end(args);
540   return res;
541#endif
542}
543
544/// Safe form of dStrcmp: checks both strings for NULL before comparing
545bool dStrEqual(const char* str1, const char* str2)
546{
547   if (!str1 || !str2)
548      return false;
549   else
550      return (String::compare(str1, str2) == 0);
551}
552
553/// Check if one string starts with another
554bool dStrStartsWith(const char* str1, const char* str2)
555{
556   return !dStrnicmp(str1, str2, dStrlen(str2));
557}
558
559/// Check if one string ends with another
560bool dStrEndsWith(const char* str1, const char* str2)
561{
562   const char *p = str1 + dStrlen(str1) - dStrlen(str2);
563   return ((p >= str1) && !dStricmp(p, str2));
564}
565
566/// Strip the path from the input filename
567char* dStripPath(const char* filename)
568{
569   const char* itr = filename + dStrlen(filename);
570   while(--itr != filename) {
571      if (*itr == '/' || *itr == '\\') {
572         itr++;
573         break;
574      }
575   }
576   return dStrdup(itr);
577}
578
579char* dStristr( char* str1, const char* str2 )
580{
581   if( !str1 || !str2 )
582      return NULL;
583
584   // Slow but at least we have it.
585
586   U32 str2len = strlen( str2 );
587   while( *str1 )
588   {
589      if( strncasecmp( str1, str2, str2len ) == 0 )
590         return str1;
591
592      ++ str1;
593   }
594
595   return NULL;
596}
597
598const char* dStristr( const char* str1, const char* str2 )
599{
600   return dStristr( const_cast< char* >( str1 ), str2 );
601}
602
603int dStrrev(char* str)
604{
605   int l=<a href="/coding/file/stringfunctions_8h/#stringfunctions_8h_1ab08bdbead2d56aa91fb39c1d4aa3a436">dStrlen</a>(str)-1; //get the string length
606   for(int x=0;x < l;x++,l--)
607   {
608      str[x]^=str[l];  //triple XOR Trick
609      str[l]^=str[x];  //for not using a temp
610      str[x]^=str[l];
611   }
612   return l;
613}
614
615int dItoa(int n, char s[])
616{
617   int i, sign;
618
619   if ((sign = n) < 0)  /* record sign */
620      n = -n;          /* make n positive */
621   i = 0;
622   do {       /* generate digits in reverse order */
623      s[i++] = n % 10 + '0';   /* get next digit */
624   } while ((n /= 10) > 0);     /* delete it */
625   if (sign < 0)
626      s[i++] = '-';
627   s[i] = '\0';
628   dStrrev(s);
629   return dStrlen(s);
630}
631