blob: 75fd1e25f3472b4cbe372b7721baf6a646745f2c [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
Jim Cownie5e8470a2013-09-27 10:38:44 +00005//===----------------------------------------------------------------------===//
6//
Chandler Carruth57b08b02019-01-19 10:56:40 +00007// 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
Jim Cownie5e8470a2013-09-27 10:38:44 +000010//
11//===----------------------------------------------------------------------===//
12
Jim Cownie5e8470a2013-09-27 10:38:44 +000013#include "kmp_str.h"
14
Jonathan Peyton30419822017-05-12 18:01:32 +000015#include <stdarg.h> // va_*
16#include <stdio.h> // vsnprintf()
17#include <stdlib.h> // malloc(), realloc()
Jim Cownie5e8470a2013-09-27 10:38:44 +000018
19#include "kmp.h"
20#include "kmp_i18n.h"
21
Jonathan Peyton30419822017-05-12 18:01:32 +000022/* String buffer.
Jim Cownie5e8470a2013-09-27 10:38:44 +000023
Jonathan Peyton30419822017-05-12 18:01:32 +000024 Usage:
Jim Cownie5e8470a2013-09-27 10:38:44 +000025
Jonathan Peyton30419822017-05-12 18:01:32 +000026 // Declare buffer and initialize it.
27 kmp_str_buf_t buffer;
28 __kmp_str_buf_init( & buffer );
Jim Cownie5e8470a2013-09-27 10:38:44 +000029
Jonathan Peyton30419822017-05-12 18:01:32 +000030 // 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);
Jim Cownie5e8470a2013-09-27 10:38:44 +000033
Jonathan Peyton30419822017-05-12 18:01:32 +000034 // 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 );
Jim Cownie5e8470a2013-09-27 10:38:44 +000037
Jonathan Peyton30419822017-05-12 18:01:32 +000038 // Free buffer.
39 __kmp_str_buf_free( & buffer );
Jim Cownie5e8470a2013-09-27 10:38:44 +000040
Jonathan Peyton30419822017-05-12 18:01:32 +000041 // Alternatively, you can detach allocated memory from buffer:
42 __kmp_str_buf_detach( & buffer );
43 return buffer.str; // That memory should be freed eventually.
Jim Cownie5e8470a2013-09-27 10:38:44 +000044
Jonathan Peyton30419822017-05-12 18:01:32 +000045 Notes:
Jim Cownie5e8470a2013-09-27 10:38:44 +000046
Jonathan Peyton30419822017-05-12 18:01:32 +000047 * 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.
Jim Cownie5e8470a2013-09-27 10:38:44 +000055*/
56
57// TODO: __kmp_str_buf_print() can use thread local memory allocator.
58
Jonathan Peyton30419822017-05-12 18:01:32 +000059#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 }
Jim Cownie5e8470a2013-09-27 10:38:44 +000070
Jonathan Peyton30419822017-05-12 18:01:32 +000071void __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;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +000076 }
Jonathan Peyton30419822017-05-12 18:01:32 +000077 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +000078} // __kmp_str_buf_clear
79
Jonathan Peyton30419822017-05-12 18:01:32 +000080void __kmp_str_buf_reserve(kmp_str_buf_t *buffer, int size) {
81 KMP_STR_BUF_INVARIANT(buffer);
82 KMP_DEBUG_ASSERT(size >= 0);
Jim Cownie5e8470a2013-09-27 10:38:44 +000083
Jonathan Peyton30419822017-05-12 18:01:32 +000084 if (buffer->size < (unsigned int)size) {
85 // Calculate buffer size.
86 do {
87 buffer->size *= 2;
88 } while (buffer->size < (unsigned int)size);
Jim Cownie5e8470a2013-09-27 10:38:44 +000089
Jonathan Peyton30419822017-05-12 18:01:32 +000090 // 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);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +000095 }
Jonathan Peyton30419822017-05-12 18:01:32 +000096 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);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000101 }
102 }
103 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000104
Jonathan Peyton30419822017-05-12 18:01:32 +0000105 KMP_DEBUG_ASSERT(buffer->size > 0);
106 KMP_DEBUG_ASSERT(buffer->size >= (unsigned)size);
107 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000108} // __kmp_str_buf_reserve
109
Jonathan Peyton30419822017-05-12 18:01:32 +0000110void __kmp_str_buf_detach(kmp_str_buf_t *buffer) {
111 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000112
Jonathan Peyton30419822017-05-12 18:01:32 +0000113 // 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);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000118 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000119 KMP_MEMCPY_S(buffer->str, buffer->size, buffer->bulk, buffer->used + 1);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000120 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000121} // __kmp_str_buf_detach
122
Jonathan Peyton30419822017-05-12 18:01:32 +0000123void __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);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000127 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000128 buffer->str = buffer->bulk;
129 buffer->size = sizeof(buffer->bulk);
130 buffer->used = 0;
131 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000132} // __kmp_str_buf_free
133
Jonathan Peyton30419822017-05-12 18:01:32 +0000134void __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);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000143} // __kmp_str_buf_cat
144
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000145void __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
160int __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
161 va_list args) {
162 int rc;
Jonathan Peyton30419822017-05-12 18:01:32 +0000163 KMP_STR_BUF_INVARIANT(buffer);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000164
Jonathan Peyton30419822017-05-12 18:01:32 +0000165 for (;;) {
166 int const free = buffer->size - buffer->used;
Jonathan Peyton30419822017-05-12 18:01:32 +0000167 int size;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000168
Jonathan Peyton30419822017-05-12 18:01:32 +0000169 // 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.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000175
Jonathan Peyton30419822017-05-12 18:01:32 +0000176 Unfortunately, standard va_copy() macro is not available on Windows* OS.
177 However, it seems vsnprintf() does not modify args argument on Windows* OS.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000178*/
179
Jonathan Peyton30419822017-05-12 18:01:32 +0000180#if !KMP_OS_WINDOWS
181 va_list _args;
Jonathan Peyton04477082017-08-19 23:53:36 +0000182 va_copy(_args, args); // Make copy of args.
Jonathan Peyton30419822017-05-12 18:01:32 +0000183#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 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000191
Jonathan Peyton30419822017-05-12 18:01:32 +0000192 // No errors, string has been formatted.
193 if (rc >= 0 && rc < free) {
194 buffer->used += rc;
195 break;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000196 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000197
Jonathan Peyton30419822017-05-12 18:01:32 +0000198 // 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;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000205 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000206
Jonathan Peyton30419822017-05-12 18:01:32 +0000207 // Enlarge buffer.
208 __kmp_str_buf_reserve(buffer, size);
209
210 // And try again.
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000211 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000212
213 KMP_DEBUG_ASSERT(buffer->size > 0);
214 KMP_STR_BUF_INVARIANT(buffer);
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000215 return rc;
Jonathan Peyton30419822017-05-12 18:01:32 +0000216} // __kmp_str_buf_vprint
217
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000218// Return the number of characters written
219int __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...) {
220 int rc;
Jonathan Peyton30419822017-05-12 18:01:32 +0000221 va_list args;
222 va_start(args, format);
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000223 rc = __kmp_str_buf_vprint(buffer, format, args);
Jonathan Peyton30419822017-05-12 18:01:32 +0000224 va_end(args);
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000225 return rc;
Jonathan Peyton30419822017-05-12 18:01:32 +0000226} // __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". */
230void __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;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000238 }
239 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000240
241 __kmp_str_buf_print(buf, "%" KMP_SIZE_T_SPEC "%s", size, names[u]);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000242} // __kmp_str_buf_print_size
243
Jonathan Peyton30419822017-05-12 18:01:32 +0000244void __kmp_str_fname_init(kmp_str_fname_t *fname, char const *path) {
245 fname->path = NULL;
246 fname->dir = NULL;
247 fname->base = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000248
Jonathan Peyton30419822017-05-12 18:01:32 +0000249 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
Kelvin Lied5fe642020-01-03 22:03:42 -0500254 // Intel(R) 64 it causes assertion id debug heap, so I had to replace
Jonathan Peyton30419822017-05-12 18:01:32 +0000255 // strdup with __kmp_str_format().
256 if (KMP_OS_WINDOWS) {
257 __kmp_str_replace(fname->path, '\\', '/');
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000258 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000259 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];
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000266 }
267 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000268 base = (slash == NULL ? fname->dir : slash + 1);
269 fname->base = __kmp_str_format("%s", base); // Copy basename
270 *base = 0; // and truncate dir.
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000271 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000272
273} // kmp_str_fname_init
274
Jonathan Peyton30419822017-05-12 18:01:32 +0000275void __kmp_str_fname_free(kmp_str_fname_t *fname) {
Jonas Hahnfeldaeb40ad2017-11-09 15:52:25 +0000276 __kmp_str_free(&fname->path);
277 __kmp_str_free(&fname->dir);
278 __kmp_str_free(&fname->base);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000279} // kmp_str_fname_free
280
Jonathan Peyton30419822017-05-12 18:01:32 +0000281int __kmp_str_fname_match(kmp_str_fname_t const *fname, char const *pattern) {
282 int dir_match = 1;
283 int base_match = 1;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000284
Jonathan Peyton30419822017-05-12 18:01:32 +0000285 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);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000293 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000294
Jonathan Peyton30419822017-05-12 18:01:32 +0000295 return dir_match && base_match;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000296} // __kmp_str_fname_match
297
Jonathan Peyton30419822017-05-12 18:01:32 +0000298kmp_str_loc_t __kmp_str_loc_init(char const *psource, int init_fname) {
299 kmp_str_loc_t loc;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000300
Jonathan Peyton30419822017-05-12 18:01:32 +0000301 loc._bulk = NULL;
302 loc.file = NULL;
303 loc.func = NULL;
304 loc.line = 0;
305 loc.col = 0;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000306
Jonathan Peyton30419822017-05-12 18:01:32 +0000307 if (psource != NULL) {
308 char *str = NULL;
309 char *dummy = NULL;
310 char *line = NULL;
311 char *col = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000312
Jonathan Peyton30419822017-05-12 18:01:32 +0000313 // Copy psource to keep it intact.
314 loc._bulk = __kmp_str_format("%s", psource);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000315
Jonathan Peyton30419822017-05-12 18:01:32 +0000316 // Parse psource string: ";file;func;line;col;;"
317 str = loc._bulk;
318 __kmp_str_split(str, ';', &dummy, &str);
319 __kmp_str_split(str, ';', &loc.file, &str);
320 __kmp_str_split(str, ';', &loc.func, &str);
321 __kmp_str_split(str, ';', &line, &str);
322 __kmp_str_split(str, ';', &col, &str);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000323
Jonathan Peyton30419822017-05-12 18:01:32 +0000324 // Convert line and col into numberic values.
325 if (line != NULL) {
326 loc.line = atoi(line);
327 if (loc.line < 0) {
328 loc.line = 0;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000329 }
330 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000331 if (col != NULL) {
332 loc.col = atoi(col);
333 if (loc.col < 0) {
334 loc.col = 0;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000335 }
336 }
337 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000338
Jonathan Peyton30419822017-05-12 18:01:32 +0000339 __kmp_str_fname_init(&loc.fname, init_fname ? loc.file : NULL);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000340
Jonathan Peyton30419822017-05-12 18:01:32 +0000341 return loc;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000342} // kmp_str_loc_init
343
Jonathan Peyton30419822017-05-12 18:01:32 +0000344void __kmp_str_loc_free(kmp_str_loc_t *loc) {
345 __kmp_str_fname_free(&loc->fname);
Jonas Hahnfeldaeb40ad2017-11-09 15:52:25 +0000346 __kmp_str_free(&(loc->_bulk));
Jonathan Peyton30419822017-05-12 18:01:32 +0000347 loc->file = NULL;
348 loc->func = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000349} // kmp_str_loc_free
350
Jonathan Peyton30419822017-05-12 18:01:32 +0000351/* This function is intended to compare file names. On Windows* OS file names
352 are case-insensitive, so functions performs case-insensitive comparison. On
353 Linux* OS it performs case-sensitive comparison. Note: The function returns
354 *true* if strings are *equal*. */
355int __kmp_str_eqf( // True, if strings are equal, false otherwise.
356 char const *lhs, // First string.
357 char const *rhs // Second string.
358 ) {
359 int result;
360#if KMP_OS_WINDOWS
361 result = (_stricmp(lhs, rhs) == 0);
362#else
363 result = (strcmp(lhs, rhs) == 0);
364#endif
365 return result;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000366} // __kmp_str_eqf
367
Jonathan Peyton30419822017-05-12 18:01:32 +0000368/* This function is like sprintf, but it *allocates* new buffer, which must be
369 freed eventually by __kmp_str_free(). The function is very convenient for
370 constructing strings, it successfully replaces strdup(), strcat(), it frees
371 programmer from buffer allocations and helps to avoid buffer overflows.
372 Examples:
Jim Cownie5e8470a2013-09-27 10:38:44 +0000373
Jonathan Peyton30419822017-05-12 18:01:32 +0000374 str = __kmp_str_format("%s", orig); //strdup() doesn't care about buffer size
375 __kmp_str_free( & str );
376 str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), doesn't care
377 // about buffer size.
378 __kmp_str_free( & str );
379 str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
380 __kmp_str_free( & str );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000381
Jonathan Peyton30419822017-05-12 18:01:32 +0000382 Performance note:
383 This function allocates memory with malloc() calls, so do not call it from
384 performance-critical code. In performance-critical code consider using
385 kmp_str_buf_t instead, since it uses stack-allocated buffer for short
386 strings.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000387
Jonathan Peyton30419822017-05-12 18:01:32 +0000388 Why does this function use malloc()?
389 1. __kmp_allocate() returns cache-aligned memory allocated with malloc().
390 There are no reasons in using __kmp_allocate() for strings due to extra
391 overhead while cache-aligned memory is not necessary.
392 2. __kmp_thread_malloc() cannot be used because it requires pointer to thread
393 structure. We need to perform string operations during library startup
394 (for example, in __kmp_register_library_startup()) when no thread
395 structures are allocated yet.
396 So standard malloc() is the only available option.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000397*/
398
Jonathan Peyton30419822017-05-12 18:01:32 +0000399char *__kmp_str_format( // Allocated string.
400 char const *format, // Format string.
401 ... // Other parameters.
402 ) {
403 va_list args;
404 int size = 512;
405 char *buffer = NULL;
406 int rc;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000407
Jonathan Peyton30419822017-05-12 18:01:32 +0000408 // Allocate buffer.
409 buffer = (char *)KMP_INTERNAL_MALLOC(size);
410 if (buffer == NULL) {
411 KMP_FATAL(MemoryAllocFailed);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000412 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000413
Jonathan Peyton30419822017-05-12 18:01:32 +0000414 for (;;) {
415 // Try to format string.
416 va_start(args, format);
417 rc = KMP_VSNPRINTF(buffer, size, format, args);
418 va_end(args);
419
420 // No errors, string has been formatted.
421 if (rc >= 0 && rc < size) {
422 break;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000423 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000424
Jonathan Peyton30419822017-05-12 18:01:32 +0000425 // Error occurred, buffer is too small.
426 if (rc >= 0) {
427 // C99-conforming implementation of vsnprintf returns required buffer
428 // size.
429 size = rc + 1;
430 } else {
431 // Older implementations just return -1.
432 size = size * 2;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000433 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000434
Jonathan Peyton30419822017-05-12 18:01:32 +0000435 // Enlarge buffer and try again.
436 buffer = (char *)KMP_INTERNAL_REALLOC(buffer, size);
437 if (buffer == NULL) {
438 KMP_FATAL(MemoryAllocFailed);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000439 }
440 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000441
Jonathan Peyton30419822017-05-12 18:01:32 +0000442 return buffer;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000443} // func __kmp_str_format
444
Jonas Hahnfeldaeb40ad2017-11-09 15:52:25 +0000445void __kmp_str_free(char **str) {
Jonathan Peyton30419822017-05-12 18:01:32 +0000446 KMP_DEBUG_ASSERT(str != NULL);
Jonas Hahnfeldaeb40ad2017-11-09 15:52:25 +0000447 KMP_INTERNAL_FREE(*str);
Jonathan Peyton30419822017-05-12 18:01:32 +0000448 *str = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000449} // func __kmp_str_free
450
Jonathan Peyton30419822017-05-12 18:01:32 +0000451/* If len is zero, returns true iff target and data have exact case-insensitive
452 match. If len is negative, returns true iff target is a case-insensitive
453 substring of data. If len is positive, returns true iff target is a
454 case-insensitive substring of data or vice versa, and neither is shorter than
455 len. */
456int __kmp_str_match(char const *target, int len, char const *data) {
457 int i;
458 if (target == NULL || data == NULL) {
459 return FALSE;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000460 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000461 for (i = 0; target[i] && data[i]; ++i) {
462 if (TOLOWER(target[i]) != TOLOWER(data[i])) {
463 return FALSE;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000464 }
465 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000466 return ((len > 0) ? i >= len : (!target[i] && (len || !data[i])));
Jim Cownie5e8470a2013-09-27 10:38:44 +0000467} // __kmp_str_match
468
Jonathan Peyton30419822017-05-12 18:01:32 +0000469int __kmp_str_match_false(char const *data) {
470 int result =
471 __kmp_str_match("false", 1, data) || __kmp_str_match("off", 2, data) ||
472 __kmp_str_match("0", 1, data) || __kmp_str_match(".false.", 2, data) ||
Jonathan Peyton60eec6f2018-09-26 20:19:44 +0000473 __kmp_str_match(".f.", 2, data) || __kmp_str_match("no", 1, data) ||
474 __kmp_str_match("disabled", 0, data);
Jonathan Peyton30419822017-05-12 18:01:32 +0000475 return result;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000476} // __kmp_str_match_false
477
Jonathan Peyton30419822017-05-12 18:01:32 +0000478int __kmp_str_match_true(char const *data) {
479 int result =
480 __kmp_str_match("true", 1, data) || __kmp_str_match("on", 2, data) ||
481 __kmp_str_match("1", 1, data) || __kmp_str_match(".true.", 2, data) ||
Jonathan Peyton60eec6f2018-09-26 20:19:44 +0000482 __kmp_str_match(".t.", 2, data) || __kmp_str_match("yes", 1, data) ||
483 __kmp_str_match("enabled", 0, data);
Jonathan Peyton30419822017-05-12 18:01:32 +0000484 return result;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000485} // __kmp_str_match_true
486
Jonathan Peyton30419822017-05-12 18:01:32 +0000487void __kmp_str_replace(char *str, char search_for, char replace_with) {
488 char *found = NULL;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000489
Jonathan Peyton30419822017-05-12 18:01:32 +0000490 found = strchr(str, search_for);
491 while (found) {
492 *found = replace_with;
493 found = strchr(found + 1, search_for);
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000494 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000495} // __kmp_str_replace
496
Jonathan Peyton30419822017-05-12 18:01:32 +0000497void __kmp_str_split(char *str, // I: String to split.
498 char delim, // I: Character to split on.
499 char **head, // O: Pointer to head (may be NULL).
500 char **tail // O: Pointer to tail (may be NULL).
501 ) {
502 char *h = str;
503 char *t = NULL;
504 if (str != NULL) {
505 char *ptr = strchr(str, delim);
506 if (ptr != NULL) {
507 *ptr = 0;
508 t = ptr + 1;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000509 }
510 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000511 if (head != NULL) {
512 *head = h;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000513 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000514 if (tail != NULL) {
515 *tail = t;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000516 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000517} // __kmp_str_split
518
Jonathan Peyton30419822017-05-12 18:01:32 +0000519/* strtok_r() is not available on Windows* OS. This function reimplements
520 strtok_r(). */
521char *__kmp_str_token(
522 char *str, // String to split into tokens. Note: String *is* modified!
523 char const *delim, // Delimiters.
524 char **buf // Internal buffer.
525 ) {
526 char *token = NULL;
527#if KMP_OS_WINDOWS
528 // On Windows* OS there is no strtok_r() function. Let us implement it.
529 if (str != NULL) {
530 *buf = str; // First call, initialize buf.
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000531 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000532 *buf += strspn(*buf, delim); // Skip leading delimiters.
533 if (**buf != 0) { // Rest of the string is not yet empty.
534 token = *buf; // Use it as result.
535 *buf += strcspn(*buf, delim); // Skip non-delimiters.
536 if (**buf != 0) { // Rest of the string is not yet empty.
537 **buf = 0; // Terminate token here.
538 *buf += 1; // Advance buf to start with the next token next time.
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000539 }
540 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000541#else
542 // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
543 token = strtok_r(str, delim, buf);
544#endif
545 return token;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000546} // __kmp_str_token
Jim Cownie5e8470a2013-09-27 10:38:44 +0000547
Jonathan Peyton30419822017-05-12 18:01:32 +0000548int __kmp_str_to_int(char const *str, char sentinel) {
549 int result, factor;
550 char const *t;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000551
Jonathan Peyton30419822017-05-12 18:01:32 +0000552 result = 0;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000553
Jonathan Peyton30419822017-05-12 18:01:32 +0000554 for (t = str; *t != '\0'; ++t) {
555 if (*t < '0' || *t > '9')
556 break;
557 result = (result * 10) + (*t - '0');
558 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000559
Jonathan Peyton30419822017-05-12 18:01:32 +0000560 switch (*t) {
561 case '\0': /* the current default for no suffix is bytes */
562 factor = 1;
563 break;
564 case 'b':
565 case 'B': /* bytes */
566 ++t;
567 factor = 1;
568 break;
569 case 'k':
570 case 'K': /* kilo-bytes */
571 ++t;
572 factor = 1024;
573 break;
574 case 'm':
575 case 'M': /* mega-bytes */
576 ++t;
577 factor = (1024 * 1024);
578 break;
579 default:
580 if (*t != sentinel)
581 return (-1);
582 t = "";
583 factor = 1;
584 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000585
Jonathan Peyton30419822017-05-12 18:01:32 +0000586 if (result > (INT_MAX / factor))
587 result = INT_MAX;
588 else
589 result *= factor;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000590
Jonathan Peyton30419822017-05-12 18:01:32 +0000591 return (*t != 0 ? 0 : result);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000592} // __kmp_str_to_int
593
Jonathan Peyton30419822017-05-12 18:01:32 +0000594/* The routine parses input string. It is expected it is a unsigned integer with
595 optional unit. Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb"
596 or "m" for megabytes, ..., "yb" or "y" for yottabytes. :-) Unit name is
597 case-insensitive. The routine returns 0 if everything is ok, or error code:
598 -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
599 value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown
600 unit *size is set to zero. */
601void __kmp_str_to_size( // R: Error code.
602 char const *str, // I: String of characters, unsigned number and unit ("b",
603 // "kb", etc).
604 size_t *out, // O: Parsed number.
605 size_t dfactor, // I: The factor if none of the letters specified.
606 char const **error // O: Null if everything is ok, error message otherwise.
607 ) {
Jim Cownie5e8470a2013-09-27 10:38:44 +0000608
Jonathan Peyton30419822017-05-12 18:01:32 +0000609 size_t value = 0;
610 size_t factor = 0;
611 int overflow = 0;
612 int i = 0;
613 int digit;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000614
Jonathan Peyton30419822017-05-12 18:01:32 +0000615 KMP_DEBUG_ASSERT(str != NULL);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000616
Jonathan Peyton30419822017-05-12 18:01:32 +0000617 // Skip spaces.
618 while (str[i] == ' ' || str[i] == '\t') {
619 ++i;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000620 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000621
Jonathan Peyton30419822017-05-12 18:01:32 +0000622 // Parse number.
623 if (str[i] < '0' || str[i] > '9') {
624 *error = KMP_I18N_STR(NotANumber);
625 return;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000626 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000627 do {
628 digit = str[i] - '0';
629 overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
630 value = (value * 10) + digit;
631 ++i;
632 } while (str[i] >= '0' && str[i] <= '9');
Jim Cownie5e8470a2013-09-27 10:38:44 +0000633
Jonathan Peyton30419822017-05-12 18:01:32 +0000634 // Skip spaces.
635 while (str[i] == ' ' || str[i] == '\t') {
636 ++i;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000637 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000638
Jonathan Peyton30419822017-05-12 18:01:32 +0000639// Parse unit.
640#define _case(ch, exp) \
641 case ch: \
642 case ch - ('a' - 'A'): { \
643 size_t shift = (exp)*10; \
644 ++i; \
645 if (shift < sizeof(size_t) * 8) { \
646 factor = (size_t)(1) << shift; \
647 } else { \
648 overflow = 1; \
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000649 } \
Jonathan Peyton30419822017-05-12 18:01:32 +0000650 } break;
651 switch (str[i]) {
652 _case('k', 1); // Kilo
653 _case('m', 2); // Mega
654 _case('g', 3); // Giga
655 _case('t', 4); // Tera
656 _case('p', 5); // Peta
657 _case('e', 6); // Exa
658 _case('z', 7); // Zetta
659 _case('y', 8); // Yotta
660 // Oops. No more units...
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000661 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000662#undef _case
663 if (str[i] == 'b' || str[i] == 'B') { // Skip optional "b".
664 if (factor == 0) {
665 factor = 1;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000666 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000667 ++i;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000668 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000669 if (!(str[i] == ' ' || str[i] == '\t' || str[i] == 0)) { // Bad unit
670 *error = KMP_I18N_STR(BadUnit);
671 return;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000672 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000673
Jonathan Peyton30419822017-05-12 18:01:32 +0000674 if (factor == 0) {
675 factor = dfactor;
676 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000677
Jonathan Peyton30419822017-05-12 18:01:32 +0000678 // Apply factor.
679 overflow = overflow || (value > (KMP_SIZE_T_MAX / factor));
680 value *= factor;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000681
Jonathan Peyton30419822017-05-12 18:01:32 +0000682 // Skip spaces.
683 while (str[i] == ' ' || str[i] == '\t') {
684 ++i;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000685 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000686
Jonathan Peyton30419822017-05-12 18:01:32 +0000687 if (str[i] != 0) {
688 *error = KMP_I18N_STR(IllegalCharacters);
689 return;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000690 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000691
Jonathan Peyton30419822017-05-12 18:01:32 +0000692 if (overflow) {
693 *error = KMP_I18N_STR(ValueTooLarge);
694 *out = KMP_SIZE_T_MAX;
695 return;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000696 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000697
Jonathan Peyton30419822017-05-12 18:01:32 +0000698 *error = NULL;
699 *out = value;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000700} // __kmp_str_to_size
701
Jonathan Peyton30419822017-05-12 18:01:32 +0000702void __kmp_str_to_uint( // R: Error code.
703 char const *str, // I: String of characters, unsigned number.
704 kmp_uint64 *out, // O: Parsed number.
705 char const **error // O: Null if everything is ok, error message otherwise.
706 ) {
707 size_t value = 0;
708 int overflow = 0;
709 int i = 0;
710 int digit;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000711
Jonathan Peyton30419822017-05-12 18:01:32 +0000712 KMP_DEBUG_ASSERT(str != NULL);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000713
Jonathan Peyton30419822017-05-12 18:01:32 +0000714 // Skip spaces.
715 while (str[i] == ' ' || str[i] == '\t') {
716 ++i;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000717 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000718
Jonathan Peyton30419822017-05-12 18:01:32 +0000719 // Parse number.
720 if (str[i] < '0' || str[i] > '9') {
721 *error = KMP_I18N_STR(NotANumber);
722 return;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000723 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000724 do {
725 digit = str[i] - '0';
726 overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
727 value = (value * 10) + digit;
728 ++i;
729 } while (str[i] >= '0' && str[i] <= '9');
Jim Cownie5e8470a2013-09-27 10:38:44 +0000730
Jonathan Peyton30419822017-05-12 18:01:32 +0000731 // Skip spaces.
732 while (str[i] == ' ' || str[i] == '\t') {
733 ++i;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000734 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000735
Jonathan Peyton30419822017-05-12 18:01:32 +0000736 if (str[i] != 0) {
737 *error = KMP_I18N_STR(IllegalCharacters);
738 return;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000739 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000740
Jonathan Peyton30419822017-05-12 18:01:32 +0000741 if (overflow) {
742 *error = KMP_I18N_STR(ValueTooLarge);
743 *out = (kmp_uint64)-1;
744 return;
Jonathan Peytonbd3a7632017-09-27 20:36:27 +0000745 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000746
Jonathan Peyton30419822017-05-12 18:01:32 +0000747 *error = NULL;
748 *out = value;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000749} // __kmp_str_to_unit
750
Jim Cownie5e8470a2013-09-27 10:38:44 +0000751// end of file //