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