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