stringFunctions.cpp
Engine/source/core/strings/stringFunctions.cpp
Public Typedefs
char
nat_char
Public Functions
int
compare_left(const nat_char * a, const nat_char * b)
int
dItoa(int n, char s)
bool
dStrEndsWith(const char * str1, const char * str2)
Check if one string ends with another.
bool
char *
dStrichr(char * str, char ch)
char *
dStripPath(const char * filename)
Strip the path from the input filename.
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)
int
int
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)
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) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON) 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 char *buffer = (char *) dMalloc_r(dStrlen(src) + 1, fileName, lineNumber); 220 dStrcpy(buffer, src); 221 return buffer; 222} 223 224char* dStrichr( char* str, char ch ) 225{ 226 AssertFatal( str != NULL, "dStrichr - NULL string" ); 227 228 if( !ch ) 229 return dStrchr( str, ch ); 230 231 char c = dToupper( ch ); 232 while( *str ) 233 { 234 if( dToupper( *str ) == c ) 235 return str; 236 237 ++ str; 238 } 239 240 return NULL; 241} 242 243const char* dStrichr( const char* str, char ch ) 244{ 245 AssertFatal( str != NULL, "dStrichr - NULL string" ); 246 247 if( !ch ) 248 return dStrchr( str, ch ); 249 250 char c = dToupper( ch ); 251 while( *str ) 252 { 253 if( dToupper( *str ) == c ) 254 return str; 255 256 ++ str; 257 } 258 259 return NULL; 260} 261 262// concatenates a list of src's onto the end of dst 263// the list of src's MUST be terminated by a NULL parameter 264// dStrcatl(dst, sizeof(dst), src1, src2, NULL); 265char* dStrcatl(char *dst, dsize_t dstSize, ...) 266{ 267 const char* src = NULL; 268 char *p = dst; 269 270 AssertFatal(dstSize > 0, "dStrcatl: destination size is set zero"); 271 dstSize--; // leave room for string termination 272 273 // find end of dst 274 while (dstSize && *p++) 275 dstSize--; 276 277 va_list args; 278 va_start(args, dstSize); 279 280 // concatenate each src to end of dst 281 while ( (src = va_arg(args, const char*)) != NULL ) 282 { 283 while( dstSize && *src ) 284 { 285 *p++ = *src++; 286 dstSize--; 287 } 288 } 289 290 va_end(args); 291 292 // make sure the string is terminated 293 *p = 0; 294 295 return dst; 296} 297 298 299// copy a list of src's into dst 300// the list of src's MUST be terminated by a NULL parameter 301// dStrccpyl(dst, sizeof(dst), src1, src2, NULL); 302char* dStrcpyl(char *dst, dsize_t dstSize, ...) 303{ 304 const char* src = NULL; 305 char *p = dst; 306 307 AssertFatal(dstSize > 0, "dStrcpyl: destination size is set zero"); 308 dstSize--; // leave room for string termination 309 310 va_list args; 311 va_start(args, dstSize); 312 313 // concatenate each src to end of dst 314 while ( (src = va_arg(args, const char*)) != NULL ) 315 { 316 while( dstSize && *src ) 317 { 318 *p++ = *src++; 319 dstSize--; 320 } 321 } 322 323 va_end(args); 324 325 // make sure the string is terminated 326 *p = 0; 327 328 return dst; 329} 330 331 332S32 dStrcmp( const UTF16 *str1, const UTF16 *str2) 333{ 334#if defined(TORQUE_OS_WIN) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON) 335 return wcscmp( reinterpret_cast<const wchar_t *>( str1 ), reinterpret_cast<const wchar_t *>( str2 ) ); 336#else 337 S32 ret; 338 const UTF16 *a, *b; 339 a = str1; 340 b = str2; 341 342 while( ((ret = *a - *b) == 0) && *a && *b ) 343 a++, b++; 344 345 return ret; 346#endif 347} 348 349char* dStrupr(char *str) 350{ 351#if defined(TORQUE_OS_WIN) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON) 352 return _strupr(str); 353#else 354 if (str == NULL) 355 return(NULL); 356 357 char* saveStr = str; 358 while (*str) 359 { 360 *str = toupper(*str); 361 str++; 362 } 363 return saveStr; 364#endif 365} 366 367char* dStrlwr(char *str) 368{ 369#if defined(TORQUE_OS_WIN) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON) 370 return _strlwr(str); 371#else 372 if (str == NULL) 373 return(NULL); 374 375 char* saveStr = str; 376 while (*str) 377 { 378 *str = tolower(*str); 379 str++; 380 } 381 return saveStr; 382#endif 383} 384 385//------------------------------------------------------------------------------ 386// standard I/O functions 387 388void dPrintf(const char *format, ...) 389{ 390 va_list args; 391 va_start(args, format); 392 vprintf(format, args); 393 va_end(args); 394} 395 396S32 dVprintf(const char *format, va_list arglist) 397{ 398 return (S32)vprintf(format, arglist); 399} 400 401S32 dSprintf(char *buffer, U32 bufferSize, const char *format, ...) 402{ 403 va_list args; 404 va_start(args, format); 405 406 S32 len = vsnprintf(buffer, bufferSize, format, args); 407 va_end(args); 408 409 AssertWarn( len < bufferSize, "Buffer too small in call to dSprintf!" ); 410 411 return (len); 412} 413 414 415S32 dVsprintf(char *buffer, U32 bufferSize, const char *format, va_list arglist) 416{ 417 S32 len = vsnprintf(buffer, bufferSize, format, arglist); 418 419 AssertWarn( len < bufferSize, "Buffer too small in call to dVsprintf!" ); 420 421 return (len); 422} 423 424 425S32 dSscanf(const char *buffer, const char *format, ...) 426{ 427#if defined(TORQUE_OS_WIN) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON) 428 va_list args; 429 va_start(args, format); 430 431 // Boy is this lame. We have to scan through the format string, and find out how many 432 // arguments there are. We'll store them off as void*, and pass them to the sscanf 433 // function through specialized calls. We're going to have to put a cap on the number of args that 434 // can be passed, 8 for the moment. Sigh. 435 static void* sVarArgs[20]; 436 U32 numArgs = 0; 437 438 for (const char* search = format; *search != '\0'; search++) { 439 if (search[0] == '%' && search[1] != '%') 440 numArgs++; 441 } 442 AssertFatal(numArgs <= 20, "Error, too many arguments to lame implementation of dSscanf. Fix implmentation"); 443 444 // Ok, we have the number of arguments... 445 for (U32 i = 0; i < numArgs; i++) 446 sVarArgs[i] = va_arg(args, void*); 447 va_end(args); 448 449 switch (numArgs) { 450 case 0: return 0; 451 case 1: return sscanf(buffer, format, sVarArgs[0]); 452 case 2: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1]); 453 case 3: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2]); 454 case 4: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3]); 455 case 5: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4]); 456 case 6: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5]); 457 case 7: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6]); 458 case 8: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7]); 459 case 9: return sscanf(buffer, format, sVarArgs[0], sVarArgs[1], sVarArgs[2], sVarArgs[3], sVarArgs[4], sVarArgs[5], sVarArgs[6], sVarArgs[7], sVarArgs[8]); 460 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]); 461 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]); 462 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]); 463 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]); 464 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]); 465 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]); 466 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]); 467 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]); 468 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]); 469 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]); 470 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]); 471 } 472 return 0; 473#else 474 va_list args; 475 va_start(args, format); 476 S32 res = vsscanf(buffer, format, args); 477 va_end(args); 478 return res; 479#endif 480} 481 482/// Safe form of dStrcmp: checks both strings for NULL before comparing 483bool dStrEqual(const char* str1, const char* str2) 484{ 485 if (!str1 || !str2) 486 return false; 487 else 488 return (dStrcmp(str1, str2) == 0); 489} 490 491/// Check if one string starts with another 492bool dStrStartsWith(const char* str1, const char* str2) 493{ 494 return !dStrnicmp(str1, str2, dStrlen(str2)); 495} 496 497/// Check if one string ends with another 498bool dStrEndsWith(const char* str1, const char* str2) 499{ 500 const char *p = str1 + dStrlen(str1) - dStrlen(str2); 501 return ((p >= str1) && !dStricmp(p, str2)); 502} 503 504/// Strip the path from the input filename 505char* dStripPath(const char* filename) 506{ 507 const char* itr = filename + dStrlen(filename); 508 while(--itr != filename) { 509 if (*itr == '/' || *itr == '\\') { 510 itr++; 511 break; 512 } 513 } 514 return dStrdup(itr); 515} 516 517char* dStristr( char* str1, const char* str2 ) 518{ 519 if( !str1 || !str2 ) 520 return NULL; 521 522 // Slow but at least we have it. 523 524 U32 str2len = strlen( str2 ); 525 while( *str1 ) 526 { 527 if( strncasecmp( str1, str2, str2len ) == 0 ) 528 return str1; 529 530 ++ str1; 531 } 532 533 return NULL; 534} 535 536const char* dStristr( const char* str1, const char* str2 ) 537{ 538 return dStristr( const_cast< char* >( str1 ), str2 ); 539} 540 541int dStrrev(char* str) 542{ 543 int l=<a href="/coding/file/stringfunctions_8h/#stringfunctions_8h_1ab08bdbead2d56aa91fb39c1d4aa3a436">dStrlen</a>(str)-1; //get the string length 544 for(int x=0;x < l;x++,l--) 545 { 546 str[x]^=str[l]; //triple XOR Trick 547 str[l]^=str[x]; //for not using a temp 548 str[x]^=str[l]; 549 } 550 return l; 551} 552 553int dItoa(int n, char s[]) 554{ 555 int i, sign; 556 557 if ((sign = n) < 0) /* record sign */ 558 n = -n; /* make n positive */ 559 i = 0; 560 do { /* generate digits in reverse order */ 561 s[i++] = n % 10 + '0'; /* get next digit */ 562 } while ((n /= 10) > 0); /* delete it */ 563 if (sign < 0) 564 s[i++] = '-'; 565 s[i] = '\0'; 566 dStrrev(s); 567 return dStrlen(s); 568} 569
