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