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