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