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