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