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