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