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