blob: 88967e155a18f5553c3f1d9dc02a11e937246a9f [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
Jonathan Peytonde4749b2016-12-14 23:01:24 +00002 * kmp_str.cpp -- String manipulation routines.
Jim Cownie5e8470a2013-09-27 10:38:44 +00003 */
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
Jonathan Peyton30419822017-05-12 18:01:32 +000018#include <stdarg.h> // va_*
19#include <stdio.h> // vsnprintf()
20#include <stdlib.h> // malloc(), realloc()
Jim Cownie5e8470a2013-09-27 10:38:44 +000021
22#include "kmp.h"
23#include "kmp_i18n.h"
24
Jonathan Peyton30419822017-05-12 18:01:32 +000025/* String buffer.
Jim Cownie5e8470a2013-09-27 10:38:44 +000026
Jonathan Peyton30419822017-05-12 18:01:32 +000027 Usage:
Jim Cownie5e8470a2013-09-27 10:38:44 +000028
Jonathan Peyton30419822017-05-12 18:01:32 +000029 // Declare buffer and initialize it.
30 kmp_str_buf_t buffer;
31 __kmp_str_buf_init( & buffer );
Jim Cownie5e8470a2013-09-27 10:38:44 +000032
Jonathan Peyton30419822017-05-12 18:01:32 +000033 // 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);
Jim Cownie5e8470a2013-09-27 10:38:44 +000036
Jonathan Peyton30419822017-05-12 18:01:32 +000037 // 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 );
Jim Cownie5e8470a2013-09-27 10:38:44 +000040
Jonathan Peyton30419822017-05-12 18:01:32 +000041 // Free buffer.
42 __kmp_str_buf_free( & buffer );
Jim Cownie5e8470a2013-09-27 10:38:44 +000043
Jonathan Peyton30419822017-05-12 18:01:32 +000044 // Alternatively, you can detach allocated memory from buffer:
45 __kmp_str_buf_detach( & buffer );
46 return buffer.str; // That memory should be freed eventually.
Jim Cownie5e8470a2013-09-27 10:38:44 +000047
Jonathan Peyton30419822017-05-12 18:01:32 +000048 Notes:
Jim Cownie5e8470a2013-09-27 10:38:44 +000049
Jonathan Peyton30419822017-05-12 18:01:32 +000050 * 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.
Jim Cownie5e8470a2013-09-27 10:38:44 +000058*/
59
60// TODO: __kmp_str_buf_print() can use thread local memory allocator.
61
Jonathan Peyton30419822017-05-12 18:01:32 +000062#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 }
Jim Cownie5e8470a2013-09-27 10:38:44 +000073
Jonathan Peyton30419822017-05-12 18:01:32 +000074void __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);
Jim Cownie5e8470a2013-09-27 10:38:44 +000081} // __kmp_str_buf_clear
82
Jonathan Peyton30419822017-05-12 18:01:32 +000083void __kmp_str_buf_reserve(kmp_str_buf_t *buffer, int size) {
84 KMP_STR_BUF_INVARIANT(buffer);
85 KMP_DEBUG_ASSERT(size >= 0);
Jim Cownie5e8470a2013-09-27 10:38:44 +000086
Jonathan Peyton30419822017-05-12 18:01:32 +000087 if (buffer->size < (unsigned int)size) {
88 // Calculate buffer size.
89 do {
90 buffer->size *= 2;
91 } while (buffer->size < (unsigned int)size);
Jim Cownie5e8470a2013-09-27 10:38:44 +000092
Jonathan Peyton30419822017-05-12 18:01:32 +000093 // 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000105 }; // if
106
Jonathan Peyton30419822017-05-12 18:01:32 +0000107 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000108
Jonathan Peyton30419822017-05-12 18:01:32 +0000109 KMP_DEBUG_ASSERT(buffer->size > 0);
110 KMP_DEBUG_ASSERT(buffer->size >= (unsigned)size);
111 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000112} // __kmp_str_buf_reserve
113
Jonathan Peyton30419822017-05-12 18:01:32 +0000114void __kmp_str_buf_detach(kmp_str_buf_t *buffer) {
115 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000116
Jonathan Peyton30419822017-05-12 18:01:32 +0000117 // 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);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000122 }; // if
Jonathan Peyton30419822017-05-12 18:01:32 +0000123 KMP_MEMCPY_S(buffer->str, buffer->size, buffer->bulk, buffer->used + 1);
124 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000125} // __kmp_str_buf_detach
126
Jonathan Peyton30419822017-05-12 18:01:32 +0000127void __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);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000136} // __kmp_str_buf_free
137
Jonathan Peyton30419822017-05-12 18:01:32 +0000138void __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);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000147} // __kmp_str_buf_cat
148
Jonathan Peyton30419822017-05-12 18:01:32 +0000149void __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
150 va_list args) {
151 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000152
Jonathan Peyton30419822017-05-12 18:01:32 +0000153 for (;;) {
154 int const free = buffer->size - buffer->used;
155 int rc;
156 int size;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000157
Jonathan Peyton30419822017-05-12 18:01:32 +0000158 // 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.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000164
Jonathan Peyton30419822017-05-12 18:01:32 +0000165 Unfortunately, standard va_copy() macro is not available on Windows* OS.
166 However, it seems vsnprintf() does not modify args argument on Windows* OS.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000167*/
168
Jonathan Peyton30419822017-05-12 18:01:32 +0000169#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 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000180
Jonathan Peyton30419822017-05-12 18:01:32 +0000181 // No errors, string has been formatted.
182 if (rc >= 0 && rc < free) {
183 buffer->used += rc;
184 break;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000185 }; // if
186
Jonathan Peyton30419822017-05-12 18:01:32 +0000187 // 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000195
Jonathan Peyton30419822017-05-12 18:01:32 +0000196 // 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
206void __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". */
215void __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]);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000227} // __kmp_str_buf_print_size
228
Jonathan Peyton30419822017-05-12 18:01:32 +0000229void __kmp_str_fname_init(kmp_str_fname_t *fname, char const *path) {
230 fname->path = NULL;
231 fname->dir = NULL;
232 fname->base = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000233
Jonathan Peyton30419822017-05-12 18:01:32 +0000234 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, '\\', '/');
Jim Cownie5e8470a2013-09-27 10:38:44 +0000243 }; // if
Jonathan Peyton30419822017-05-12 18:01:32 +0000244 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000257
258} // kmp_str_fname_init
259
Jonathan Peyton30419822017-05-12 18:01:32 +0000260void __kmp_str_fname_free(kmp_str_fname_t *fname) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000261 __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));
Jim Cownie5e8470a2013-09-27 10:38:44 +0000264} // kmp_str_fname_free
265
Jonathan Peyton30419822017-05-12 18:01:32 +0000266int __kmp_str_fname_match(kmp_str_fname_t const *fname, char const *pattern) {
267 int dir_match = 1;
268 int base_match = 1;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000269
Jonathan Peyton30419822017-05-12 18:01:32 +0000270 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000279
Jonathan Peyton30419822017-05-12 18:01:32 +0000280 return dir_match && base_match;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000281} // __kmp_str_fname_match
282
Jonathan Peyton30419822017-05-12 18:01:32 +0000283kmp_str_loc_t __kmp_str_loc_init(char const *psource, int init_fname) {
284 kmp_str_loc_t loc;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000285
Jonathan Peyton30419822017-05-12 18:01:32 +0000286 loc._bulk = NULL;
287 loc.file = NULL;
288 loc.func = NULL;
289 loc.line = 0;
290 loc.col = 0;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000291
Jonathan Peyton30419822017-05-12 18:01:32 +0000292 if (psource != NULL) {
293 char *str = NULL;
294 char *dummy = NULL;
295 char *line = NULL;
296 char *col = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000297
Jonathan Peyton30419822017-05-12 18:01:32 +0000298 // Copy psource to keep it intact.
299 loc._bulk = __kmp_str_format("%s", psource);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000300
Jonathan Peyton30419822017-05-12 18:01:32 +0000301 // 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);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000308
Jonathan Peyton30419822017-05-12 18:01:32 +0000309 // 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000321 }; // if
322
Jonathan Peyton30419822017-05-12 18:01:32 +0000323 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000324
Jonathan Peyton30419822017-05-12 18:01:32 +0000325 __kmp_str_fname_init(&loc.fname, init_fname ? loc.file : NULL);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000326
Jonathan Peyton30419822017-05-12 18:01:32 +0000327 return loc;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000328} // kmp_str_loc_init
329
Jonathan Peyton30419822017-05-12 18:01:32 +0000330void __kmp_str_loc_free(kmp_str_loc_t *loc) {
331 __kmp_str_fname_free(&loc->fname);
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000332 __kmp_str_free(CCAST(const char **, &(loc->_bulk)));
Jonathan Peyton30419822017-05-12 18:01:32 +0000333 loc->file = NULL;
334 loc->func = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000335} // kmp_str_loc_free
336
Jonathan Peyton30419822017-05-12 18:01:32 +0000337/* 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*. */
341int __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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000352} // __kmp_str_eqf
353
Jonathan Peyton30419822017-05-12 18:01:32 +0000354/* 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:
Jim Cownie5e8470a2013-09-27 10:38:44 +0000359
Jonathan Peyton30419822017-05-12 18:01:32 +0000360 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 );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000367
Jonathan Peyton30419822017-05-12 18:01:32 +0000368 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.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000373
Jonathan Peyton30419822017-05-12 18:01:32 +0000374 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.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000383*/
384
Jonathan Peyton30419822017-05-12 18:01:32 +0000385char *__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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000393
Jonathan Peyton30419822017-05-12 18:01:32 +0000394 // Allocate buffer.
395 buffer = (char *)KMP_INTERNAL_MALLOC(size);
396 if (buffer == NULL) {
397 KMP_FATAL(MemoryAllocFailed);
398 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000399
Jonathan Peyton30419822017-05-12 18:01:32 +0000400 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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000409 }; // if
410
Jonathan Peyton30419822017-05-12 18:01:32 +0000411 // 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000420
Jonathan Peyton30419822017-05-12 18:01:32 +0000421 // 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000427
Jonathan Peyton30419822017-05-12 18:01:32 +0000428 return buffer;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000429} // func __kmp_str_format
430
Jonathan Peyton30419822017-05-12 18:01:32 +0000431void __kmp_str_free(char const **str) {
432 KMP_DEBUG_ASSERT(str != NULL);
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000433 KMP_INTERNAL_FREE(CCAST(char *, *str));
Jonathan Peyton30419822017-05-12 18:01:32 +0000434 *str = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000435} // func __kmp_str_free
436
Jonathan Peyton30419822017-05-12 18:01:32 +0000437/* 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. */
442int __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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000450 }; // if
Jonathan Peyton30419822017-05-12 18:01:32 +0000451 }; // for i
452 return ((len > 0) ? i >= len : (!target[i] && (len || !data[i])));
Jim Cownie5e8470a2013-09-27 10:38:44 +0000453} // __kmp_str_match
454
Jonathan Peyton30419822017-05-12 18:01:32 +0000455int __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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000461} // __kmp_str_match_false
462
Jonathan Peyton30419822017-05-12 18:01:32 +0000463int __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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000469} // __kmp_str_match_true
470
Jonathan Peyton30419822017-05-12 18:01:32 +0000471void __kmp_str_replace(char *str, char search_for, char replace_with) {
472 char *found = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000473
Jonathan Peyton30419822017-05-12 18:01:32 +0000474 found = strchr(str, search_for);
475 while (found) {
476 *found = replace_with;
477 found = strchr(found + 1, search_for);
478 }; // while
Jim Cownie5e8470a2013-09-27 10:38:44 +0000479} // __kmp_str_replace
480
Jonathan Peyton30419822017-05-12 18:01:32 +0000481void __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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000493 }; // if
Jonathan Peyton30419822017-05-12 18:01:32 +0000494 }; // if
495 if (head != NULL) {
496 *head = h;
497 }; // if
498 if (tail != NULL) {
499 *tail = t;
500 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000501} // __kmp_str_split
502
Jonathan Peyton30419822017-05-12 18:01:32 +0000503/* strtok_r() is not available on Windows* OS. This function reimplements
504 strtok_r(). */
505char *__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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000530}; // __kmp_str_token
531
Jonathan Peyton30419822017-05-12 18:01:32 +0000532int __kmp_str_to_int(char const *str, char sentinel) {
533 int result, factor;
534 char const *t;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000535
Jonathan Peyton30419822017-05-12 18:01:32 +0000536 result = 0;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000537
Jonathan Peyton30419822017-05-12 18:01:32 +0000538 for (t = str; *t != '\0'; ++t) {
539 if (*t < '0' || *t > '9')
540 break;
541 result = (result * 10) + (*t - '0');
542 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000543
Jonathan Peyton30419822017-05-12 18:01:32 +0000544 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 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000569
Jonathan Peyton30419822017-05-12 18:01:32 +0000570 if (result > (INT_MAX / factor))
571 result = INT_MAX;
572 else
573 result *= factor;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000574
Jonathan Peyton30419822017-05-12 18:01:32 +0000575 return (*t != 0 ? 0 : result);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000576} // __kmp_str_to_int
577
Jonathan Peyton30419822017-05-12 18:01:32 +0000578/* 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. */
585void __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 ) {
Jim Cownie5e8470a2013-09-27 10:38:44 +0000592
Jonathan Peyton30419822017-05-12 18:01:32 +0000593 size_t value = 0;
594 size_t factor = 0;
595 int overflow = 0;
596 int i = 0;
597 int digit;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000598
Jonathan Peyton30419822017-05-12 18:01:32 +0000599 KMP_DEBUG_ASSERT(str != NULL);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000600
Jonathan Peyton30419822017-05-12 18:01:32 +0000601 // Skip spaces.
602 while (str[i] == ' ' || str[i] == '\t') {
603 ++i;
604 }; // while
Jim Cownie5e8470a2013-09-27 10:38:44 +0000605
Jonathan Peyton30419822017-05-12 18:01:32 +0000606 // 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');
Jim Cownie5e8470a2013-09-27 10:38:44 +0000617
Jonathan Peyton30419822017-05-12 18:01:32 +0000618 // Skip spaces.
619 while (str[i] == ' ' || str[i] == '\t') {
620 ++i;
621 }; // while
Jim Cownie5e8470a2013-09-27 10:38:44 +0000622
Jonathan Peyton30419822017-05-12 18:01:32 +0000623// 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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000650 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000651 ++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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000657
Jonathan Peyton30419822017-05-12 18:01:32 +0000658 if (factor == 0) {
659 factor = dfactor;
660 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000661
Jonathan Peyton30419822017-05-12 18:01:32 +0000662 // Apply factor.
663 overflow = overflow || (value > (KMP_SIZE_T_MAX / factor));
664 value *= factor;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000665
Jonathan Peyton30419822017-05-12 18:01:32 +0000666 // Skip spaces.
667 while (str[i] == ' ' || str[i] == '\t') {
668 ++i;
669 }; // while
Jim Cownie5e8470a2013-09-27 10:38:44 +0000670
Jonathan Peyton30419822017-05-12 18:01:32 +0000671 if (str[i] != 0) {
672 *error = KMP_I18N_STR(IllegalCharacters);
673 return;
674 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000675
Jonathan Peyton30419822017-05-12 18:01:32 +0000676 if (overflow) {
677 *error = KMP_I18N_STR(ValueTooLarge);
678 *out = KMP_SIZE_T_MAX;
679 return;
680 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000681
Jonathan Peyton30419822017-05-12 18:01:32 +0000682 *error = NULL;
683 *out = value;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000684} // __kmp_str_to_size
685
Jonathan Peyton30419822017-05-12 18:01:32 +0000686void __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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000695
Jonathan Peyton30419822017-05-12 18:01:32 +0000696 KMP_DEBUG_ASSERT(str != NULL);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000697
Jonathan Peyton30419822017-05-12 18:01:32 +0000698 // Skip spaces.
699 while (str[i] == ' ' || str[i] == '\t') {
700 ++i;
701 }; // while
Jim Cownie5e8470a2013-09-27 10:38:44 +0000702
Jonathan Peyton30419822017-05-12 18:01:32 +0000703 // 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');
Jim Cownie5e8470a2013-09-27 10:38:44 +0000714
Jonathan Peyton30419822017-05-12 18:01:32 +0000715 // Skip spaces.
716 while (str[i] == ' ' || str[i] == '\t') {
717 ++i;
718 }; // while
Jim Cownie5e8470a2013-09-27 10:38:44 +0000719
Jonathan Peyton30419822017-05-12 18:01:32 +0000720 if (str[i] != 0) {
721 *error = KMP_I18N_STR(IllegalCharacters);
722 return;
723 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000724
Jonathan Peyton30419822017-05-12 18:01:32 +0000725 if (overflow) {
726 *error = KMP_I18N_STR(ValueTooLarge);
727 *out = (kmp_uint64)-1;
728 return;
729 }; // if
Jim Cownie5e8470a2013-09-27 10:38:44 +0000730
Jonathan Peyton30419822017-05-12 18:01:32 +0000731 *error = NULL;
732 *out = value;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000733} // __kmp_str_to_unit
734
Jim Cownie5e8470a2013-09-27 10:38:44 +0000735// end of file //