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   }
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       }
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       }
105     }
106   }
107 
108   KMP_DEBUG_ASSERT(buffer->size > 0);
109   KMP_DEBUG_ASSERT(buffer->size >= (unsigned)size);
110   KMP_STR_BUF_INVARIANT(buffer);
111 } // __kmp_str_buf_reserve
112 
113 void __kmp_str_buf_detach(kmp_str_buf_t *buffer) {
114   KMP_STR_BUF_INVARIANT(buffer);
115 
116   // If internal bulk is used, allocate memory and copy it.
117   if (buffer->size <= sizeof(buffer->bulk)) {
118     buffer->str = (char *)KMP_INTERNAL_MALLOC(buffer->size);
119     if (buffer->str == NULL) {
120       KMP_FATAL(MemoryAllocFailed);
121     }
122     KMP_MEMCPY_S(buffer->str, buffer->size, buffer->bulk, buffer->used + 1);
123   }
124 } // __kmp_str_buf_detach
125 
126 void __kmp_str_buf_free(kmp_str_buf_t *buffer) {
127   KMP_STR_BUF_INVARIANT(buffer);
128   if (buffer->size > sizeof(buffer->bulk)) {
129     KMP_INTERNAL_FREE(buffer->str);
130   }
131   buffer->str = buffer->bulk;
132   buffer->size = sizeof(buffer->bulk);
133   buffer->used = 0;
134   KMP_STR_BUF_INVARIANT(buffer);
135 } // __kmp_str_buf_free
136 
137 void __kmp_str_buf_cat(kmp_str_buf_t *buffer, char const *str, int len) {
138   KMP_STR_BUF_INVARIANT(buffer);
139   KMP_DEBUG_ASSERT(str != NULL);
140   KMP_DEBUG_ASSERT(len >= 0);
141   __kmp_str_buf_reserve(buffer, buffer->used + len + 1);
142   KMP_MEMCPY(buffer->str + buffer->used, str, len);
143   buffer->str[buffer->used + len] = 0;
144   buffer->used += len;
145   KMP_STR_BUF_INVARIANT(buffer);
146 } // __kmp_str_buf_cat
147 
148 void __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
149                           va_list args) {
150   KMP_STR_BUF_INVARIANT(buffer);
151 
152   for (;;) {
153     int const free = buffer->size - buffer->used;
154     int rc;
155     int size;
156 
157     // Try to format string.
158     {
159 /* On Linux* OS Intel(R) 64, vsnprintf() modifies args argument, so vsnprintf()
160    crashes if it is called for the second time with the same args. To prevent
161    the crash, we have to pass a fresh intact copy of args to vsnprintf() on each
162    iteration.
163 
164    Unfortunately, standard va_copy() macro is not available on Windows* OS.
165    However, it seems vsnprintf() does not modify args argument on Windows* OS.
166 */
167 
168 #if !KMP_OS_WINDOWS
169       va_list _args;
170       va_copy(_args, args); // Make copy of args.
171 #define args _args // Substitute args with its copy, _args.
172 #endif // KMP_OS_WINDOWS
173       rc = KMP_VSNPRINTF(buffer->str + buffer->used, free, format, args);
174 #if !KMP_OS_WINDOWS
175 #undef args // Remove substitution.
176       va_end(_args);
177 #endif // KMP_OS_WINDOWS
178     }
179 
180     // No errors, string has been formatted.
181     if (rc >= 0 && rc < free) {
182       buffer->used += rc;
183       break;
184     }
185 
186     // Error occurred, buffer is too small.
187     if (rc >= 0) {
188       // C99-conforming implementation of vsnprintf returns required buffer size
189       size = buffer->used + rc + 1;
190     } else {
191       // Older implementations just return -1. Double buffer size.
192       size = buffer->size * 2;
193     }
194 
195     // Enlarge buffer.
196     __kmp_str_buf_reserve(buffer, size);
197 
198     // And try again.
199   }
200 
201   KMP_DEBUG_ASSERT(buffer->size > 0);
202   KMP_STR_BUF_INVARIANT(buffer);
203 } // __kmp_str_buf_vprint
204 
205 void __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...) {
206   va_list args;
207   va_start(args, format);
208   __kmp_str_buf_vprint(buffer, format, args);
209   va_end(args);
210 } // __kmp_str_buf_print
211 
212 /* The function prints specified size to buffer. Size is expressed using biggest
213    possible unit, for example 1024 is printed as "1k". */
214 void __kmp_str_buf_print_size(kmp_str_buf_t *buf, size_t size) {
215   char const *names[] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y"};
216   int const units = sizeof(names) / sizeof(char const *);
217   int u = 0;
218   if (size > 0) {
219     while ((size % 1024 == 0) && (u + 1 < units)) {
220       size = size / 1024;
221       ++u;
222     }
223   }
224 
225   __kmp_str_buf_print(buf, "%" KMP_SIZE_T_SPEC "%s", size, names[u]);
226 } // __kmp_str_buf_print_size
227 
228 void __kmp_str_fname_init(kmp_str_fname_t *fname, char const *path) {
229   fname->path = NULL;
230   fname->dir = NULL;
231   fname->base = NULL;
232 
233   if (path != NULL) {
234     char *slash = NULL; // Pointer to the last character of dir.
235     char *base = NULL; // Pointer to the beginning of basename.
236     fname->path = __kmp_str_format("%s", path);
237     // Original code used strdup() function to copy a string, but on Windows* OS
238     // Intel(R) 64 it causes assertioon id debug heap, so I had to replace
239     // strdup with __kmp_str_format().
240     if (KMP_OS_WINDOWS) {
241       __kmp_str_replace(fname->path, '\\', '/');
242     }
243     fname->dir = __kmp_str_format("%s", fname->path);
244     slash = strrchr(fname->dir, '/');
245     if (KMP_OS_WINDOWS &&
246         slash == NULL) { // On Windows* OS, if slash not found,
247       char first = TOLOWER(fname->dir[0]); // look for drive.
248       if ('a' <= first && first <= 'z' && fname->dir[1] == ':') {
249         slash = &fname->dir[1];
250       }
251     }
252     base = (slash == NULL ? fname->dir : slash + 1);
253     fname->base = __kmp_str_format("%s", base); // Copy basename
254     *base = 0; // and truncate dir.
255   }
256 
257 } // kmp_str_fname_init
258 
259 void __kmp_str_fname_free(kmp_str_fname_t *fname) {
260   __kmp_str_free(CCAST(char const **, &fname->path));
261   __kmp_str_free(CCAST(char const **, &fname->dir));
262   __kmp_str_free(CCAST(char const **, &fname->base));
263 } // kmp_str_fname_free
264 
265 int __kmp_str_fname_match(kmp_str_fname_t const *fname, char const *pattern) {
266   int dir_match = 1;
267   int base_match = 1;
268 
269   if (pattern != NULL) {
270     kmp_str_fname_t ptrn;
271     __kmp_str_fname_init(&ptrn, pattern);
272     dir_match = strcmp(ptrn.dir, "*/") == 0 ||
273                 (fname->dir != NULL && __kmp_str_eqf(fname->dir, ptrn.dir));
274     base_match = strcmp(ptrn.base, "*") == 0 ||
275                  (fname->base != NULL && __kmp_str_eqf(fname->base, ptrn.base));
276     __kmp_str_fname_free(&ptrn);
277   }
278 
279   return dir_match && base_match;
280 } // __kmp_str_fname_match
281 
282 kmp_str_loc_t __kmp_str_loc_init(char const *psource, int init_fname) {
283   kmp_str_loc_t loc;
284 
285   loc._bulk = NULL;
286   loc.file = NULL;
287   loc.func = NULL;
288   loc.line = 0;
289   loc.col = 0;
290 
291   if (psource != NULL) {
292     char *str = NULL;
293     char *dummy = NULL;
294     char *line = NULL;
295     char *col = NULL;
296 
297     // Copy psource to keep it intact.
298     loc._bulk = __kmp_str_format("%s", psource);
299 
300     // Parse psource string: ";file;func;line;col;;"
301     str = loc._bulk;
302     __kmp_str_split(str, ';', &dummy, &str);
303     __kmp_str_split(str, ';', &loc.file, &str);
304     __kmp_str_split(str, ';', &loc.func, &str);
305     __kmp_str_split(str, ';', &line, &str);
306     __kmp_str_split(str, ';', &col, &str);
307 
308     // Convert line and col into numberic values.
309     if (line != NULL) {
310       loc.line = atoi(line);
311       if (loc.line < 0) {
312         loc.line = 0;
313       }
314     }
315     if (col != NULL) {
316       loc.col = atoi(col);
317       if (loc.col < 0) {
318         loc.col = 0;
319       }
320     }
321   }
322 
323   __kmp_str_fname_init(&loc.fname, init_fname ? loc.file : NULL);
324 
325   return loc;
326 } // kmp_str_loc_init
327 
328 void __kmp_str_loc_free(kmp_str_loc_t *loc) {
329   __kmp_str_fname_free(&loc->fname);
330   __kmp_str_free(CCAST(const char **, &(loc->_bulk)));
331   loc->file = NULL;
332   loc->func = NULL;
333 } // kmp_str_loc_free
334 
335 /* This function is intended to compare file names. On Windows* OS file names
336    are case-insensitive, so functions performs case-insensitive comparison. On
337    Linux* OS it performs case-sensitive comparison. Note: The function returns
338    *true* if strings are *equal*. */
339 int __kmp_str_eqf( // True, if strings are equal, false otherwise.
340     char const *lhs, // First string.
341     char const *rhs // Second string.
342     ) {
343   int result;
344 #if KMP_OS_WINDOWS
345   result = (_stricmp(lhs, rhs) == 0);
346 #else
347   result = (strcmp(lhs, rhs) == 0);
348 #endif
349   return result;
350 } // __kmp_str_eqf
351 
352 /* This function is like sprintf, but it *allocates* new buffer, which must be
353    freed eventually by __kmp_str_free(). The function is very convenient for
354    constructing strings, it successfully replaces strdup(), strcat(), it frees
355    programmer from buffer allocations and helps to avoid buffer overflows.
356    Examples:
357 
358    str = __kmp_str_format("%s", orig); //strdup() doesn't care about buffer size
359    __kmp_str_free( & str );
360    str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), doesn't care
361                                                    // about buffer size.
362    __kmp_str_free( & str );
363    str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
364    __kmp_str_free( & str );
365 
366    Performance note:
367    This function allocates memory with malloc() calls, so do not call it from
368    performance-critical code. In performance-critical code consider using
369    kmp_str_buf_t instead, since it uses stack-allocated buffer for short
370    strings.
371 
372    Why does this function use malloc()?
373    1. __kmp_allocate() returns cache-aligned memory allocated with malloc().
374       There are no reasons in using __kmp_allocate() for strings due to extra
375       overhead while cache-aligned memory is not necessary.
376    2. __kmp_thread_malloc() cannot be used because it requires pointer to thread
377       structure. We need to perform string operations during library startup
378       (for example, in __kmp_register_library_startup()) when no thread
379       structures are allocated yet.
380    So standard malloc() is the only available option.
381 */
382 
383 char *__kmp_str_format( // Allocated string.
384     char const *format, // Format string.
385     ... // Other parameters.
386     ) {
387   va_list args;
388   int size = 512;
389   char *buffer = NULL;
390   int rc;
391 
392   // Allocate buffer.
393   buffer = (char *)KMP_INTERNAL_MALLOC(size);
394   if (buffer == NULL) {
395     KMP_FATAL(MemoryAllocFailed);
396   }
397 
398   for (;;) {
399     // Try to format string.
400     va_start(args, format);
401     rc = KMP_VSNPRINTF(buffer, size, format, args);
402     va_end(args);
403 
404     // No errors, string has been formatted.
405     if (rc >= 0 && rc < size) {
406       break;
407     }
408 
409     // Error occurred, buffer is too small.
410     if (rc >= 0) {
411       // C99-conforming implementation of vsnprintf returns required buffer
412       // size.
413       size = rc + 1;
414     } else {
415       // Older implementations just return -1.
416       size = size * 2;
417     }
418 
419     // Enlarge buffer and try again.
420     buffer = (char *)KMP_INTERNAL_REALLOC(buffer, size);
421     if (buffer == NULL) {
422       KMP_FATAL(MemoryAllocFailed);
423     }
424   }
425 
426   return buffer;
427 } // func __kmp_str_format
428 
429 void __kmp_str_free(char const **str) {
430   KMP_DEBUG_ASSERT(str != NULL);
431   KMP_INTERNAL_FREE(CCAST(char *, *str));
432   *str = NULL;
433 } // func __kmp_str_free
434 
435 /* If len is zero, returns true iff target and data have exact case-insensitive
436    match. If len is negative, returns true iff target is a case-insensitive
437    substring of data. If len is positive, returns true iff target is a
438    case-insensitive substring of data or vice versa, and neither is shorter than
439    len. */
440 int __kmp_str_match(char const *target, int len, char const *data) {
441   int i;
442   if (target == NULL || data == NULL) {
443     return FALSE;
444   }
445   for (i = 0; target[i] && data[i]; ++i) {
446     if (TOLOWER(target[i]) != TOLOWER(data[i])) {
447       return FALSE;
448     }
449   }
450   return ((len > 0) ? i >= len : (!target[i] && (len || !data[i])));
451 } // __kmp_str_match
452 
453 int __kmp_str_match_false(char const *data) {
454   int result =
455       __kmp_str_match("false", 1, data) || __kmp_str_match("off", 2, data) ||
456       __kmp_str_match("0", 1, data) || __kmp_str_match(".false.", 2, data) ||
457       __kmp_str_match(".f.", 2, data) || __kmp_str_match("no", 1, data);
458   return result;
459 } // __kmp_str_match_false
460 
461 int __kmp_str_match_true(char const *data) {
462   int result =
463       __kmp_str_match("true", 1, data) || __kmp_str_match("on", 2, data) ||
464       __kmp_str_match("1", 1, data) || __kmp_str_match(".true.", 2, data) ||
465       __kmp_str_match(".t.", 2, data) || __kmp_str_match("yes", 1, 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