LLVM OpenMP* Runtime Library
kmp_str.cpp
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 
71 void __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 
80 void __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 
110 void __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 
123 void __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 
134 void __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 
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  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
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
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
221 int __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". */
232 void __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 
246 void __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 
277 void __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 
283 int __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.
305 void __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 
347 kmp_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 
393 void __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*. */
404 int __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 
448 char *__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 
494 void __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. */
505 int __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
520 bool __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 
543 int __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 
552 int __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 
561 void __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 
571 void __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(). */
595 char *__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 
622 int __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  // Cap parsing to create largest integer
632  if (result >= (INT_MAX - (*t - '0')) / 10) {
633  result = INT_MAX;
634  break;
635  }
636  result = (result * 10) + (*t - '0');
637  }
638 
639  return result;
640 }
641 
642 int __kmp_str_to_int(char const *str, char sentinel) {
643  int result, factor;
644  char const *t;
645 
646  result = 0;
647 
648  for (t = str; *t != '\0'; ++t) {
649  if (*t < '0' || *t > '9')
650  break;
651  // Cap parsing to create largest integer
652  if (result >= (INT_MAX - (*t - '0')) / 10) {
653  result = INT_MAX;
654  break;
655  }
656  result = (result * 10) + (*t - '0');
657  }
658 
659  // Parse rest of large number by skipping the digits so t points to sentinel
660  if (result == INT_MAX)
661  for (t = str; *t != '\0'; ++t)
662  if (*t < '0' || *t > '9')
663  break;
664 
665  switch (*t) {
666  case '\0': /* the current default for no suffix is bytes */
667  factor = 1;
668  break;
669  case 'b':
670  case 'B': /* bytes */
671  ++t;
672  factor = 1;
673  break;
674  case 'k':
675  case 'K': /* kilo-bytes */
676  ++t;
677  factor = 1024;
678  break;
679  case 'm':
680  case 'M': /* mega-bytes */
681  ++t;
682  factor = (1024 * 1024);
683  break;
684  default:
685  if (*t != sentinel)
686  return (-1);
687  t = "";
688  factor = 1;
689  }
690 
691  if (result > (INT_MAX / factor))
692  result = INT_MAX;
693  else
694  result *= factor;
695 
696  return (*t != 0 ? 0 : result);
697 } // __kmp_str_to_int
698 
699 /* The routine parses input string. It is expected it is a unsigned integer with
700  optional unit. Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb"
701  or "m" for megabytes, ..., "yb" or "y" for yottabytes. :-) Unit name is
702  case-insensitive. The routine returns 0 if everything is ok, or error code:
703  -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
704  value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown
705  unit *size is set to zero. */
706 void __kmp_str_to_size( // R: Error code.
707  char const *str, // I: String of characters, unsigned number and unit ("b",
708  // "kb", etc).
709  size_t *out, // O: Parsed number.
710  size_t dfactor, // I: The factor if none of the letters specified.
711  char const **error // O: Null if everything is ok, error message otherwise.
712 ) {
713 
714  size_t value = 0;
715  size_t factor = 0;
716  int overflow = 0;
717  int i = 0;
718  int digit;
719 
720  KMP_DEBUG_ASSERT(str != NULL);
721 
722  // Skip spaces.
723  while (str[i] == ' ' || str[i] == '\t') {
724  ++i;
725  }
726 
727  // Parse number.
728  if (str[i] < '0' || str[i] > '9') {
729  *error = KMP_I18N_STR(NotANumber);
730  return;
731  }
732  do {
733  digit = str[i] - '0';
734  overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
735  value = (value * 10) + digit;
736  ++i;
737  } while (str[i] >= '0' && str[i] <= '9');
738 
739  // Skip spaces.
740  while (str[i] == ' ' || str[i] == '\t') {
741  ++i;
742  }
743 
744 // Parse unit.
745 #define _case(ch, exp) \
746  case ch: \
747  case ch - ('a' - 'A'): { \
748  size_t shift = (exp)*10; \
749  ++i; \
750  if (shift < sizeof(size_t) * 8) { \
751  factor = (size_t)(1) << shift; \
752  } else { \
753  overflow = 1; \
754  } \
755  } break;
756  switch (str[i]) {
757  _case('k', 1); // Kilo
758  _case('m', 2); // Mega
759  _case('g', 3); // Giga
760  _case('t', 4); // Tera
761  _case('p', 5); // Peta
762  _case('e', 6); // Exa
763  _case('z', 7); // Zetta
764  _case('y', 8); // Yotta
765  // Oops. No more units...
766  }
767 #undef _case
768  if (str[i] == 'b' || str[i] == 'B') { // Skip optional "b".
769  if (factor == 0) {
770  factor = 1;
771  }
772  ++i;
773  }
774  if (!(str[i] == ' ' || str[i] == '\t' || str[i] == 0)) { // Bad unit
775  *error = KMP_I18N_STR(BadUnit);
776  return;
777  }
778 
779  if (factor == 0) {
780  factor = dfactor;
781  }
782 
783  // Apply factor.
784  overflow = overflow || (value > (KMP_SIZE_T_MAX / factor));
785  value *= factor;
786 
787  // Skip spaces.
788  while (str[i] == ' ' || str[i] == '\t') {
789  ++i;
790  }
791 
792  if (str[i] != 0) {
793  *error = KMP_I18N_STR(IllegalCharacters);
794  return;
795  }
796 
797  if (overflow) {
798  *error = KMP_I18N_STR(ValueTooLarge);
799  *out = KMP_SIZE_T_MAX;
800  return;
801  }
802 
803  *error = NULL;
804  *out = value;
805 } // __kmp_str_to_size
806 
807 void __kmp_str_to_uint( // R: Error code.
808  char const *str, // I: String of characters, unsigned number.
809  kmp_uint64 *out, // O: Parsed number.
810  char const **error // O: Null if everything is ok, error message otherwise.
811 ) {
812  size_t value = 0;
813  int overflow = 0;
814  int i = 0;
815  int digit;
816 
817  KMP_DEBUG_ASSERT(str != NULL);
818 
819  // Skip spaces.
820  while (str[i] == ' ' || str[i] == '\t') {
821  ++i;
822  }
823 
824  // Parse number.
825  if (str[i] < '0' || str[i] > '9') {
826  *error = KMP_I18N_STR(NotANumber);
827  return;
828  }
829  do {
830  digit = str[i] - '0';
831  overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
832  value = (value * 10) + digit;
833  ++i;
834  } while (str[i] >= '0' && str[i] <= '9');
835 
836  // Skip spaces.
837  while (str[i] == ' ' || str[i] == '\t') {
838  ++i;
839  }
840 
841  if (str[i] != 0) {
842  *error = KMP_I18N_STR(IllegalCharacters);
843  return;
844  }
845 
846  if (overflow) {
847  *error = KMP_I18N_STR(ValueTooLarge);
848  *out = (kmp_uint64)-1;
849  return;
850  }
851 
852  *error = NULL;
853  *out = value;
854 } // __kmp_str_to_unit
855 
856 // end of file //