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