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 int __kmp_str_match_false(char const *data) {
519  int result =
520  __kmp_str_match("false", 1, data) || __kmp_str_match("off", 2, data) ||
521  __kmp_str_match("0", 1, data) || __kmp_str_match(".false.", 2, data) ||
522  __kmp_str_match(".f.", 2, data) || __kmp_str_match("no", 1, data) ||
523  __kmp_str_match("disabled", 0, data);
524  return result;
525 } // __kmp_str_match_false
526 
527 int __kmp_str_match_true(char const *data) {
528  int result =
529  __kmp_str_match("true", 1, data) || __kmp_str_match("on", 2, data) ||
530  __kmp_str_match("1", 1, data) || __kmp_str_match(".true.", 2, data) ||
531  __kmp_str_match(".t.", 2, data) || __kmp_str_match("yes", 1, data) ||
532  __kmp_str_match("enabled", 0, data);
533  return result;
534 } // __kmp_str_match_true
535 
536 void __kmp_str_replace(char *str, char search_for, char replace_with) {
537  char *found = NULL;
538 
539  found = strchr(str, search_for);
540  while (found) {
541  *found = replace_with;
542  found = strchr(found + 1, search_for);
543  }
544 } // __kmp_str_replace
545 
546 void __kmp_str_split(char *str, // I: String to split.
547  char delim, // I: Character to split on.
548  char **head, // O: Pointer to head (may be NULL).
549  char **tail // O: Pointer to tail (may be NULL).
550 ) {
551  char *h = str;
552  char *t = NULL;
553  if (str != NULL) {
554  char *ptr = strchr(str, delim);
555  if (ptr != NULL) {
556  *ptr = 0;
557  t = ptr + 1;
558  }
559  }
560  if (head != NULL) {
561  *head = h;
562  }
563  if (tail != NULL) {
564  *tail = t;
565  }
566 } // __kmp_str_split
567 
568 /* strtok_r() is not available on Windows* OS. This function reimplements
569  strtok_r(). */
570 char *__kmp_str_token(
571  char *str, // String to split into tokens. Note: String *is* modified!
572  char const *delim, // Delimiters.
573  char **buf // Internal buffer.
574 ) {
575  char *token = NULL;
576 #if KMP_OS_WINDOWS
577  // On Windows* OS there is no strtok_r() function. Let us implement it.
578  if (str != NULL) {
579  *buf = str; // First call, initialize buf.
580  }
581  *buf += strspn(*buf, delim); // Skip leading delimiters.
582  if (**buf != 0) { // Rest of the string is not yet empty.
583  token = *buf; // Use it as result.
584  *buf += strcspn(*buf, delim); // Skip non-delimiters.
585  if (**buf != 0) { // Rest of the string is not yet empty.
586  **buf = 0; // Terminate token here.
587  *buf += 1; // Advance buf to start with the next token next time.
588  }
589  }
590 #else
591  // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
592  token = strtok_r(str, delim, buf);
593 #endif
594  return token;
595 } // __kmp_str_token
596 
597 int __kmp_str_to_int(char const *str, char sentinel) {
598  int result, factor;
599  char const *t;
600 
601  result = 0;
602 
603  for (t = str; *t != '\0'; ++t) {
604  if (*t < '0' || *t > '9')
605  break;
606  result = (result * 10) + (*t - '0');
607  }
608 
609  switch (*t) {
610  case '\0': /* the current default for no suffix is bytes */
611  factor = 1;
612  break;
613  case 'b':
614  case 'B': /* bytes */
615  ++t;
616  factor = 1;
617  break;
618  case 'k':
619  case 'K': /* kilo-bytes */
620  ++t;
621  factor = 1024;
622  break;
623  case 'm':
624  case 'M': /* mega-bytes */
625  ++t;
626  factor = (1024 * 1024);
627  break;
628  default:
629  if (*t != sentinel)
630  return (-1);
631  t = "";
632  factor = 1;
633  }
634 
635  if (result > (INT_MAX / factor))
636  result = INT_MAX;
637  else
638  result *= factor;
639 
640  return (*t != 0 ? 0 : result);
641 } // __kmp_str_to_int
642 
643 /* The routine parses input string. It is expected it is a unsigned integer with
644  optional unit. Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb"
645  or "m" for megabytes, ..., "yb" or "y" for yottabytes. :-) Unit name is
646  case-insensitive. The routine returns 0 if everything is ok, or error code:
647  -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
648  value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown
649  unit *size is set to zero. */
650 void __kmp_str_to_size( // R: Error code.
651  char const *str, // I: String of characters, unsigned number and unit ("b",
652  // "kb", etc).
653  size_t *out, // O: Parsed number.
654  size_t dfactor, // I: The factor if none of the letters specified.
655  char const **error // O: Null if everything is ok, error message otherwise.
656 ) {
657 
658  size_t value = 0;
659  size_t factor = 0;
660  int overflow = 0;
661  int i = 0;
662  int digit;
663 
664  KMP_DEBUG_ASSERT(str != NULL);
665 
666  // Skip spaces.
667  while (str[i] == ' ' || str[i] == '\t') {
668  ++i;
669  }
670 
671  // Parse number.
672  if (str[i] < '0' || str[i] > '9') {
673  *error = KMP_I18N_STR(NotANumber);
674  return;
675  }
676  do {
677  digit = str[i] - '0';
678  overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
679  value = (value * 10) + digit;
680  ++i;
681  } while (str[i] >= '0' && str[i] <= '9');
682 
683  // Skip spaces.
684  while (str[i] == ' ' || str[i] == '\t') {
685  ++i;
686  }
687 
688 // Parse unit.
689 #define _case(ch, exp) \
690  case ch: \
691  case ch - ('a' - 'A'): { \
692  size_t shift = (exp)*10; \
693  ++i; \
694  if (shift < sizeof(size_t) * 8) { \
695  factor = (size_t)(1) << shift; \
696  } else { \
697  overflow = 1; \
698  } \
699  } break;
700  switch (str[i]) {
701  _case('k', 1); // Kilo
702  _case('m', 2); // Mega
703  _case('g', 3); // Giga
704  _case('t', 4); // Tera
705  _case('p', 5); // Peta
706  _case('e', 6); // Exa
707  _case('z', 7); // Zetta
708  _case('y', 8); // Yotta
709  // Oops. No more units...
710  }
711 #undef _case
712  if (str[i] == 'b' || str[i] == 'B') { // Skip optional "b".
713  if (factor == 0) {
714  factor = 1;
715  }
716  ++i;
717  }
718  if (!(str[i] == ' ' || str[i] == '\t' || str[i] == 0)) { // Bad unit
719  *error = KMP_I18N_STR(BadUnit);
720  return;
721  }
722 
723  if (factor == 0) {
724  factor = dfactor;
725  }
726 
727  // Apply factor.
728  overflow = overflow || (value > (KMP_SIZE_T_MAX / factor));
729  value *= factor;
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_SIZE_T_MAX;
744  return;
745  }
746 
747  *error = NULL;
748  *out = value;
749 } // __kmp_str_to_size
750 
751 void __kmp_str_to_uint( // R: Error code.
752  char const *str, // I: String of characters, unsigned number.
753  kmp_uint64 *out, // O: Parsed number.
754  char const **error // O: Null if everything is ok, error message otherwise.
755 ) {
756  size_t value = 0;
757  int overflow = 0;
758  int i = 0;
759  int digit;
760 
761  KMP_DEBUG_ASSERT(str != NULL);
762 
763  // Skip spaces.
764  while (str[i] == ' ' || str[i] == '\t') {
765  ++i;
766  }
767 
768  // Parse number.
769  if (str[i] < '0' || str[i] > '9') {
770  *error = KMP_I18N_STR(NotANumber);
771  return;
772  }
773  do {
774  digit = str[i] - '0';
775  overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
776  value = (value * 10) + digit;
777  ++i;
778  } while (str[i] >= '0' && str[i] <= '9');
779 
780  // Skip spaces.
781  while (str[i] == ' ' || str[i] == '\t') {
782  ++i;
783  }
784 
785  if (str[i] != 0) {
786  *error = KMP_I18N_STR(IllegalCharacters);
787  return;
788  }
789 
790  if (overflow) {
791  *error = KMP_I18N_STR(ValueTooLarge);
792  *out = (kmp_uint64)-1;
793  return;
794  }
795 
796  *error = NULL;
797  *out = value;
798 } // __kmp_str_to_unit
799 
800 // end of file //