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 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 assertion 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 = (char)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 // Get the numeric fields from source location string.
300 // For clang these fields are Line/Col of the start of the construct.
301 // For icc these are LineBegin/LineEnd of the construct.
302 // Function is fast as it does not duplicate string (which involves memory
303 // allocation), and parses the string in place.
304 void __kmp_str_loc_numbers(char const *Psource, int *LineBeg,
305  int *LineEndOrCol) {
306  char *Str;
307  KMP_DEBUG_ASSERT(LineBeg);
308  KMP_DEBUG_ASSERT(LineEndOrCol);
309  // Parse Psource string ";file;func;line;line_end_or_column;;" to get
310  // numbers only, skipping string fields "file" and "func".
311 
312  // Find 1-st semicolon.
313  KMP_DEBUG_ASSERT(Psource);
314 #ifdef __cplusplus
315  Str = strchr(CCAST(char *, Psource), ';');
316 #else
317  Str = strchr(Psource, ';');
318 #endif
319  // Check returned pointer to see if the format of Psource is broken.
320  if (Str) {
321  // Find 2-nd semicolon.
322  Str = strchr(Str + 1, ';');
323  }
324  if (Str) {
325  // Find 3-rd semicolon.
326  Str = strchr(Str + 1, ';');
327  }
328  if (Str) {
329  // Read begin line number.
330  *LineBeg = atoi(Str + 1);
331  // Find 4-th semicolon.
332  Str = strchr(Str + 1, ';');
333  } else {
334  // Broken format of input string, cannot read the number.
335  *LineBeg = 0;
336  }
337  if (Str) {
338  // Read end line or column number.
339  *LineEndOrCol = atoi(Str + 1);
340  } else {
341  // Broken format of input string, cannot read the number.
342  *LineEndOrCol = 0;
343  }
344 }
345 
346 kmp_str_loc_t __kmp_str_loc_init(char const *psource, bool init_fname) {
347  kmp_str_loc_t loc;
348 
349  loc._bulk = NULL;
350  loc.file = NULL;
351  loc.func = NULL;
352  loc.line = 0;
353  loc.col = 0;
354 
355  if (psource != NULL) {
356  char *str = NULL;
357  char *dummy = NULL;
358  char *line = NULL;
359  char *col = NULL;
360 
361  // Copy psource to keep it intact.
362  loc._bulk = __kmp_str_format("%s", psource);
363 
364  // Parse psource string: ";file;func;line;col;;"
365  str = loc._bulk;
366  __kmp_str_split(str, ';', &dummy, &str);
367  __kmp_str_split(str, ';', &loc.file, &str);
368  __kmp_str_split(str, ';', &loc.func, &str);
369  __kmp_str_split(str, ';', &line, &str);
370  __kmp_str_split(str, ';', &col, &str);
371 
372  // Convert line and col into numberic values.
373  if (line != NULL) {
374  loc.line = atoi(line);
375  if (loc.line < 0) {
376  loc.line = 0;
377  }
378  }
379  if (col != NULL) {
380  loc.col = atoi(col);
381  if (loc.col < 0) {
382  loc.col = 0;
383  }
384  }
385  }
386 
387  __kmp_str_fname_init(&loc.fname, init_fname ? loc.file : NULL);
388 
389  return loc;
390 } // kmp_str_loc_init
391 
392 void __kmp_str_loc_free(kmp_str_loc_t *loc) {
393  __kmp_str_fname_free(&loc->fname);
394  __kmp_str_free(&(loc->_bulk));
395  loc->file = NULL;
396  loc->func = NULL;
397 } // kmp_str_loc_free
398 
399 /* This function is intended to compare file names. On Windows* OS file names
400  are case-insensitive, so functions performs case-insensitive comparison. On
401  Linux* OS it performs case-sensitive comparison. Note: The function returns
402  *true* if strings are *equal*. */
403 int __kmp_str_eqf( // True, if strings are equal, false otherwise.
404  char const *lhs, // First string.
405  char const *rhs // Second string.
406  ) {
407  int result;
408 #if KMP_OS_WINDOWS
409  result = (_stricmp(lhs, rhs) == 0);
410 #else
411  result = (strcmp(lhs, rhs) == 0);
412 #endif
413  return result;
414 } // __kmp_str_eqf
415 
416 /* This function is like sprintf, but it *allocates* new buffer, which must be
417  freed eventually by __kmp_str_free(). The function is very convenient for
418  constructing strings, it successfully replaces strdup(), strcat(), it frees
419  programmer from buffer allocations and helps to avoid buffer overflows.
420  Examples:
421 
422  str = __kmp_str_format("%s", orig); //strdup() doesn't care about buffer size
423  __kmp_str_free( & str );
424  str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), doesn't care
425  // about buffer size.
426  __kmp_str_free( & str );
427  str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
428  __kmp_str_free( & str );
429 
430  Performance note:
431  This function allocates memory with malloc() calls, so do not call it from
432  performance-critical code. In performance-critical code consider using
433  kmp_str_buf_t instead, since it uses stack-allocated buffer for short
434  strings.
435 
436  Why does this function use malloc()?
437  1. __kmp_allocate() returns cache-aligned memory allocated with malloc().
438  There are no reasons in using __kmp_allocate() for strings due to extra
439  overhead while cache-aligned memory is not necessary.
440  2. __kmp_thread_malloc() cannot be used because it requires pointer to thread
441  structure. We need to perform string operations during library startup
442  (for example, in __kmp_register_library_startup()) when no thread
443  structures are allocated yet.
444  So standard malloc() is the only available option.
445 */
446 
447 char *__kmp_str_format( // Allocated string.
448  char const *format, // Format string.
449  ... // Other parameters.
450  ) {
451  va_list args;
452  int size = 512;
453  char *buffer = NULL;
454  int rc;
455 
456  // Allocate buffer.
457  buffer = (char *)KMP_INTERNAL_MALLOC(size);
458  if (buffer == NULL) {
459  KMP_FATAL(MemoryAllocFailed);
460  }
461 
462  for (;;) {
463  // Try to format string.
464  va_start(args, format);
465  rc = KMP_VSNPRINTF(buffer, size, format, args);
466  va_end(args);
467 
468  // No errors, string has been formatted.
469  if (rc >= 0 && rc < size) {
470  break;
471  }
472 
473  // Error occurred, buffer is too small.
474  if (rc >= 0) {
475  // C99-conforming implementation of vsnprintf returns required buffer
476  // size.
477  size = rc + 1;
478  } else {
479  // Older implementations just return -1.
480  size = size * 2;
481  }
482 
483  // Enlarge buffer and try again.
484  buffer = (char *)KMP_INTERNAL_REALLOC(buffer, size);
485  if (buffer == NULL) {
486  KMP_FATAL(MemoryAllocFailed);
487  }
488  }
489 
490  return buffer;
491 } // func __kmp_str_format
492 
493 void __kmp_str_free(char **str) {
494  KMP_DEBUG_ASSERT(str != NULL);
495  KMP_INTERNAL_FREE(*str);
496  *str = NULL;
497 } // func __kmp_str_free
498 
499 /* If len is zero, returns true iff target and data have exact case-insensitive
500  match. If len is negative, returns true iff target is a case-insensitive
501  substring of data. If len is positive, returns true iff target is a
502  case-insensitive substring of data or vice versa, and neither is shorter than
503  len. */
504 int __kmp_str_match(char const *target, int len, char const *data) {
505  int i;
506  if (target == NULL || data == NULL) {
507  return FALSE;
508  }
509  for (i = 0; target[i] && data[i]; ++i) {
510  if (TOLOWER(target[i]) != TOLOWER(data[i])) {
511  return FALSE;
512  }
513  }
514  return ((len > 0) ? i >= len : (!target[i] && (len || !data[i])));
515 } // __kmp_str_match
516 
517 int __kmp_str_match_false(char const *data) {
518  int result =
519  __kmp_str_match("false", 1, data) || __kmp_str_match("off", 2, data) ||
520  __kmp_str_match("0", 1, data) || __kmp_str_match(".false.", 2, data) ||
521  __kmp_str_match(".f.", 2, data) || __kmp_str_match("no", 1, data) ||
522  __kmp_str_match("disabled", 0, data);
523  return result;
524 } // __kmp_str_match_false
525 
526 int __kmp_str_match_true(char const *data) {
527  int result =
528  __kmp_str_match("true", 1, data) || __kmp_str_match("on", 2, data) ||
529  __kmp_str_match("1", 1, data) || __kmp_str_match(".true.", 2, data) ||
530  __kmp_str_match(".t.", 2, data) || __kmp_str_match("yes", 1, data) ||
531  __kmp_str_match("enabled", 0, data);
532  return result;
533 } // __kmp_str_match_true
534 
535 void __kmp_str_replace(char *str, char search_for, char replace_with) {
536  char *found = NULL;
537 
538  found = strchr(str, search_for);
539  while (found) {
540  *found = replace_with;
541  found = strchr(found + 1, search_for);
542  }
543 } // __kmp_str_replace
544 
545 void __kmp_str_split(char *str, // I: String to split.
546  char delim, // I: Character to split on.
547  char **head, // O: Pointer to head (may be NULL).
548  char **tail // O: Pointer to tail (may be NULL).
549  ) {
550  char *h = str;
551  char *t = NULL;
552  if (str != NULL) {
553  char *ptr = strchr(str, delim);
554  if (ptr != NULL) {
555  *ptr = 0;
556  t = ptr + 1;
557  }
558  }
559  if (head != NULL) {
560  *head = h;
561  }
562  if (tail != NULL) {
563  *tail = t;
564  }
565 } // __kmp_str_split
566 
567 /* strtok_r() is not available on Windows* OS. This function reimplements
568  strtok_r(). */
569 char *__kmp_str_token(
570  char *str, // String to split into tokens. Note: String *is* modified!
571  char const *delim, // Delimiters.
572  char **buf // Internal buffer.
573  ) {
574  char *token = NULL;
575 #if KMP_OS_WINDOWS
576  // On Windows* OS there is no strtok_r() function. Let us implement it.
577  if (str != NULL) {
578  *buf = str; // First call, initialize buf.
579  }
580  *buf += strspn(*buf, delim); // Skip leading delimiters.
581  if (**buf != 0) { // Rest of the string is not yet empty.
582  token = *buf; // Use it as result.
583  *buf += strcspn(*buf, delim); // Skip non-delimiters.
584  if (**buf != 0) { // Rest of the string is not yet empty.
585  **buf = 0; // Terminate token here.
586  *buf += 1; // Advance buf to start with the next token next time.
587  }
588  }
589 #else
590  // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
591  token = strtok_r(str, delim, buf);
592 #endif
593  return token;
594 } // __kmp_str_token
595 
596 int __kmp_str_to_int(char const *str, char sentinel) {
597  int result, factor;
598  char const *t;
599 
600  result = 0;
601 
602  for (t = str; *t != '\0'; ++t) {
603  if (*t < '0' || *t > '9')
604  break;
605  result = (result * 10) + (*t - '0');
606  }
607 
608  switch (*t) {
609  case '\0': /* the current default for no suffix is bytes */
610  factor = 1;
611  break;
612  case 'b':
613  case 'B': /* bytes */
614  ++t;
615  factor = 1;
616  break;
617  case 'k':
618  case 'K': /* kilo-bytes */
619  ++t;
620  factor = 1024;
621  break;
622  case 'm':
623  case 'M': /* mega-bytes */
624  ++t;
625  factor = (1024 * 1024);
626  break;
627  default:
628  if (*t != sentinel)
629  return (-1);
630  t = "";
631  factor = 1;
632  }
633 
634  if (result > (INT_MAX / factor))
635  result = INT_MAX;
636  else
637  result *= factor;
638 
639  return (*t != 0 ? 0 : result);
640 } // __kmp_str_to_int
641 
642 /* The routine parses input string. It is expected it is a unsigned integer with
643  optional unit. Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb"
644  or "m" for megabytes, ..., "yb" or "y" for yottabytes. :-) Unit name is
645  case-insensitive. The routine returns 0 if everything is ok, or error code:
646  -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
647  value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown
648  unit *size is set to zero. */
649 void __kmp_str_to_size( // R: Error code.
650  char const *str, // I: String of characters, unsigned number and unit ("b",
651  // "kb", etc).
652  size_t *out, // O: Parsed number.
653  size_t dfactor, // I: The factor if none of the letters specified.
654  char const **error // O: Null if everything is ok, error message otherwise.
655  ) {
656 
657  size_t value = 0;
658  size_t factor = 0;
659  int overflow = 0;
660  int i = 0;
661  int digit;
662 
663  KMP_DEBUG_ASSERT(str != NULL);
664 
665  // Skip spaces.
666  while (str[i] == ' ' || str[i] == '\t') {
667  ++i;
668  }
669 
670  // Parse number.
671  if (str[i] < '0' || str[i] > '9') {
672  *error = KMP_I18N_STR(NotANumber);
673  return;
674  }
675  do {
676  digit = str[i] - '0';
677  overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
678  value = (value * 10) + digit;
679  ++i;
680  } while (str[i] >= '0' && str[i] <= '9');
681 
682  // Skip spaces.
683  while (str[i] == ' ' || str[i] == '\t') {
684  ++i;
685  }
686 
687 // Parse unit.
688 #define _case(ch, exp) \
689  case ch: \
690  case ch - ('a' - 'A'): { \
691  size_t shift = (exp)*10; \
692  ++i; \
693  if (shift < sizeof(size_t) * 8) { \
694  factor = (size_t)(1) << shift; \
695  } else { \
696  overflow = 1; \
697  } \
698  } break;
699  switch (str[i]) {
700  _case('k', 1); // Kilo
701  _case('m', 2); // Mega
702  _case('g', 3); // Giga
703  _case('t', 4); // Tera
704  _case('p', 5); // Peta
705  _case('e', 6); // Exa
706  _case('z', 7); // Zetta
707  _case('y', 8); // Yotta
708  // Oops. No more units...
709  }
710 #undef _case
711  if (str[i] == 'b' || str[i] == 'B') { // Skip optional "b".
712  if (factor == 0) {
713  factor = 1;
714  }
715  ++i;
716  }
717  if (!(str[i] == ' ' || str[i] == '\t' || str[i] == 0)) { // Bad unit
718  *error = KMP_I18N_STR(BadUnit);
719  return;
720  }
721 
722  if (factor == 0) {
723  factor = dfactor;
724  }
725 
726  // Apply factor.
727  overflow = overflow || (value > (KMP_SIZE_T_MAX / factor));
728  value *= factor;
729 
730  // Skip spaces.
731  while (str[i] == ' ' || str[i] == '\t') {
732  ++i;
733  }
734 
735  if (str[i] != 0) {
736  *error = KMP_I18N_STR(IllegalCharacters);
737  return;
738  }
739 
740  if (overflow) {
741  *error = KMP_I18N_STR(ValueTooLarge);
742  *out = KMP_SIZE_T_MAX;
743  return;
744  }
745 
746  *error = NULL;
747  *out = value;
748 } // __kmp_str_to_size
749 
750 void __kmp_str_to_uint( // R: Error code.
751  char const *str, // I: String of characters, unsigned number.
752  kmp_uint64 *out, // O: Parsed number.
753  char const **error // O: Null if everything is ok, error message otherwise.
754  ) {
755  size_t value = 0;
756  int overflow = 0;
757  int i = 0;
758  int digit;
759 
760  KMP_DEBUG_ASSERT(str != NULL);
761 
762  // Skip spaces.
763  while (str[i] == ' ' || str[i] == '\t') {
764  ++i;
765  }
766 
767  // Parse number.
768  if (str[i] < '0' || str[i] > '9') {
769  *error = KMP_I18N_STR(NotANumber);
770  return;
771  }
772  do {
773  digit = str[i] - '0';
774  overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
775  value = (value * 10) + digit;
776  ++i;
777  } while (str[i] >= '0' && str[i] <= '9');
778 
779  // Skip spaces.
780  while (str[i] == ' ' || str[i] == '\t') {
781  ++i;
782  }
783 
784  if (str[i] != 0) {
785  *error = KMP_I18N_STR(IllegalCharacters);
786  return;
787  }
788 
789  if (overflow) {
790  *error = KMP_I18N_STR(ValueTooLarge);
791  *out = (kmp_uint64)-1;
792  return;
793  }
794 
795  *error = NULL;
796  *out = value;
797 } // __kmp_str_to_unit
798 
799 // end of file //