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, 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 
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, 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 
145 void __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
160 int __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
219 int __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". */
230 void __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 
244 void __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 
275 void __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 
281 int __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 
298 kmp_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 
344 void __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*. */
355 int __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 
399 char *__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 
445 void __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. */
456 int __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 
469 int __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 
478 int __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 
487 void __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 
497 void __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(). */
521 char *__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 
548 int __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. */
601 void __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 
702 void __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 //