1 /* 2 * kmp_str.cpp -- String manipulation routines. 3 */ 4 5 6 //===----------------------------------------------------------------------===// 7 // 8 // The LLVM Compiler Infrastructure 9 // 10 // This file is dual licensed under the MIT and the University of Illinois Open 11 // Source Licenses. See LICENSE.txt for details. 12 // 13 //===----------------------------------------------------------------------===// 14 15 16 #include "kmp_str.h" 17 18 #include <stdarg.h> // va_* 19 #include <stdio.h> // vsnprintf() 20 #include <stdlib.h> // malloc(), realloc() 21 22 #include "kmp.h" 23 #include "kmp_i18n.h" 24 25 /* 26 ------------------------------------------------------------------------------------------------ 27 String buffer. 28 ------------------------------------------------------------------------------------------------ 29 30 Usage: 31 32 // Declare buffer and initialize it. 33 kmp_str_buf_t buffer; 34 __kmp_str_buf_init( & buffer ); 35 36 // Print to buffer. 37 __kmp_str_buf_print( & buffer, "Error in file \"%s\" line %d\n", "foo.c", 12 ); 38 __kmp_str_buf_print( & buffer, " <%s>\n", line ); 39 40 // Use buffer contents. buffer.str is a pointer to data, buffer.used is a number of printed 41 // characters (not including terminating zero). 42 write( fd, buffer.str, buffer.used ); 43 44 // Free buffer. 45 __kmp_str_buf_free( & buffer ); 46 47 // Alternatively, you can detach allocated memory from buffer: 48 __kmp_str_buf_detach( & buffer ); 49 return buffer.str; // That memory should be freed eventually. 50 51 52 Notes: 53 54 * Buffer users may use buffer.str and buffer.used. Users should not change any fields of 55 buffer directly. 56 57 * buffer.str is never NULL. If buffer is empty, buffer.str points to empty string (""). 58 59 * For performance reasons, buffer uses stack memory (buffer.bulk) first. If stack memory is 60 exhausted, buffer allocates memory on heap by malloc(), and reallocates it by realloc() 61 as amount of used memory grows. 62 63 * Buffer doubles amount of allocated memory each time it is exhausted. 64 65 ------------------------------------------------------------------------------------------------ 66 */ 67 68 // TODO: __kmp_str_buf_print() can use thread local memory allocator. 69 70 #define KMP_STR_BUF_INVARIANT( b ) \ 71 { \ 72 KMP_DEBUG_ASSERT( (b)->str != NULL ); \ 73 KMP_DEBUG_ASSERT( (b)->size >= sizeof( (b)->bulk ) ); \ 74 KMP_DEBUG_ASSERT( (b)->size % sizeof( (b)->bulk ) == 0 ); \ 75 KMP_DEBUG_ASSERT( (unsigned)(b)->used < (b)->size ); \ 76 KMP_DEBUG_ASSERT( (b)->size == sizeof( (b)->bulk ) ? (b)->str == & (b)->bulk[ 0 ] : 1 ); \ 77 KMP_DEBUG_ASSERT( (b)->size > sizeof( (b)->bulk ) ? (b)->str != & (b)->bulk[ 0 ] : 1 ); \ 78 } 79 80 void 81 __kmp_str_buf_clear( 82 kmp_str_buf_t * buffer 83 ) { 84 KMP_STR_BUF_INVARIANT( buffer ); 85 if ( buffer->used > 0 ) { 86 buffer->used = 0; 87 buffer->str[ 0 ] = 0; 88 }; // if 89 KMP_STR_BUF_INVARIANT( buffer ); 90 } // __kmp_str_buf_clear 91 92 93 void 94 __kmp_str_buf_reserve( 95 kmp_str_buf_t * buffer, 96 int size 97 ) { 98 99 KMP_STR_BUF_INVARIANT( buffer ); 100 KMP_DEBUG_ASSERT( size >= 0 ); 101 102 if ( buffer->size < (unsigned int)size ) { 103 104 // Calculate buffer size. 105 do { 106 buffer->size *= 2; 107 } while ( buffer->size < (unsigned int)size ); 108 109 // Enlarge buffer. 110 if ( buffer->str == & buffer->bulk[ 0 ] ) { 111 buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size ); 112 if ( buffer->str == NULL ) { 113 KMP_FATAL( MemoryAllocFailed ); 114 }; // if 115 KMP_MEMCPY_S( buffer->str, buffer->size, buffer->bulk, buffer->used + 1 ); 116 } else { 117 buffer->str = (char *) KMP_INTERNAL_REALLOC( buffer->str, buffer->size ); 118 if ( buffer->str == NULL ) { 119 KMP_FATAL( MemoryAllocFailed ); 120 }; // if 121 }; // if 122 123 }; // if 124 125 KMP_DEBUG_ASSERT( buffer->size > 0 ); 126 KMP_DEBUG_ASSERT( buffer->size >= (unsigned)size ); 127 KMP_STR_BUF_INVARIANT( buffer ); 128 129 } // __kmp_str_buf_reserve 130 131 132 void 133 __kmp_str_buf_detach( 134 kmp_str_buf_t * buffer 135 ) { 136 137 KMP_STR_BUF_INVARIANT( buffer ); 138 139 // If internal bulk is used, allocate memory and copy it. 140 if ( buffer->size <= sizeof( buffer->bulk ) ) { 141 buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size ); 142 if ( buffer->str == NULL ) { 143 KMP_FATAL( MemoryAllocFailed ); 144 }; // if 145 KMP_MEMCPY_S( buffer->str, buffer->size, buffer->bulk, buffer->used + 1 ); 146 }; // if 147 148 } // __kmp_str_buf_detach 149 150 151 void 152 __kmp_str_buf_free( 153 kmp_str_buf_t * buffer 154 ) { 155 KMP_STR_BUF_INVARIANT( buffer ); 156 if ( buffer->size > sizeof( buffer->bulk ) ) { 157 KMP_INTERNAL_FREE( buffer->str ); 158 }; // if 159 buffer->str = buffer->bulk; 160 buffer->size = sizeof( buffer->bulk ); 161 buffer->used = 0; 162 KMP_STR_BUF_INVARIANT( buffer ); 163 } // __kmp_str_buf_free 164 165 166 void 167 __kmp_str_buf_cat( 168 kmp_str_buf_t * buffer, 169 char const * str, 170 int len 171 ) { 172 KMP_STR_BUF_INVARIANT( buffer ); 173 KMP_DEBUG_ASSERT( str != NULL ); 174 KMP_DEBUG_ASSERT( len >= 0 ); 175 __kmp_str_buf_reserve( buffer, buffer->used + len + 1 ); 176 KMP_MEMCPY( buffer->str + buffer->used, str, len ); 177 buffer->str[ buffer->used + len ] = 0; 178 buffer->used += len; 179 KMP_STR_BUF_INVARIANT( buffer ); 180 } // __kmp_str_buf_cat 181 182 183 void 184 __kmp_str_buf_vprint( 185 kmp_str_buf_t * buffer, 186 char const * format, 187 va_list args 188 ) { 189 190 KMP_STR_BUF_INVARIANT( buffer ); 191 192 for ( ; ; ) { 193 194 int const free = buffer->size - buffer->used; 195 int rc; 196 int size; 197 198 // Try to format string. 199 { 200 /* 201 On Linux* OS Intel(R) 64, vsnprintf() modifies args argument, so vsnprintf() crashes if it 202 is called for the second time with the same args. To prevent the crash, we have to 203 pass a fresh intact copy of args to vsnprintf() on each iteration. 204 205 Unfortunately, standard va_copy() macro is not available on Windows* OS. However, it 206 seems vsnprintf() does not modify args argument on Windows* OS. 207 */ 208 209 #if ! KMP_OS_WINDOWS 210 va_list _args; 211 __va_copy( _args, args ); // Make copy of args. 212 #define args _args // Substitute args with its copy, _args. 213 #endif // KMP_OS_WINDOWS 214 rc = KMP_VSNPRINTF( buffer->str + buffer->used, free, format, args ); 215 #if ! KMP_OS_WINDOWS 216 #undef args // Remove substitution. 217 va_end( _args ); 218 #endif // KMP_OS_WINDOWS 219 } 220 221 // No errors, string has been formatted. 222 if ( rc >= 0 && rc < free ) { 223 buffer->used += rc; 224 break; 225 }; // if 226 227 // Error occurred, buffer is too small. 228 if ( rc >= 0 ) { 229 // C99-conforming implementation of vsnprintf returns required buffer size. 230 size = buffer->used + rc + 1; 231 } else { 232 // Older implementations just return -1. Double buffer size. 233 size = buffer->size * 2; 234 }; // if 235 236 // Enlarge buffer. 237 __kmp_str_buf_reserve( buffer, size ); 238 239 // And try again. 240 241 }; // forever 242 243 KMP_DEBUG_ASSERT( buffer->size > 0 ); 244 KMP_STR_BUF_INVARIANT( buffer ); 245 246 } // __kmp_str_buf_vprint 247 248 249 void 250 __kmp_str_buf_print( 251 kmp_str_buf_t * buffer, 252 char const * format, 253 ... 254 ) { 255 256 va_list args; 257 va_start( args, format ); 258 __kmp_str_buf_vprint( buffer, format, args ); 259 va_end( args ); 260 261 } // __kmp_str_buf_print 262 263 264 /* 265 The function prints specified size to buffer. Size is expressed using biggest possible unit, for 266 example 1024 is printed as "1k". 267 */ 268 269 void 270 __kmp_str_buf_print_size( 271 kmp_str_buf_t * buf, 272 size_t size 273 ) { 274 275 char const * names[] = { "", "k", "M", "G", "T", "P", "E", "Z", "Y" }; 276 int const units = sizeof( names ) / sizeof( char const * ); 277 int u = 0; 278 if ( size > 0 ) { 279 while ( ( size % 1024 == 0 ) && ( u + 1 < units ) ) { 280 size = size / 1024; 281 ++ u; 282 }; // while 283 }; // if 284 285 __kmp_str_buf_print( buf, "%" KMP_SIZE_T_SPEC "%s", size, names[ u ] ); 286 287 } // __kmp_str_buf_print_size 288 289 290 void 291 __kmp_str_fname_init( 292 kmp_str_fname_t * fname, 293 char const * path 294 ) { 295 296 fname->path = NULL; 297 fname->dir = NULL; 298 fname->base = NULL; 299 300 if ( path != NULL ) { 301 char * slash = NULL; // Pointer to the last character of dir. 302 char * base = NULL; // Pointer to the beginning of basename. 303 fname->path = __kmp_str_format( "%s", path ); 304 // Original code used strdup() function to copy a string, but on Windows* OS Intel(R) 64 it 305 // causes assertioon id debug heap, so I had to replace strdup with __kmp_str_format(). 306 if ( KMP_OS_WINDOWS ) { 307 __kmp_str_replace( fname->path, '\\', '/' ); 308 }; // if 309 fname->dir = __kmp_str_format( "%s", fname->path ); 310 slash = strrchr( fname->dir, '/' ); 311 if ( KMP_OS_WINDOWS && slash == NULL ) { // On Windows* OS, if slash not found, 312 char first = TOLOWER( fname->dir[ 0 ] ); // look for drive. 313 if ( 'a' <= first && first <= 'z' && fname->dir[ 1 ] == ':' ) { 314 slash = & fname->dir[ 1 ]; 315 }; // if 316 }; // if 317 base = ( slash == NULL ? fname->dir : slash + 1 ); 318 fname->base = __kmp_str_format( "%s", base ); // Copy basename 319 * base = 0; // and truncate dir. 320 }; // if 321 322 } // kmp_str_fname_init 323 324 325 void 326 __kmp_str_fname_free( 327 kmp_str_fname_t * fname 328 ) { 329 __kmp_str_free( (char const **)( & fname->path ) ); 330 __kmp_str_free( (char const **)( & fname->dir ) ); 331 __kmp_str_free( (char const **)( & fname->base ) ); 332 } // kmp_str_fname_free 333 334 335 int 336 __kmp_str_fname_match( 337 kmp_str_fname_t const * fname, 338 char const * pattern 339 ) { 340 341 int dir_match = 1; 342 int base_match = 1; 343 344 if ( pattern != NULL ) { 345 kmp_str_fname_t ptrn; 346 __kmp_str_fname_init( & ptrn, pattern ); 347 dir_match = 348 strcmp( ptrn.dir, "*/" ) == 0 349 || 350 ( fname->dir != NULL && __kmp_str_eqf( fname->dir, ptrn.dir ) ); 351 base_match = 352 strcmp( ptrn.base, "*" ) == 0 353 || 354 ( fname->base != NULL && __kmp_str_eqf( fname->base, ptrn.base ) ); 355 __kmp_str_fname_free( & ptrn ); 356 }; // if 357 358 return dir_match && base_match; 359 360 } // __kmp_str_fname_match 361 362 363 kmp_str_loc_t 364 __kmp_str_loc_init( 365 char const * psource, 366 int init_fname 367 ) { 368 369 kmp_str_loc_t loc; 370 371 loc._bulk = NULL; 372 loc.file = NULL; 373 loc.func = NULL; 374 loc.line = 0; 375 loc.col = 0; 376 377 if ( psource != NULL ) { 378 379 char * str = NULL; 380 char * dummy = NULL; 381 char * line = NULL; 382 char * col = NULL; 383 384 // Copy psource to keep it intact. 385 loc._bulk = __kmp_str_format( "%s", psource ); 386 387 // Parse psource string: ";file;func;line;col;;" 388 str = loc._bulk; 389 __kmp_str_split( str, ';', & dummy, & str ); 390 __kmp_str_split( str, ';', & loc.file, & str ); 391 __kmp_str_split( str, ';', & loc.func, & str ); 392 __kmp_str_split( str, ';', & line, & str ); 393 __kmp_str_split( str, ';', & col, & str ); 394 395 // Convert line and col into numberic values. 396 if ( line != NULL ) { 397 loc.line = atoi( line ); 398 if ( loc.line < 0 ) { 399 loc.line = 0; 400 }; // if 401 }; // if 402 if ( col != NULL ) { 403 loc.col = atoi( col ); 404 if ( loc.col < 0 ) { 405 loc.col = 0; 406 }; // if 407 }; // if 408 409 }; // if 410 411 __kmp_str_fname_init( & loc.fname, init_fname ? loc.file : NULL ); 412 413 return loc; 414 415 } // kmp_str_loc_init 416 417 418 void 419 __kmp_str_loc_free( 420 kmp_str_loc_t * loc 421 ) { 422 __kmp_str_fname_free( & loc->fname ); 423 __kmp_str_free((const char **) &(loc->_bulk)); 424 loc->file = NULL; 425 loc->func = NULL; 426 } // kmp_str_loc_free 427 428 429 430 /* 431 This function is intended to compare file names. On Windows* OS file names are case-insensitive, 432 so functions performs case-insensitive comparison. On Linux* OS it performs case-sensitive 433 comparison. 434 Note: The function returns *true* if strings are *equal*. 435 */ 436 437 int 438 __kmp_str_eqf( // True, if strings are equal, false otherwise. 439 char const * lhs, // First string. 440 char const * rhs // Second string. 441 ) { 442 int result; 443 #if KMP_OS_WINDOWS 444 result = ( _stricmp( lhs, rhs ) == 0 ); 445 #else 446 result = ( strcmp( lhs, rhs ) == 0 ); 447 #endif 448 return result; 449 } // __kmp_str_eqf 450 451 452 /* 453 This function is like sprintf, but it *allocates* new buffer, which must be freed eventually by 454 __kmp_str_free(). The function is very convenient for constructing strings, it successfully 455 replaces strdup(), strcat(), it frees programmer from buffer allocations and helps to avoid 456 buffer overflows. Examples: 457 458 str = __kmp_str_format( "%s", orig ); // strdup(), do not care about buffer size. 459 __kmp_str_free( & str ); 460 str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), do not care about buffer size. 461 __kmp_str_free( & str ); 462 str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string. 463 __kmp_str_free( & str ); 464 465 Performance note: 466 This function allocates memory with malloc() calls, so do not call it from 467 performance-critical code. In performance-critical code consider using kmp_str_buf_t 468 instead, since it uses stack-allocated buffer for short strings. 469 470 Why does this function use malloc()? 471 1. __kmp_allocate() returns cache-aligned memory allocated with malloc(). There are no 472 reasons in using __kmp_allocate() for strings due to extra overhead while cache-aligned 473 memory is not necessary. 474 2. __kmp_thread_malloc() cannot be used because it requires pointer to thread structure. 475 We need to perform string operations during library startup (for example, in 476 __kmp_register_library_startup()) when no thread structures are allocated yet. 477 So standard malloc() is the only available option. 478 */ 479 480 char * 481 __kmp_str_format( // Allocated string. 482 char const * format, // Format string. 483 ... // Other parameters. 484 ) { 485 486 va_list args; 487 int size = 512; 488 char * buffer = NULL; 489 int rc; 490 491 // Allocate buffer. 492 buffer = (char *) KMP_INTERNAL_MALLOC( size ); 493 if ( buffer == NULL ) { 494 KMP_FATAL( MemoryAllocFailed ); 495 }; // if 496 497 for ( ; ; ) { 498 499 // Try to format string. 500 va_start( args, format ); 501 rc = KMP_VSNPRINTF( buffer, size, format, args ); 502 va_end( args ); 503 504 // No errors, string has been formatted. 505 if ( rc >= 0 && rc < size ) { 506 break; 507 }; // if 508 509 // Error occurred, buffer is too small. 510 if ( rc >= 0 ) { 511 // C99-conforming implementation of vsnprintf returns required buffer size. 512 size = rc + 1; 513 } else { 514 // Older implementations just return -1. 515 size = size * 2; 516 }; // if 517 518 // Enlarge buffer and try again. 519 buffer = (char *) KMP_INTERNAL_REALLOC( buffer, size ); 520 if ( buffer == NULL ) { 521 KMP_FATAL( MemoryAllocFailed ); 522 }; // if 523 524 }; // forever 525 526 return buffer; 527 528 } // func __kmp_str_format 529 530 531 void 532 __kmp_str_free( 533 char const * * str 534 ) { 535 KMP_DEBUG_ASSERT( str != NULL ); 536 KMP_INTERNAL_FREE( (void *) * str ); 537 * str = NULL; 538 } // func __kmp_str_free 539 540 541 /* If len is zero, returns true iff target and data have exact case-insensitive match. 542 If len is negative, returns true iff target is a case-insensitive substring of data. 543 If len is positive, returns true iff target is a case-insensitive substring of data or 544 vice versa, and neither is shorter than len. 545 */ 546 int 547 __kmp_str_match( 548 char const * target, 549 int len, 550 char const * data 551 ) { 552 int i; 553 if ( target == NULL || data == NULL ) { 554 return FALSE; 555 }; // if 556 for ( i = 0; target[i] && data[i]; ++ i ) { 557 if ( TOLOWER( target[i] ) != TOLOWER( data[i] ) ) { 558 return FALSE; 559 }; // if 560 }; // for i 561 return ( ( len > 0 ) ? i >= len : ( ! target[i] && ( len || ! data[i] ) ) ); 562 } // __kmp_str_match 563 564 565 int 566 __kmp_str_match_false( char const * data ) { 567 int result = 568 __kmp_str_match( "false", 1, data ) || 569 __kmp_str_match( "off", 2, data ) || 570 __kmp_str_match( "0", 1, data ) || 571 __kmp_str_match( ".false.", 2, data ) || 572 __kmp_str_match( ".f.", 2, data ) || 573 __kmp_str_match( "no", 1, data ); 574 return result; 575 } // __kmp_str_match_false 576 577 578 int 579 __kmp_str_match_true( char const * data ) { 580 int result = 581 __kmp_str_match( "true", 1, data ) || 582 __kmp_str_match( "on", 2, data ) || 583 __kmp_str_match( "1", 1, data ) || 584 __kmp_str_match( ".true.", 2, data ) || 585 __kmp_str_match( ".t.", 2, data ) || 586 __kmp_str_match( "yes", 1, data ); 587 return result; 588 } // __kmp_str_match_true 589 590 void 591 __kmp_str_replace( 592 char * str, 593 char search_for, 594 char replace_with 595 ) { 596 597 char * found = NULL; 598 599 found = strchr( str, search_for ); 600 while ( found ) { 601 * found = replace_with; 602 found = strchr( found + 1, search_for ); 603 }; // while 604 605 } // __kmp_str_replace 606 607 608 void 609 __kmp_str_split( 610 char * str, // I: String to split. 611 char delim, // I: Character to split on. 612 char ** head, // O: Pointer to head (may be NULL). 613 char ** tail // O: Pointer to tail (may be NULL). 614 ) { 615 char * h = str; 616 char * t = NULL; 617 if ( str != NULL ) { 618 char * ptr = strchr( str, delim ); 619 if ( ptr != NULL ) { 620 * ptr = 0; 621 t = ptr + 1; 622 }; // if 623 }; // if 624 if ( head != NULL ) { 625 * head = h; 626 }; // if 627 if ( tail != NULL ) { 628 * tail = t; 629 }; // if 630 } // __kmp_str_split 631 632 /* 633 strtok_r() is not available on Windows* OS. This function reimplements strtok_r(). 634 */ 635 char * 636 __kmp_str_token( 637 char * str, // String to split into tokens. Note: String *is* modified! 638 char const * delim, // Delimiters. 639 char ** buf // Internal buffer. 640 ) { 641 char * token = NULL; 642 #if KMP_OS_WINDOWS 643 // On Windows* OS there is no strtok_r() function. Let us implement it. 644 if ( str != NULL ) { 645 * buf = str; // First call, initialize buf. 646 }; // if 647 * buf += strspn( * buf, delim ); // Skip leading delimiters. 648 if ( ** buf != 0 ) { // Rest of the string is not yet empty. 649 token = * buf; // Use it as result. 650 * buf += strcspn( * buf, delim ); // Skip non-delimiters. 651 if ( ** buf != 0 ) { // Rest of the string is not yet empty. 652 ** buf = 0; // Terminate token here. 653 * buf += 1; // Advance buf to start with the next token next time. 654 }; // if 655 }; // if 656 #else 657 // On Linux* OS and OS X*, strtok_r() is available. Let us use it. 658 token = strtok_r( str, delim, buf ); 659 #endif 660 return token; 661 }; // __kmp_str_token 662 663 664 int 665 __kmp_str_to_int( 666 char const * str, 667 char sentinel 668 ) { 669 int result, factor; 670 char const * t; 671 672 result = 0; 673 674 for (t = str; *t != '\0'; ++t) { 675 if (*t < '0' || *t > '9') 676 break; 677 result = (result * 10) + (*t - '0'); 678 } 679 680 switch (*t) { 681 case '\0': /* the current default for no suffix is bytes */ 682 factor = 1; 683 break; 684 case 'b': case 'B': /* bytes */ 685 ++t; 686 factor = 1; 687 break; 688 case 'k': case 'K': /* kilo-bytes */ 689 ++t; 690 factor = 1024; 691 break; 692 case 'm': case 'M': /* mega-bytes */ 693 ++t; 694 factor = (1024 * 1024); 695 break; 696 default: 697 if(*t != sentinel) 698 return (-1); 699 t = ""; 700 factor = 1; 701 } 702 703 if (result > (INT_MAX / factor)) 704 result = INT_MAX; 705 else 706 result *= factor; 707 708 return (*t != 0 ? 0 : result); 709 710 } // __kmp_str_to_int 711 712 713 /* 714 The routine parses input string. It is expected it is a unsigned integer with optional unit. 715 Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb" or "m" for megabytes, ..., "yb" 716 or "y" for yottabytes. :-) Unit name is case-insensitive. The routine returns 0 if everything is 717 ok, or error code: -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed 718 value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown unit *size is set 719 to zero. 720 */ 721 void 722 __kmp_str_to_size( // R: Error code. 723 char const * str, // I: String of characters, unsigned number and unit ("b", "kb", etc). 724 size_t * out, // O: Parsed number. 725 size_t dfactor, // I: The factor if none of the letters specified. 726 char const * * error // O: Null if everything is ok, error message otherwise. 727 ) { 728 729 size_t value = 0; 730 size_t factor = 0; 731 int overflow = 0; 732 int i = 0; 733 int digit; 734 735 736 KMP_DEBUG_ASSERT( str != NULL ); 737 738 // Skip spaces. 739 while ( str[ i ] == ' ' || str[ i ] == '\t') { 740 ++ i; 741 }; // while 742 743 // Parse number. 744 if ( str[ i ] < '0' || str[ i ] > '9' ) { 745 * error = KMP_I18N_STR( NotANumber ); 746 return; 747 }; // if 748 do { 749 digit = str[ i ] - '0'; 750 overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 ); 751 value = ( value * 10 ) + digit; 752 ++ i; 753 } while ( str[ i ] >= '0' && str[ i ] <= '9' ); 754 755 // Skip spaces. 756 while ( str[ i ] == ' ' || str[ i ] == '\t' ) { 757 ++ i; 758 }; // while 759 760 // Parse unit. 761 #define _case( ch, exp ) \ 762 case ch : \ 763 case ch - ( 'a' - 'A' ) : { \ 764 size_t shift = (exp) * 10; \ 765 ++ i; \ 766 if ( shift < sizeof( size_t ) * 8 ) { \ 767 factor = (size_t)( 1 ) << shift; \ 768 } else { \ 769 overflow = 1; \ 770 }; \ 771 } break; 772 switch ( str[ i ] ) { 773 _case( 'k', 1 ); // Kilo 774 _case( 'm', 2 ); // Mega 775 _case( 'g', 3 ); // Giga 776 _case( 't', 4 ); // Tera 777 _case( 'p', 5 ); // Peta 778 _case( 'e', 6 ); // Exa 779 _case( 'z', 7 ); // Zetta 780 _case( 'y', 8 ); // Yotta 781 // Oops. No more units... 782 }; // switch 783 #undef _case 784 if ( str[ i ] == 'b' || str[ i ] == 'B' ) { // Skip optional "b". 785 if ( factor == 0 ) { 786 factor = 1; 787 } 788 ++ i; 789 }; // if 790 if ( ! ( str[ i ] == ' ' || str[ i ] == '\t' || str[ i ] == 0 ) ) { // Bad unit 791 * error = KMP_I18N_STR( BadUnit ); 792 return; 793 }; // if 794 795 if ( factor == 0 ) { 796 factor = dfactor; 797 } 798 799 // Apply factor. 800 overflow = overflow || ( value > ( KMP_SIZE_T_MAX / factor ) ); 801 value *= factor; 802 803 // Skip spaces. 804 while ( str[ i ] == ' ' || str[ i ] == '\t' ) { 805 ++ i; 806 }; // while 807 808 if ( str[ i ] != 0 ) { 809 * error = KMP_I18N_STR( IllegalCharacters ); 810 return; 811 }; // if 812 813 if ( overflow ) { 814 * error = KMP_I18N_STR( ValueTooLarge ); 815 * out = KMP_SIZE_T_MAX; 816 return; 817 }; // if 818 819 * error = NULL; 820 * out = value; 821 822 } // __kmp_str_to_size 823 824 825 void 826 __kmp_str_to_uint( // R: Error code. 827 char const * str, // I: String of characters, unsigned number. 828 kmp_uint64 * out, // O: Parsed number. 829 char const * * error // O: Null if everything is ok, error message otherwise. 830 ) { 831 832 size_t value = 0; 833 int overflow = 0; 834 int i = 0; 835 int digit; 836 837 838 KMP_DEBUG_ASSERT( str != NULL ); 839 840 // Skip spaces. 841 while ( str[ i ] == ' ' || str[ i ] == '\t' ) { 842 ++ i; 843 }; // while 844 845 // Parse number. 846 if ( str[ i ] < '0' || str[ i ] > '9' ) { 847 * error = KMP_I18N_STR( NotANumber ); 848 return; 849 }; // if 850 do { 851 digit = str[ i ] - '0'; 852 overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 ); 853 value = ( value * 10 ) + digit; 854 ++ i; 855 } while ( str[ i ] >= '0' && str[ i ] <= '9' ); 856 857 // Skip spaces. 858 while ( str[ i ] == ' ' || str[ i ] == '\t' ) { 859 ++ i; 860 }; // while 861 862 if ( str[ i ] != 0 ) { 863 * error = KMP_I18N_STR( IllegalCharacters ); 864 return; 865 }; // if 866 867 if ( overflow ) { 868 * error = KMP_I18N_STR( ValueTooLarge ); 869 * out = (kmp_uint64) -1; 870 return; 871 }; // if 872 873 * error = NULL; 874 * out = value; 875 876 } // __kmp_str_to_unit 877 878 879 880 // end of file // 881