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