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