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 
__kmp_str_buf_clear(kmp_str_buf_t * buffer)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 
__kmp_str_buf_reserve(kmp_str_buf_t * buffer,int size)80 void __kmp_str_buf_reserve(kmp_str_buf_t *buffer, int 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 
__kmp_str_buf_detach(kmp_str_buf_t * buffer)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 
__kmp_str_buf_free(kmp_str_buf_t * buffer)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 
__kmp_str_buf_cat(kmp_str_buf_t * buffer,char const * str,int len)134 void __kmp_str_buf_cat(kmp_str_buf_t *buffer, char const *str, int len) {
135   KMP_STR_BUF_INVARIANT(buffer);
136   KMP_DEBUG_ASSERT(str != NULL);
137   KMP_DEBUG_ASSERT(len >= 0);
138   __kmp_str_buf_reserve(buffer, buffer->used + len + 1);
139   KMP_MEMCPY(buffer->str + buffer->used, str, len);
140   buffer->str[buffer->used + len] = 0;
141   buffer->used += len;
142   KMP_STR_BUF_INVARIANT(buffer);
143 } // __kmp_str_buf_cat
144 
__kmp_str_buf_catbuf(kmp_str_buf_t * dest,const kmp_str_buf_t * src)145 void __kmp_str_buf_catbuf(kmp_str_buf_t *dest, const kmp_str_buf_t *src) {
146   KMP_DEBUG_ASSERT(dest);
147   KMP_DEBUG_ASSERT(src);
148   KMP_STR_BUF_INVARIANT(dest);
149   KMP_STR_BUF_INVARIANT(src);
150   if (!src->str || !src->used)
151     return;
152   __kmp_str_buf_reserve(dest, dest->used + src->used + 1);
153   KMP_MEMCPY(dest->str + dest->used, src->str, src->used);
154   dest->str[dest->used + src->used] = 0;
155   dest->used += src->used;
156   KMP_STR_BUF_INVARIANT(dest);
157 } // __kmp_str_buf_catbuf
158 
159 // Return the number of characters written
__kmp_str_buf_vprint(kmp_str_buf_t * buffer,char const * format,va_list args)160 int __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
161                          va_list args) {
162   int rc;
163   KMP_STR_BUF_INVARIANT(buffer);
164 
165   for (;;) {
166     int const free = buffer->size - buffer->used;
167     int size;
168 
169     // Try to format string.
170     {
171 /* On Linux* OS Intel(R) 64, vsnprintf() modifies args argument, so vsnprintf()
172    crashes if it is called for the second time with the same args. To prevent
173    the crash, we have to pass a fresh intact copy of args to vsnprintf() on each
174    iteration.
175 
176    Unfortunately, standard va_copy() macro is not available on Windows* OS.
177    However, it seems vsnprintf() does not modify args argument on Windows* OS.
178 */
179 
180 #if !KMP_OS_WINDOWS
181       va_list _args;
182       va_copy(_args, args); // Make copy of args.
183 #define args _args // Substitute args with its copy, _args.
184 #endif // KMP_OS_WINDOWS
185       rc = KMP_VSNPRINTF(buffer->str + buffer->used, free, format, args);
186 #if !KMP_OS_WINDOWS
187 #undef args // Remove substitution.
188       va_end(_args);
189 #endif // KMP_OS_WINDOWS
190     }
191 
192     // No errors, string has been formatted.
193     if (rc >= 0 && rc < free) {
194       buffer->used += rc;
195       break;
196     }
197 
198     // Error occurred, buffer is too small.
199     if (rc >= 0) {
200       // C99-conforming implementation of vsnprintf returns required buffer size
201       size = buffer->used + rc + 1;
202     } else {
203       // Older implementations just return -1. Double buffer size.
204       size = buffer->size * 2;
205     }
206 
207     // Enlarge buffer.
208     __kmp_str_buf_reserve(buffer, size);
209 
210     // And try again.
211   }
212 
213   KMP_DEBUG_ASSERT(buffer->size > 0);
214   KMP_STR_BUF_INVARIANT(buffer);
215   return rc;
216 } // __kmp_str_buf_vprint
217 
218 // Return the number of characters written
__kmp_str_buf_print(kmp_str_buf_t * buffer,char const * format,...)219 int __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...) {
220   int rc;
221   va_list args;
222   va_start(args, format);
223   rc = __kmp_str_buf_vprint(buffer, format, args);
224   va_end(args);
225   return rc;
226 } // __kmp_str_buf_print
227 
228 /* The function prints specified size to buffer. Size is expressed using biggest
229    possible unit, for example 1024 is printed as "1k". */
__kmp_str_buf_print_size(kmp_str_buf_t * buf,size_t size)230 void __kmp_str_buf_print_size(kmp_str_buf_t *buf, size_t size) {
231   char const *names[] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y"};
232   int const units = sizeof(names) / sizeof(char const *);
233   int u = 0;
234   if (size > 0) {
235     while ((size % 1024 == 0) && (u + 1 < units)) {
236       size = size / 1024;
237       ++u;
238     }
239   }
240 
241   __kmp_str_buf_print(buf, "%" KMP_SIZE_T_SPEC "%s", size, names[u]);
242 } // __kmp_str_buf_print_size
243 
__kmp_str_fname_init(kmp_str_fname_t * fname,char const * path)244 void __kmp_str_fname_init(kmp_str_fname_t *fname, char const *path) {
245   fname->path = NULL;
246   fname->dir = NULL;
247   fname->base = NULL;
248 
249   if (path != NULL) {
250     char *slash = NULL; // Pointer to the last character of dir.
251     char *base = NULL; // Pointer to the beginning of basename.
252     fname->path = __kmp_str_format("%s", path);
253     // Original code used strdup() function to copy a string, but on Windows* OS
254     // Intel(R) 64 it causes assertion id debug heap, so I had to replace
255     // strdup with __kmp_str_format().
256     if (KMP_OS_WINDOWS) {
257       __kmp_str_replace(fname->path, '\\', '/');
258     }
259     fname->dir = __kmp_str_format("%s", fname->path);
260     slash = strrchr(fname->dir, '/');
261     if (KMP_OS_WINDOWS &&
262         slash == NULL) { // On Windows* OS, if slash not found,
263       char first = TOLOWER(fname->dir[0]); // look for drive.
264       if ('a' <= first && first <= 'z' && fname->dir[1] == ':') {
265         slash = &fname->dir[1];
266       }
267     }
268     base = (slash == NULL ? fname->dir : slash + 1);
269     fname->base = __kmp_str_format("%s", base); // Copy basename
270     *base = 0; // and truncate dir.
271   }
272 
273 } // kmp_str_fname_init
274 
__kmp_str_fname_free(kmp_str_fname_t * fname)275 void __kmp_str_fname_free(kmp_str_fname_t *fname) {
276   __kmp_str_free(&fname->path);
277   __kmp_str_free(&fname->dir);
278   __kmp_str_free(&fname->base);
279 } // kmp_str_fname_free
280 
__kmp_str_fname_match(kmp_str_fname_t const * fname,char const * pattern)281 int __kmp_str_fname_match(kmp_str_fname_t const *fname, char const *pattern) {
282   int dir_match = 1;
283   int base_match = 1;
284 
285   if (pattern != NULL) {
286     kmp_str_fname_t ptrn;
287     __kmp_str_fname_init(&ptrn, pattern);
288     dir_match = strcmp(ptrn.dir, "*/") == 0 ||
289                 (fname->dir != NULL && __kmp_str_eqf(fname->dir, ptrn.dir));
290     base_match = strcmp(ptrn.base, "*") == 0 ||
291                  (fname->base != NULL && __kmp_str_eqf(fname->base, ptrn.base));
292     __kmp_str_fname_free(&ptrn);
293   }
294 
295   return dir_match && base_match;
296 } // __kmp_str_fname_match
297 
298 // Get the numeric fields from source location string.
299 // For clang these fields are Line/Col of the start of the construct.
300 // For icc these are LineBegin/LineEnd of the construct.
301 // Function is fast as it does not duplicate string (which involves memory
302 // allocation), and parses the string in place.
__kmp_str_loc_numbers(char const * Psource,int * LineBeg,int * LineEndOrCol)303 void __kmp_str_loc_numbers(char const *Psource, int *LineBeg,
304                            int *LineEndOrCol) {
305   char *Str;
306   KMP_DEBUG_ASSERT(LineBeg);
307   KMP_DEBUG_ASSERT(LineEndOrCol);
308   // Parse Psource string ";file;func;line;line_end_or_column;;" to get
309   // numbers only, skipping string fields "file" and "func".
310 
311   // Find 1-st semicolon.
312   KMP_DEBUG_ASSERT(Psource);
313 #ifdef __cplusplus
314   Str = strchr(CCAST(char *, Psource), ';');
315 #else
316   Str = strchr(Psource, ';');
317 #endif
318   // Check returned pointer to see if the format of Psource is broken.
319   if (Str) {
320     // Find 2-nd semicolon.
321     Str = strchr(Str + 1, ';');
322   }
323   if (Str) {
324     // Find 3-rd semicolon.
325     Str = strchr(Str + 1, ';');
326   }
327   if (Str) {
328     // Read begin line number.
329     *LineBeg = atoi(Str + 1);
330     // Find 4-th semicolon.
331     Str = strchr(Str + 1, ';');
332   } else {
333     // Broken format of input string, cannot read the number.
334     *LineBeg = 0;
335   }
336   if (Str) {
337     // Read end line or column number.
338     *LineEndOrCol = atoi(Str + 1);
339   } else {
340     // Broken format of input string, cannot read the number.
341     *LineEndOrCol = 0;
342   }
343 }
344 
__kmp_str_loc_init(char const * psource,bool init_fname)345 kmp_str_loc_t __kmp_str_loc_init(char const *psource, bool init_fname) {
346   kmp_str_loc_t loc;
347 
348   loc._bulk = NULL;
349   loc.file = NULL;
350   loc.func = NULL;
351   loc.line = 0;
352   loc.col = 0;
353 
354   if (psource != NULL) {
355     char *str = NULL;
356     char *dummy = NULL;
357     char *line = NULL;
358     char *col = NULL;
359 
360     // Copy psource to keep it intact.
361     loc._bulk = __kmp_str_format("%s", psource);
362 
363     // Parse psource string: ";file;func;line;col;;"
364     str = loc._bulk;
365     __kmp_str_split(str, ';', &dummy, &str);
366     __kmp_str_split(str, ';', &loc.file, &str);
367     __kmp_str_split(str, ';', &loc.func, &str);
368     __kmp_str_split(str, ';', &line, &str);
369     __kmp_str_split(str, ';', &col, &str);
370 
371     // Convert line and col into numberic values.
372     if (line != NULL) {
373       loc.line = atoi(line);
374       if (loc.line < 0) {
375         loc.line = 0;
376       }
377     }
378     if (col != NULL) {
379       loc.col = atoi(col);
380       if (loc.col < 0) {
381         loc.col = 0;
382       }
383     }
384   }
385 
386   __kmp_str_fname_init(&loc.fname, init_fname ? loc.file : NULL);
387 
388   return loc;
389 } // kmp_str_loc_init
390 
__kmp_str_loc_free(kmp_str_loc_t * loc)391 void __kmp_str_loc_free(kmp_str_loc_t *loc) {
392   __kmp_str_fname_free(&loc->fname);
393   __kmp_str_free(&(loc->_bulk));
394   loc->file = NULL;
395   loc->func = NULL;
396 } // kmp_str_loc_free
397 
398 /* This function is intended to compare file names. On Windows* OS file names
399    are case-insensitive, so functions performs case-insensitive comparison. On
400    Linux* OS it performs case-sensitive comparison. Note: The function returns
401    *true* if strings are *equal*. */
__kmp_str_eqf(char const * lhs,char const * rhs)402 int __kmp_str_eqf( // True, if strings are equal, false otherwise.
403     char const *lhs, // First string.
404     char const *rhs // Second string.
405     ) {
406   int result;
407 #if KMP_OS_WINDOWS
408   result = (_stricmp(lhs, rhs) == 0);
409 #else
410   result = (strcmp(lhs, rhs) == 0);
411 #endif
412   return result;
413 } // __kmp_str_eqf
414 
415 /* This function is like sprintf, but it *allocates* new buffer, which must be
416    freed eventually by __kmp_str_free(). The function is very convenient for
417    constructing strings, it successfully replaces strdup(), strcat(), it frees
418    programmer from buffer allocations and helps to avoid buffer overflows.
419    Examples:
420 
421    str = __kmp_str_format("%s", orig); //strdup() doesn't care about buffer size
422    __kmp_str_free( & str );
423    str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), doesn't care
424                                                    // about buffer size.
425    __kmp_str_free( & str );
426    str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
427    __kmp_str_free( & str );
428 
429    Performance note:
430    This function allocates memory with malloc() calls, so do not call it from
431    performance-critical code. In performance-critical code consider using
432    kmp_str_buf_t instead, since it uses stack-allocated buffer for short
433    strings.
434 
435    Why does this function use malloc()?
436    1. __kmp_allocate() returns cache-aligned memory allocated with malloc().
437       There are no reasons in using __kmp_allocate() for strings due to extra
438       overhead while cache-aligned memory is not necessary.
439    2. __kmp_thread_malloc() cannot be used because it requires pointer to thread
440       structure. We need to perform string operations during library startup
441       (for example, in __kmp_register_library_startup()) when no thread
442       structures are allocated yet.
443    So standard malloc() is the only available option.
444 */
445 
__kmp_str_format(char const * format,...)446 char *__kmp_str_format( // Allocated string.
447     char const *format, // Format string.
448     ... // Other parameters.
449     ) {
450   va_list args;
451   int size = 512;
452   char *buffer = NULL;
453   int rc;
454 
455   // Allocate buffer.
456   buffer = (char *)KMP_INTERNAL_MALLOC(size);
457   if (buffer == NULL) {
458     KMP_FATAL(MemoryAllocFailed);
459   }
460 
461   for (;;) {
462     // Try to format string.
463     va_start(args, format);
464     rc = KMP_VSNPRINTF(buffer, size, format, args);
465     va_end(args);
466 
467     // No errors, string has been formatted.
468     if (rc >= 0 && rc < size) {
469       break;
470     }
471 
472     // Error occurred, buffer is too small.
473     if (rc >= 0) {
474       // C99-conforming implementation of vsnprintf returns required buffer
475       // size.
476       size = rc + 1;
477     } else {
478       // Older implementations just return -1.
479       size = size * 2;
480     }
481 
482     // Enlarge buffer and try again.
483     buffer = (char *)KMP_INTERNAL_REALLOC(buffer, size);
484     if (buffer == NULL) {
485       KMP_FATAL(MemoryAllocFailed);
486     }
487   }
488 
489   return buffer;
490 } // func __kmp_str_format
491 
__kmp_str_free(char ** str)492 void __kmp_str_free(char **str) {
493   KMP_DEBUG_ASSERT(str != NULL);
494   KMP_INTERNAL_FREE(*str);
495   *str = NULL;
496 } // func __kmp_str_free
497 
498 /* If len is zero, returns true iff target and data have exact case-insensitive
499    match. If len is negative, returns true iff target is a case-insensitive
500    substring of data. If len is positive, returns true iff target is a
501    case-insensitive substring of data or vice versa, and neither is shorter than
502    len. */
__kmp_str_match(char const * target,int len,char const * data)503 int __kmp_str_match(char const *target, int len, char const *data) {
504   int i;
505   if (target == NULL || data == NULL) {
506     return FALSE;
507   }
508   for (i = 0; target[i] && data[i]; ++i) {
509     if (TOLOWER(target[i]) != TOLOWER(data[i])) {
510       return FALSE;
511     }
512   }
513   return ((len > 0) ? i >= len : (!target[i] && (len || !data[i])));
514 } // __kmp_str_match
515 
__kmp_str_match_false(char const * data)516 int __kmp_str_match_false(char const *data) {
517   int result =
518       __kmp_str_match("false", 1, data) || __kmp_str_match("off", 2, data) ||
519       __kmp_str_match("0", 1, data) || __kmp_str_match(".false.", 2, data) ||
520       __kmp_str_match(".f.", 2, data) || __kmp_str_match("no", 1, data) ||
521       __kmp_str_match("disabled", 0, data);
522   return result;
523 } // __kmp_str_match_false
524 
__kmp_str_match_true(char const * data)525 int __kmp_str_match_true(char const *data) {
526   int result =
527       __kmp_str_match("true", 1, data) || __kmp_str_match("on", 2, data) ||
528       __kmp_str_match("1", 1, data) || __kmp_str_match(".true.", 2, data) ||
529       __kmp_str_match(".t.", 2, data) || __kmp_str_match("yes", 1, data) ||
530       __kmp_str_match("enabled", 0, data);
531   return result;
532 } // __kmp_str_match_true
533 
__kmp_str_replace(char * str,char search_for,char replace_with)534 void __kmp_str_replace(char *str, char search_for, char replace_with) {
535   char *found = NULL;
536 
537   found = strchr(str, search_for);
538   while (found) {
539     *found = replace_with;
540     found = strchr(found + 1, search_for);
541   }
542 } // __kmp_str_replace
543 
__kmp_str_split(char * str,char delim,char ** head,char ** tail)544 void __kmp_str_split(char *str, // I: String to split.
545                      char delim, // I: Character to split on.
546                      char **head, // O: Pointer to head (may be NULL).
547                      char **tail // O: Pointer to tail (may be NULL).
548                      ) {
549   char *h = str;
550   char *t = NULL;
551   if (str != NULL) {
552     char *ptr = strchr(str, delim);
553     if (ptr != NULL) {
554       *ptr = 0;
555       t = ptr + 1;
556     }
557   }
558   if (head != NULL) {
559     *head = h;
560   }
561   if (tail != NULL) {
562     *tail = t;
563   }
564 } // __kmp_str_split
565 
566 /* strtok_r() is not available on Windows* OS. This function reimplements
567    strtok_r(). */
__kmp_str_token(char * str,char const * delim,char ** buf)568 char *__kmp_str_token(
569     char *str, // String to split into tokens. Note: String *is* modified!
570     char const *delim, // Delimiters.
571     char **buf // Internal buffer.
572     ) {
573   char *token = NULL;
574 #if KMP_OS_WINDOWS
575   // On Windows* OS there is no strtok_r() function. Let us implement it.
576   if (str != NULL) {
577     *buf = str; // First call, initialize buf.
578   }
579   *buf += strspn(*buf, delim); // Skip leading delimiters.
580   if (**buf != 0) { // Rest of the string is not yet empty.
581     token = *buf; // Use it as result.
582     *buf += strcspn(*buf, delim); // Skip non-delimiters.
583     if (**buf != 0) { // Rest of the string is not yet empty.
584       **buf = 0; // Terminate token here.
585       *buf += 1; // Advance buf to start with the next token next time.
586     }
587   }
588 #else
589   // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
590   token = strtok_r(str, delim, buf);
591 #endif
592   return token;
593 } // __kmp_str_token
594 
__kmp_str_to_int(char const * str,char sentinel)595 int __kmp_str_to_int(char const *str, char sentinel) {
596   int result, factor;
597   char const *t;
598 
599   result = 0;
600 
601   for (t = str; *t != '\0'; ++t) {
602     if (*t < '0' || *t > '9')
603       break;
604     result = (result * 10) + (*t - '0');
605   }
606 
607   switch (*t) {
608   case '\0': /* the current default for no suffix is bytes */
609     factor = 1;
610     break;
611   case 'b':
612   case 'B': /* bytes */
613     ++t;
614     factor = 1;
615     break;
616   case 'k':
617   case 'K': /* kilo-bytes */
618     ++t;
619     factor = 1024;
620     break;
621   case 'm':
622   case 'M': /* mega-bytes */
623     ++t;
624     factor = (1024 * 1024);
625     break;
626   default:
627     if (*t != sentinel)
628       return (-1);
629     t = "";
630     factor = 1;
631   }
632 
633   if (result > (INT_MAX / factor))
634     result = INT_MAX;
635   else
636     result *= factor;
637 
638   return (*t != 0 ? 0 : result);
639 } // __kmp_str_to_int
640 
641 /* The routine parses input string. It is expected it is a unsigned integer with
642    optional unit. Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb"
643    or "m" for megabytes, ..., "yb" or "y" for yottabytes. :-) Unit name is
644    case-insensitive. The routine returns 0 if everything is ok, or error code:
645    -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
646    value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown
647    unit *size is set to zero. */
__kmp_str_to_size(char const * str,size_t * out,size_t dfactor,char const ** error)648 void __kmp_str_to_size( // R: Error code.
649     char const *str, // I: String of characters, unsigned number and unit ("b",
650     // "kb", etc).
651     size_t *out, // O: Parsed number.
652     size_t dfactor, // I: The factor if none of the letters specified.
653     char const **error // O: Null if everything is ok, error message otherwise.
654     ) {
655 
656   size_t value = 0;
657   size_t factor = 0;
658   int overflow = 0;
659   int i = 0;
660   int digit;
661 
662   KMP_DEBUG_ASSERT(str != NULL);
663 
664   // Skip spaces.
665   while (str[i] == ' ' || str[i] == '\t') {
666     ++i;
667   }
668 
669   // Parse number.
670   if (str[i] < '0' || str[i] > '9') {
671     *error = KMP_I18N_STR(NotANumber);
672     return;
673   }
674   do {
675     digit = str[i] - '0';
676     overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
677     value = (value * 10) + digit;
678     ++i;
679   } while (str[i] >= '0' && str[i] <= '9');
680 
681   // Skip spaces.
682   while (str[i] == ' ' || str[i] == '\t') {
683     ++i;
684   }
685 
686 // Parse unit.
687 #define _case(ch, exp)                                                         \
688   case ch:                                                                     \
689   case ch - ('a' - 'A'): {                                                     \
690     size_t shift = (exp)*10;                                                   \
691     ++i;                                                                       \
692     if (shift < sizeof(size_t) * 8) {                                          \
693       factor = (size_t)(1) << shift;                                           \
694     } else {                                                                   \
695       overflow = 1;                                                            \
696     }                                                                          \
697   } break;
698   switch (str[i]) {
699     _case('k', 1); // Kilo
700     _case('m', 2); // Mega
701     _case('g', 3); // Giga
702     _case('t', 4); // Tera
703     _case('p', 5); // Peta
704     _case('e', 6); // Exa
705     _case('z', 7); // Zetta
706     _case('y', 8); // Yotta
707     // Oops. No more units...
708   }
709 #undef _case
710   if (str[i] == 'b' || str[i] == 'B') { // Skip optional "b".
711     if (factor == 0) {
712       factor = 1;
713     }
714     ++i;
715   }
716   if (!(str[i] == ' ' || str[i] == '\t' || str[i] == 0)) { // Bad unit
717     *error = KMP_I18N_STR(BadUnit);
718     return;
719   }
720 
721   if (factor == 0) {
722     factor = dfactor;
723   }
724 
725   // Apply factor.
726   overflow = overflow || (value > (KMP_SIZE_T_MAX / factor));
727   value *= factor;
728 
729   // Skip spaces.
730   while (str[i] == ' ' || str[i] == '\t') {
731     ++i;
732   }
733 
734   if (str[i] != 0) {
735     *error = KMP_I18N_STR(IllegalCharacters);
736     return;
737   }
738 
739   if (overflow) {
740     *error = KMP_I18N_STR(ValueTooLarge);
741     *out = KMP_SIZE_T_MAX;
742     return;
743   }
744 
745   *error = NULL;
746   *out = value;
747 } // __kmp_str_to_size
748 
__kmp_str_to_uint(char const * str,kmp_uint64 * out,char const ** error)749 void __kmp_str_to_uint( // R: Error code.
750     char const *str, // I: String of characters, unsigned number.
751     kmp_uint64 *out, // O: Parsed number.
752     char const **error // O: Null if everything is ok, error message otherwise.
753     ) {
754   size_t value = 0;
755   int overflow = 0;
756   int i = 0;
757   int digit;
758 
759   KMP_DEBUG_ASSERT(str != NULL);
760 
761   // Skip spaces.
762   while (str[i] == ' ' || str[i] == '\t') {
763     ++i;
764   }
765 
766   // Parse number.
767   if (str[i] < '0' || str[i] > '9') {
768     *error = KMP_I18N_STR(NotANumber);
769     return;
770   }
771   do {
772     digit = str[i] - '0';
773     overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
774     value = (value * 10) + digit;
775     ++i;
776   } while (str[i] >= '0' && str[i] <= '9');
777 
778   // Skip spaces.
779   while (str[i] == ' ' || str[i] == '\t') {
780     ++i;
781   }
782 
783   if (str[i] != 0) {
784     *error = KMP_I18N_STR(IllegalCharacters);
785     return;
786   }
787 
788   if (overflow) {
789     *error = KMP_I18N_STR(ValueTooLarge);
790     *out = (kmp_uint64)-1;
791     return;
792   }
793 
794   *error = NULL;
795   *out = value;
796 } // __kmp_str_to_unit
797 
798 // end of file //
799