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