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