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