17cc577a4SJonathan Peyton /*
2de4749b7SJonathan Peyton * kmp_str.cpp -- String manipulation routines.
37cc577a4SJonathan Peyton */
47cc577a4SJonathan Peyton
57cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
67cc577a4SJonathan Peyton //
757b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
857b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
957b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
107cc577a4SJonathan Peyton //
117cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
127cc577a4SJonathan Peyton
137cc577a4SJonathan Peyton #include "kmp_str.h"
147cc577a4SJonathan Peyton
157cc577a4SJonathan Peyton #include <stdarg.h> // va_*
167cc577a4SJonathan Peyton #include <stdio.h> // vsnprintf()
177cc577a4SJonathan Peyton #include <stdlib.h> // malloc(), realloc()
187cc577a4SJonathan Peyton
197cc577a4SJonathan Peyton #include "kmp.h"
207cc577a4SJonathan Peyton #include "kmp_i18n.h"
217cc577a4SJonathan Peyton
223041982dSJonathan Peyton /* String buffer.
237cc577a4SJonathan Peyton
247cc577a4SJonathan Peyton Usage:
257cc577a4SJonathan Peyton
267cc577a4SJonathan Peyton // Declare buffer and initialize it.
277cc577a4SJonathan Peyton kmp_str_buf_t buffer;
287cc577a4SJonathan Peyton __kmp_str_buf_init( & buffer );
297cc577a4SJonathan Peyton
307cc577a4SJonathan Peyton // Print to buffer.
317cc577a4SJonathan Peyton __kmp_str_buf_print(& buffer, "Error in file \"%s\" line %d\n", "foo.c", 12);
327cc577a4SJonathan Peyton __kmp_str_buf_print(& buffer, " <%s>\n", line);
337cc577a4SJonathan Peyton
343041982dSJonathan Peyton // Use buffer contents. buffer.str is a pointer to data, buffer.used is a
353041982dSJonathan Peyton // number of printed characters (not including terminating zero).
367cc577a4SJonathan Peyton write( fd, buffer.str, buffer.used );
377cc577a4SJonathan Peyton
387cc577a4SJonathan Peyton // Free buffer.
397cc577a4SJonathan Peyton __kmp_str_buf_free( & buffer );
407cc577a4SJonathan Peyton
417cc577a4SJonathan Peyton // Alternatively, you can detach allocated memory from buffer:
427cc577a4SJonathan Peyton __kmp_str_buf_detach( & buffer );
437cc577a4SJonathan Peyton return buffer.str; // That memory should be freed eventually.
447cc577a4SJonathan Peyton
457cc577a4SJonathan Peyton Notes:
467cc577a4SJonathan Peyton
473041982dSJonathan Peyton * Buffer users may use buffer.str and buffer.used. Users should not change
483041982dSJonathan Peyton any fields of buffer directly.
493041982dSJonathan Peyton * buffer.str is never NULL. If buffer is empty, buffer.str points to empty
503041982dSJonathan Peyton string ("").
513041982dSJonathan Peyton * For performance reasons, buffer uses stack memory (buffer.bulk) first. If
523041982dSJonathan Peyton stack memory is exhausted, buffer allocates memory on heap by malloc(), and
533041982dSJonathan Peyton reallocates it by realloc() as amount of used memory grows.
547cc577a4SJonathan Peyton * Buffer doubles amount of allocated memory each time it is exhausted.
557cc577a4SJonathan Peyton */
567cc577a4SJonathan Peyton
577cc577a4SJonathan Peyton // TODO: __kmp_str_buf_print() can use thread local memory allocator.
587cc577a4SJonathan Peyton
597cc577a4SJonathan Peyton #define KMP_STR_BUF_INVARIANT(b) \
607cc577a4SJonathan Peyton { \
617cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((b)->str != NULL); \
627cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((b)->size >= sizeof((b)->bulk)); \
637cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((b)->size % sizeof((b)->bulk) == 0); \
647cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((unsigned)(b)->used < (b)->size); \
653041982dSJonathan Peyton KMP_DEBUG_ASSERT( \
663041982dSJonathan Peyton (b)->size == sizeof((b)->bulk) ? (b)->str == &(b)->bulk[0] : 1); \
673041982dSJonathan Peyton KMP_DEBUG_ASSERT((b)->size > sizeof((b)->bulk) ? (b)->str != &(b)->bulk[0] \
683041982dSJonathan Peyton : 1); \
697cc577a4SJonathan Peyton }
707cc577a4SJonathan Peyton
__kmp_str_buf_clear(kmp_str_buf_t * buffer)713041982dSJonathan Peyton void __kmp_str_buf_clear(kmp_str_buf_t *buffer) {
727cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
737cc577a4SJonathan Peyton if (buffer->used > 0) {
747cc577a4SJonathan Peyton buffer->used = 0;
757cc577a4SJonathan Peyton buffer->str[0] = 0;
76bd3a7633SJonathan Peyton }
777cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
787cc577a4SJonathan Peyton } // __kmp_str_buf_clear
797cc577a4SJonathan Peyton
__kmp_str_buf_reserve(kmp_str_buf_t * buffer,size_t size)806b316febSTerry Wilmarth void __kmp_str_buf_reserve(kmp_str_buf_t *buffer, size_t size) {
817cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
827cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(size >= 0);
837cc577a4SJonathan Peyton
847cc577a4SJonathan Peyton if (buffer->size < (unsigned int)size) {
857cc577a4SJonathan Peyton // Calculate buffer size.
867cc577a4SJonathan Peyton do {
877cc577a4SJonathan Peyton buffer->size *= 2;
887cc577a4SJonathan Peyton } while (buffer->size < (unsigned int)size);
897cc577a4SJonathan Peyton
907cc577a4SJonathan Peyton // Enlarge buffer.
917cc577a4SJonathan Peyton if (buffer->str == &buffer->bulk[0]) {
927cc577a4SJonathan Peyton buffer->str = (char *)KMP_INTERNAL_MALLOC(buffer->size);
937cc577a4SJonathan Peyton if (buffer->str == NULL) {
947cc577a4SJonathan Peyton KMP_FATAL(MemoryAllocFailed);
95bd3a7633SJonathan Peyton }
967cc577a4SJonathan Peyton KMP_MEMCPY_S(buffer->str, buffer->size, buffer->bulk, buffer->used + 1);
977cc577a4SJonathan Peyton } else {
987cc577a4SJonathan Peyton buffer->str = (char *)KMP_INTERNAL_REALLOC(buffer->str, buffer->size);
997cc577a4SJonathan Peyton if (buffer->str == NULL) {
1007cc577a4SJonathan Peyton KMP_FATAL(MemoryAllocFailed);
101bd3a7633SJonathan Peyton }
102bd3a7633SJonathan Peyton }
103bd3a7633SJonathan Peyton }
1047cc577a4SJonathan Peyton
1057cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(buffer->size > 0);
1067cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(buffer->size >= (unsigned)size);
1077cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
1087cc577a4SJonathan Peyton } // __kmp_str_buf_reserve
1097cc577a4SJonathan Peyton
__kmp_str_buf_detach(kmp_str_buf_t * buffer)1103041982dSJonathan Peyton void __kmp_str_buf_detach(kmp_str_buf_t *buffer) {
1117cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
1127cc577a4SJonathan Peyton
1137cc577a4SJonathan Peyton // If internal bulk is used, allocate memory and copy it.
1147cc577a4SJonathan Peyton if (buffer->size <= sizeof(buffer->bulk)) {
1157cc577a4SJonathan Peyton buffer->str = (char *)KMP_INTERNAL_MALLOC(buffer->size);
1167cc577a4SJonathan Peyton if (buffer->str == NULL) {
1177cc577a4SJonathan Peyton KMP_FATAL(MemoryAllocFailed);
118bd3a7633SJonathan Peyton }
1197cc577a4SJonathan Peyton KMP_MEMCPY_S(buffer->str, buffer->size, buffer->bulk, buffer->used + 1);
120bd3a7633SJonathan Peyton }
1217cc577a4SJonathan Peyton } // __kmp_str_buf_detach
1227cc577a4SJonathan Peyton
__kmp_str_buf_free(kmp_str_buf_t * buffer)1233041982dSJonathan Peyton void __kmp_str_buf_free(kmp_str_buf_t *buffer) {
1247cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
1257cc577a4SJonathan Peyton if (buffer->size > sizeof(buffer->bulk)) {
1267cc577a4SJonathan Peyton KMP_INTERNAL_FREE(buffer->str);
127bd3a7633SJonathan Peyton }
1287cc577a4SJonathan Peyton buffer->str = buffer->bulk;
1297cc577a4SJonathan Peyton buffer->size = sizeof(buffer->bulk);
1307cc577a4SJonathan Peyton buffer->used = 0;
1317cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
1327cc577a4SJonathan Peyton } // __kmp_str_buf_free
1337cc577a4SJonathan Peyton
__kmp_str_buf_cat(kmp_str_buf_t * buffer,char const * str,size_t len)1346b316febSTerry Wilmarth void __kmp_str_buf_cat(kmp_str_buf_t *buffer, char const *str, size_t len) {
1357cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
1367cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(str != NULL);
1377cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(len >= 0);
1386b316febSTerry Wilmarth
1397cc577a4SJonathan Peyton __kmp_str_buf_reserve(buffer, buffer->used + len + 1);
1407cc577a4SJonathan Peyton KMP_MEMCPY(buffer->str + buffer->used, str, len);
1417cc577a4SJonathan Peyton buffer->str[buffer->used + len] = 0;
1426b316febSTerry Wilmarth __kmp_type_convert(buffer->used + len, &(buffer->used));
1437cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
1447cc577a4SJonathan Peyton } // __kmp_str_buf_cat
1457cc577a4SJonathan Peyton
__kmp_str_buf_catbuf(kmp_str_buf_t * dest,const kmp_str_buf_t * src)1466d88e049SJonathan Peyton void __kmp_str_buf_catbuf(kmp_str_buf_t *dest, const kmp_str_buf_t *src) {
1476d88e049SJonathan Peyton KMP_DEBUG_ASSERT(dest);
1486d88e049SJonathan Peyton KMP_DEBUG_ASSERT(src);
1496d88e049SJonathan Peyton KMP_STR_BUF_INVARIANT(dest);
1506d88e049SJonathan Peyton KMP_STR_BUF_INVARIANT(src);
1516d88e049SJonathan Peyton if (!src->str || !src->used)
1526d88e049SJonathan Peyton return;
1536d88e049SJonathan Peyton __kmp_str_buf_reserve(dest, dest->used + src->used + 1);
1546d88e049SJonathan Peyton KMP_MEMCPY(dest->str + dest->used, src->str, src->used);
1556d88e049SJonathan Peyton dest->str[dest->used + src->used] = 0;
1566d88e049SJonathan Peyton dest->used += src->used;
1576d88e049SJonathan Peyton KMP_STR_BUF_INVARIANT(dest);
1586d88e049SJonathan Peyton } // __kmp_str_buf_catbuf
1596d88e049SJonathan Peyton
1606d88e049SJonathan Peyton // Return the number of characters written
__kmp_str_buf_vprint(kmp_str_buf_t * buffer,char const * format,va_list args)1616d88e049SJonathan Peyton int __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
1623041982dSJonathan Peyton va_list args) {
1636d88e049SJonathan Peyton int rc;
1647cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
1657cc577a4SJonathan Peyton
1667cc577a4SJonathan Peyton for (;;) {
1677cc577a4SJonathan Peyton int const free = buffer->size - buffer->used;
1687cc577a4SJonathan Peyton int size;
1697cc577a4SJonathan Peyton
1707cc577a4SJonathan Peyton // Try to format string.
1717cc577a4SJonathan Peyton {
172309b00a4SShilei Tian /* On Linux* OS Intel(R) 64, vsnprintf() modifies args argument, so
173309b00a4SShilei Tian vsnprintf() crashes if it is called for the second time with the same
174309b00a4SShilei Tian args. To prevent the crash, we have to pass a fresh intact copy of args
175309b00a4SShilei Tian to vsnprintf() on each iteration.
1767cc577a4SJonathan Peyton
177309b00a4SShilei Tian Unfortunately, standard va_copy() macro is not available on Windows*
178309b00a4SShilei Tian OS. However, it seems vsnprintf() does not modify args argument on
179309b00a4SShilei Tian Windows* OS.
1807cc577a4SJonathan Peyton */
1817cc577a4SJonathan Peyton
1827cc577a4SJonathan Peyton #if !KMP_OS_WINDOWS
1837cc577a4SJonathan Peyton va_list _args;
1840447708fSJonathan Peyton va_copy(_args, args); // Make copy of args.
1857cc577a4SJonathan Peyton #define args _args // Substitute args with its copy, _args.
1867cc577a4SJonathan Peyton #endif // KMP_OS_WINDOWS
1877cc577a4SJonathan Peyton rc = KMP_VSNPRINTF(buffer->str + buffer->used, free, format, args);
1887cc577a4SJonathan Peyton #if !KMP_OS_WINDOWS
1897cc577a4SJonathan Peyton #undef args // Remove substitution.
1907cc577a4SJonathan Peyton va_end(_args);
1917cc577a4SJonathan Peyton #endif // KMP_OS_WINDOWS
1927cc577a4SJonathan Peyton }
1937cc577a4SJonathan Peyton
1947cc577a4SJonathan Peyton // No errors, string has been formatted.
1957cc577a4SJonathan Peyton if (rc >= 0 && rc < free) {
1967cc577a4SJonathan Peyton buffer->used += rc;
1977cc577a4SJonathan Peyton break;
198bd3a7633SJonathan Peyton }
1997cc577a4SJonathan Peyton
2007cc577a4SJonathan Peyton // Error occurred, buffer is too small.
2017cc577a4SJonathan Peyton if (rc >= 0) {
2023041982dSJonathan Peyton // C99-conforming implementation of vsnprintf returns required buffer size
2037cc577a4SJonathan Peyton size = buffer->used + rc + 1;
2047cc577a4SJonathan Peyton } else {
2057cc577a4SJonathan Peyton // Older implementations just return -1. Double buffer size.
2067cc577a4SJonathan Peyton size = buffer->size * 2;
207bd3a7633SJonathan Peyton }
2087cc577a4SJonathan Peyton
2097cc577a4SJonathan Peyton // Enlarge buffer.
2107cc577a4SJonathan Peyton __kmp_str_buf_reserve(buffer, size);
2117cc577a4SJonathan Peyton
2127cc577a4SJonathan Peyton // And try again.
213bd3a7633SJonathan Peyton }
2147cc577a4SJonathan Peyton
2157cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(buffer->size > 0);
2167cc577a4SJonathan Peyton KMP_STR_BUF_INVARIANT(buffer);
2176d88e049SJonathan Peyton return rc;
2187cc577a4SJonathan Peyton } // __kmp_str_buf_vprint
2197cc577a4SJonathan Peyton
2206d88e049SJonathan Peyton // Return the number of characters written
__kmp_str_buf_print(kmp_str_buf_t * buffer,char const * format,...)2216d88e049SJonathan Peyton int __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...) {
2226d88e049SJonathan Peyton int rc;
2237cc577a4SJonathan Peyton va_list args;
2247cc577a4SJonathan Peyton va_start(args, format);
2256d88e049SJonathan Peyton rc = __kmp_str_buf_vprint(buffer, format, args);
2267cc577a4SJonathan Peyton va_end(args);
2276d88e049SJonathan Peyton return rc;
2287cc577a4SJonathan Peyton } // __kmp_str_buf_print
2297cc577a4SJonathan Peyton
2303041982dSJonathan Peyton /* The function prints specified size to buffer. Size is expressed using biggest
2313041982dSJonathan Peyton possible unit, for example 1024 is printed as "1k". */
__kmp_str_buf_print_size(kmp_str_buf_t * buf,size_t size)2323041982dSJonathan Peyton void __kmp_str_buf_print_size(kmp_str_buf_t *buf, size_t size) {
2337cc577a4SJonathan Peyton char const *names[] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y"};
2347cc577a4SJonathan Peyton int const units = sizeof(names) / sizeof(char const *);
2357cc577a4SJonathan Peyton int u = 0;
2367cc577a4SJonathan Peyton if (size > 0) {
2377cc577a4SJonathan Peyton while ((size % 1024 == 0) && (u + 1 < units)) {
2387cc577a4SJonathan Peyton size = size / 1024;
2397cc577a4SJonathan Peyton ++u;
240bd3a7633SJonathan Peyton }
241bd3a7633SJonathan Peyton }
2427cc577a4SJonathan Peyton
2437cc577a4SJonathan Peyton __kmp_str_buf_print(buf, "%" KMP_SIZE_T_SPEC "%s", size, names[u]);
2447cc577a4SJonathan Peyton } // __kmp_str_buf_print_size
2457cc577a4SJonathan Peyton
__kmp_str_fname_init(kmp_str_fname_t * fname,char const * path)2463041982dSJonathan Peyton void __kmp_str_fname_init(kmp_str_fname_t *fname, char const *path) {
2477cc577a4SJonathan Peyton fname->path = NULL;
2487cc577a4SJonathan Peyton fname->dir = NULL;
2497cc577a4SJonathan Peyton fname->base = NULL;
2507cc577a4SJonathan Peyton
2517cc577a4SJonathan Peyton if (path != NULL) {
2527cc577a4SJonathan Peyton char *slash = NULL; // Pointer to the last character of dir.
2537cc577a4SJonathan Peyton char *base = NULL; // Pointer to the beginning of basename.
2547cc577a4SJonathan Peyton fname->path = __kmp_str_format("%s", path);
2553041982dSJonathan Peyton // Original code used strdup() function to copy a string, but on Windows* OS
256ed5fe645SKelvin Li // Intel(R) 64 it causes assertion id debug heap, so I had to replace
2573041982dSJonathan Peyton // strdup with __kmp_str_format().
2587cc577a4SJonathan Peyton if (KMP_OS_WINDOWS) {
2597cc577a4SJonathan Peyton __kmp_str_replace(fname->path, '\\', '/');
260bd3a7633SJonathan Peyton }
2617cc577a4SJonathan Peyton fname->dir = __kmp_str_format("%s", fname->path);
2627cc577a4SJonathan Peyton slash = strrchr(fname->dir, '/');
2633041982dSJonathan Peyton if (KMP_OS_WINDOWS &&
2643041982dSJonathan Peyton slash == NULL) { // On Windows* OS, if slash not found,
2656b316febSTerry Wilmarth char first = (char)TOLOWER(fname->dir[0]); // look for drive.
2667cc577a4SJonathan Peyton if ('a' <= first && first <= 'z' && fname->dir[1] == ':') {
2677cc577a4SJonathan Peyton slash = &fname->dir[1];
268bd3a7633SJonathan Peyton }
269bd3a7633SJonathan Peyton }
2707cc577a4SJonathan Peyton base = (slash == NULL ? fname->dir : slash + 1);
2717cc577a4SJonathan Peyton fname->base = __kmp_str_format("%s", base); // Copy basename
2727cc577a4SJonathan Peyton *base = 0; // and truncate dir.
273bd3a7633SJonathan Peyton }
2747cc577a4SJonathan Peyton
2757cc577a4SJonathan Peyton } // kmp_str_fname_init
2767cc577a4SJonathan Peyton
__kmp_str_fname_free(kmp_str_fname_t * fname)2773041982dSJonathan Peyton void __kmp_str_fname_free(kmp_str_fname_t *fname) {
278aeb40adaSJonas Hahnfeld __kmp_str_free(&fname->path);
279aeb40adaSJonas Hahnfeld __kmp_str_free(&fname->dir);
280aeb40adaSJonas Hahnfeld __kmp_str_free(&fname->base);
2817cc577a4SJonathan Peyton } // kmp_str_fname_free
2827cc577a4SJonathan Peyton
__kmp_str_fname_match(kmp_str_fname_t const * fname,char const * pattern)2833041982dSJonathan Peyton int __kmp_str_fname_match(kmp_str_fname_t const *fname, char const *pattern) {
2847cc577a4SJonathan Peyton int dir_match = 1;
2857cc577a4SJonathan Peyton int base_match = 1;
2867cc577a4SJonathan Peyton
2877cc577a4SJonathan Peyton if (pattern != NULL) {
2887cc577a4SJonathan Peyton kmp_str_fname_t ptrn;
2897cc577a4SJonathan Peyton __kmp_str_fname_init(&ptrn, pattern);
2903041982dSJonathan Peyton dir_match = strcmp(ptrn.dir, "*/") == 0 ||
2917cc577a4SJonathan Peyton (fname->dir != NULL && __kmp_str_eqf(fname->dir, ptrn.dir));
2923041982dSJonathan Peyton base_match = strcmp(ptrn.base, "*") == 0 ||
2937cc577a4SJonathan Peyton (fname->base != NULL && __kmp_str_eqf(fname->base, ptrn.base));
2947cc577a4SJonathan Peyton __kmp_str_fname_free(&ptrn);
295bd3a7633SJonathan Peyton }
2967cc577a4SJonathan Peyton
2977cc577a4SJonathan Peyton return dir_match && base_match;
2987cc577a4SJonathan Peyton } // __kmp_str_fname_match
2997cc577a4SJonathan Peyton
30022558c85SAndreyChurbanov // Get the numeric fields from source location string.
30122558c85SAndreyChurbanov // For clang these fields are Line/Col of the start of the construct.
30222558c85SAndreyChurbanov // For icc these are LineBegin/LineEnd of the construct.
30322558c85SAndreyChurbanov // Function is fast as it does not duplicate string (which involves memory
30422558c85SAndreyChurbanov // allocation), and parses the string in place.
__kmp_str_loc_numbers(char const * Psource,int * LineBeg,int * LineEndOrCol)30522558c85SAndreyChurbanov void __kmp_str_loc_numbers(char const *Psource, int *LineBeg,
30622558c85SAndreyChurbanov int *LineEndOrCol) {
30722558c85SAndreyChurbanov char *Str;
30822558c85SAndreyChurbanov KMP_DEBUG_ASSERT(LineBeg);
30922558c85SAndreyChurbanov KMP_DEBUG_ASSERT(LineEndOrCol);
31022558c85SAndreyChurbanov // Parse Psource string ";file;func;line;line_end_or_column;;" to get
31122558c85SAndreyChurbanov // numbers only, skipping string fields "file" and "func".
31222558c85SAndreyChurbanov
31322558c85SAndreyChurbanov // Find 1-st semicolon.
31422558c85SAndreyChurbanov KMP_DEBUG_ASSERT(Psource);
31522558c85SAndreyChurbanov #ifdef __cplusplus
31622558c85SAndreyChurbanov Str = strchr(CCAST(char *, Psource), ';');
31722558c85SAndreyChurbanov #else
31822558c85SAndreyChurbanov Str = strchr(Psource, ';');
31922558c85SAndreyChurbanov #endif
32022558c85SAndreyChurbanov // Check returned pointer to see if the format of Psource is broken.
32122558c85SAndreyChurbanov if (Str) {
32222558c85SAndreyChurbanov // Find 2-nd semicolon.
32322558c85SAndreyChurbanov Str = strchr(Str + 1, ';');
32422558c85SAndreyChurbanov }
32522558c85SAndreyChurbanov if (Str) {
32622558c85SAndreyChurbanov // Find 3-rd semicolon.
32722558c85SAndreyChurbanov Str = strchr(Str + 1, ';');
32822558c85SAndreyChurbanov }
32922558c85SAndreyChurbanov if (Str) {
33022558c85SAndreyChurbanov // Read begin line number.
33122558c85SAndreyChurbanov *LineBeg = atoi(Str + 1);
33222558c85SAndreyChurbanov // Find 4-th semicolon.
33322558c85SAndreyChurbanov Str = strchr(Str + 1, ';');
33422558c85SAndreyChurbanov } else {
33522558c85SAndreyChurbanov // Broken format of input string, cannot read the number.
33622558c85SAndreyChurbanov *LineBeg = 0;
33722558c85SAndreyChurbanov }
33822558c85SAndreyChurbanov if (Str) {
339fff1abc4SAndreyChurbanov // Read end line or column number.
34022558c85SAndreyChurbanov *LineEndOrCol = atoi(Str + 1);
34122558c85SAndreyChurbanov } else {
34222558c85SAndreyChurbanov // Broken format of input string, cannot read the number.
34322558c85SAndreyChurbanov *LineEndOrCol = 0;
34422558c85SAndreyChurbanov }
34522558c85SAndreyChurbanov }
34622558c85SAndreyChurbanov
__kmp_str_loc_init(char const * psource,bool init_fname)34722558c85SAndreyChurbanov kmp_str_loc_t __kmp_str_loc_init(char const *psource, bool init_fname) {
3487cc577a4SJonathan Peyton kmp_str_loc_t loc;
3497cc577a4SJonathan Peyton
3507cc577a4SJonathan Peyton loc._bulk = NULL;
3517cc577a4SJonathan Peyton loc.file = NULL;
3527cc577a4SJonathan Peyton loc.func = NULL;
3537cc577a4SJonathan Peyton loc.line = 0;
3547cc577a4SJonathan Peyton loc.col = 0;
3557cc577a4SJonathan Peyton
3567cc577a4SJonathan Peyton if (psource != NULL) {
3577cc577a4SJonathan Peyton char *str = NULL;
3587cc577a4SJonathan Peyton char *dummy = NULL;
3597cc577a4SJonathan Peyton char *line = NULL;
3607cc577a4SJonathan Peyton char *col = NULL;
3617cc577a4SJonathan Peyton
3627cc577a4SJonathan Peyton // Copy psource to keep it intact.
3637cc577a4SJonathan Peyton loc._bulk = __kmp_str_format("%s", psource);
3647cc577a4SJonathan Peyton
3657cc577a4SJonathan Peyton // Parse psource string: ";file;func;line;col;;"
3667cc577a4SJonathan Peyton str = loc._bulk;
3677cc577a4SJonathan Peyton __kmp_str_split(str, ';', &dummy, &str);
3687cc577a4SJonathan Peyton __kmp_str_split(str, ';', &loc.file, &str);
3697cc577a4SJonathan Peyton __kmp_str_split(str, ';', &loc.func, &str);
3707cc577a4SJonathan Peyton __kmp_str_split(str, ';', &line, &str);
3717cc577a4SJonathan Peyton __kmp_str_split(str, ';', &col, &str);
3727cc577a4SJonathan Peyton
3737cc577a4SJonathan Peyton // Convert line and col into numberic values.
3747cc577a4SJonathan Peyton if (line != NULL) {
3757cc577a4SJonathan Peyton loc.line = atoi(line);
3767cc577a4SJonathan Peyton if (loc.line < 0) {
3777cc577a4SJonathan Peyton loc.line = 0;
378bd3a7633SJonathan Peyton }
379bd3a7633SJonathan Peyton }
3807cc577a4SJonathan Peyton if (col != NULL) {
3817cc577a4SJonathan Peyton loc.col = atoi(col);
3827cc577a4SJonathan Peyton if (loc.col < 0) {
3837cc577a4SJonathan Peyton loc.col = 0;
384bd3a7633SJonathan Peyton }
385bd3a7633SJonathan Peyton }
386bd3a7633SJonathan Peyton }
3877cc577a4SJonathan Peyton
3887cc577a4SJonathan Peyton __kmp_str_fname_init(&loc.fname, init_fname ? loc.file : NULL);
3897cc577a4SJonathan Peyton
3907cc577a4SJonathan Peyton return loc;
3917cc577a4SJonathan Peyton } // kmp_str_loc_init
3927cc577a4SJonathan Peyton
__kmp_str_loc_free(kmp_str_loc_t * loc)3933041982dSJonathan Peyton void __kmp_str_loc_free(kmp_str_loc_t *loc) {
3947cc577a4SJonathan Peyton __kmp_str_fname_free(&loc->fname);
395aeb40adaSJonas Hahnfeld __kmp_str_free(&(loc->_bulk));
3967cc577a4SJonathan Peyton loc->file = NULL;
3977cc577a4SJonathan Peyton loc->func = NULL;
3987cc577a4SJonathan Peyton } // kmp_str_loc_free
3997cc577a4SJonathan Peyton
4003041982dSJonathan Peyton /* This function is intended to compare file names. On Windows* OS file names
4013041982dSJonathan Peyton are case-insensitive, so functions performs case-insensitive comparison. On
4023041982dSJonathan Peyton Linux* OS it performs case-sensitive comparison. Note: The function returns
4033041982dSJonathan Peyton *true* if strings are *equal*. */
__kmp_str_eqf(char const * lhs,char const * rhs)4043041982dSJonathan Peyton int __kmp_str_eqf( // True, if strings are equal, false otherwise.
4057cc577a4SJonathan Peyton char const *lhs, // First string.
4067cc577a4SJonathan Peyton char const *rhs // Second string.
4077cc577a4SJonathan Peyton ) {
4087cc577a4SJonathan Peyton int result;
4097cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
4107cc577a4SJonathan Peyton result = (_stricmp(lhs, rhs) == 0);
4117cc577a4SJonathan Peyton #else
4127cc577a4SJonathan Peyton result = (strcmp(lhs, rhs) == 0);
4137cc577a4SJonathan Peyton #endif
4147cc577a4SJonathan Peyton return result;
4157cc577a4SJonathan Peyton } // __kmp_str_eqf
4167cc577a4SJonathan Peyton
4173041982dSJonathan Peyton /* This function is like sprintf, but it *allocates* new buffer, which must be
4183041982dSJonathan Peyton freed eventually by __kmp_str_free(). The function is very convenient for
4193041982dSJonathan Peyton constructing strings, it successfully replaces strdup(), strcat(), it frees
4203041982dSJonathan Peyton programmer from buffer allocations and helps to avoid buffer overflows.
4213041982dSJonathan Peyton Examples:
4227cc577a4SJonathan Peyton
4233041982dSJonathan Peyton str = __kmp_str_format("%s", orig); //strdup() doesn't care about buffer size
4247cc577a4SJonathan Peyton __kmp_str_free( & str );
4253041982dSJonathan Peyton str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), doesn't care
4263041982dSJonathan Peyton // about buffer size.
4277cc577a4SJonathan Peyton __kmp_str_free( & str );
4287cc577a4SJonathan Peyton str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
4297cc577a4SJonathan Peyton __kmp_str_free( & str );
4307cc577a4SJonathan Peyton
4317cc577a4SJonathan Peyton Performance note:
4327cc577a4SJonathan Peyton This function allocates memory with malloc() calls, so do not call it from
4333041982dSJonathan Peyton performance-critical code. In performance-critical code consider using
4343041982dSJonathan Peyton kmp_str_buf_t instead, since it uses stack-allocated buffer for short
4353041982dSJonathan Peyton strings.
4367cc577a4SJonathan Peyton
4377cc577a4SJonathan Peyton Why does this function use malloc()?
4383041982dSJonathan Peyton 1. __kmp_allocate() returns cache-aligned memory allocated with malloc().
4393041982dSJonathan Peyton There are no reasons in using __kmp_allocate() for strings due to extra
4403041982dSJonathan Peyton overhead while cache-aligned memory is not necessary.
4413041982dSJonathan Peyton 2. __kmp_thread_malloc() cannot be used because it requires pointer to thread
4423041982dSJonathan Peyton structure. We need to perform string operations during library startup
4433041982dSJonathan Peyton (for example, in __kmp_register_library_startup()) when no thread
4443041982dSJonathan Peyton structures are allocated yet.
4457cc577a4SJonathan Peyton So standard malloc() is the only available option.
4467cc577a4SJonathan Peyton */
4477cc577a4SJonathan Peyton
__kmp_str_format(char const * format,...)4483041982dSJonathan Peyton char *__kmp_str_format( // Allocated string.
4497cc577a4SJonathan Peyton char const *format, // Format string.
4507cc577a4SJonathan Peyton ... // Other parameters.
4517cc577a4SJonathan Peyton ) {
4527cc577a4SJonathan Peyton va_list args;
4537cc577a4SJonathan Peyton int size = 512;
4547cc577a4SJonathan Peyton char *buffer = NULL;
4557cc577a4SJonathan Peyton int rc;
4567cc577a4SJonathan Peyton
4577cc577a4SJonathan Peyton // Allocate buffer.
4587cc577a4SJonathan Peyton buffer = (char *)KMP_INTERNAL_MALLOC(size);
4597cc577a4SJonathan Peyton if (buffer == NULL) {
4607cc577a4SJonathan Peyton KMP_FATAL(MemoryAllocFailed);
461bd3a7633SJonathan Peyton }
4627cc577a4SJonathan Peyton
4637cc577a4SJonathan Peyton for (;;) {
4647cc577a4SJonathan Peyton // Try to format string.
4657cc577a4SJonathan Peyton va_start(args, format);
4667cc577a4SJonathan Peyton rc = KMP_VSNPRINTF(buffer, size, format, args);
4677cc577a4SJonathan Peyton va_end(args);
4687cc577a4SJonathan Peyton
4697cc577a4SJonathan Peyton // No errors, string has been formatted.
4707cc577a4SJonathan Peyton if (rc >= 0 && rc < size) {
4717cc577a4SJonathan Peyton break;
472bd3a7633SJonathan Peyton }
4737cc577a4SJonathan Peyton
4747cc577a4SJonathan Peyton // Error occurred, buffer is too small.
4757cc577a4SJonathan Peyton if (rc >= 0) {
4763041982dSJonathan Peyton // C99-conforming implementation of vsnprintf returns required buffer
4773041982dSJonathan Peyton // size.
4787cc577a4SJonathan Peyton size = rc + 1;
4797cc577a4SJonathan Peyton } else {
4807cc577a4SJonathan Peyton // Older implementations just return -1.
4817cc577a4SJonathan Peyton size = size * 2;
482bd3a7633SJonathan Peyton }
4837cc577a4SJonathan Peyton
4847cc577a4SJonathan Peyton // Enlarge buffer and try again.
4857cc577a4SJonathan Peyton buffer = (char *)KMP_INTERNAL_REALLOC(buffer, size);
4867cc577a4SJonathan Peyton if (buffer == NULL) {
4877cc577a4SJonathan Peyton KMP_FATAL(MemoryAllocFailed);
488bd3a7633SJonathan Peyton }
489bd3a7633SJonathan Peyton }
4907cc577a4SJonathan Peyton
4917cc577a4SJonathan Peyton return buffer;
4927cc577a4SJonathan Peyton } // func __kmp_str_format
4937cc577a4SJonathan Peyton
__kmp_str_free(char ** str)494aeb40adaSJonas Hahnfeld void __kmp_str_free(char **str) {
4957cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(str != NULL);
496aeb40adaSJonas Hahnfeld KMP_INTERNAL_FREE(*str);
4977cc577a4SJonathan Peyton *str = NULL;
4987cc577a4SJonathan Peyton } // func __kmp_str_free
4997cc577a4SJonathan Peyton
5003041982dSJonathan Peyton /* If len is zero, returns true iff target and data have exact case-insensitive
5013041982dSJonathan Peyton match. If len is negative, returns true iff target is a case-insensitive
5023041982dSJonathan Peyton substring of data. If len is positive, returns true iff target is a
5033041982dSJonathan Peyton case-insensitive substring of data or vice versa, and neither is shorter than
5043041982dSJonathan Peyton len. */
__kmp_str_match(char const * target,int len,char const * data)5053041982dSJonathan Peyton int __kmp_str_match(char const *target, int len, char const *data) {
5067cc577a4SJonathan Peyton int i;
5077cc577a4SJonathan Peyton if (target == NULL || data == NULL) {
5087cc577a4SJonathan Peyton return FALSE;
509bd3a7633SJonathan Peyton }
5107cc577a4SJonathan Peyton for (i = 0; target[i] && data[i]; ++i) {
5117cc577a4SJonathan Peyton if (TOLOWER(target[i]) != TOLOWER(data[i])) {
5127cc577a4SJonathan Peyton return FALSE;
513bd3a7633SJonathan Peyton }
514bd3a7633SJonathan Peyton }
5157cc577a4SJonathan Peyton return ((len > 0) ? i >= len : (!target[i] && (len || !data[i])));
5167cc577a4SJonathan Peyton } // __kmp_str_match
5177cc577a4SJonathan Peyton
518*d8e4cb91STerry Wilmarth // If data contains all of target, returns true, otherwise returns false.
519*d8e4cb91STerry Wilmarth // len should be the length of target
__kmp_str_contains(char const * target,int len,char const * data)520*d8e4cb91STerry Wilmarth bool __kmp_str_contains(char const *target, int len, char const *data) {
521*d8e4cb91STerry Wilmarth int i = 0, j = 0, start = 0;
522*d8e4cb91STerry Wilmarth if (target == NULL || data == NULL) {
523*d8e4cb91STerry Wilmarth return FALSE;
524*d8e4cb91STerry Wilmarth }
525*d8e4cb91STerry Wilmarth while (target[i]) {
526*d8e4cb91STerry Wilmarth if (!data[j])
527*d8e4cb91STerry Wilmarth return FALSE;
528*d8e4cb91STerry Wilmarth if (TOLOWER(target[i]) != TOLOWER(data[j])) {
529*d8e4cb91STerry Wilmarth j = start + 1;
530*d8e4cb91STerry Wilmarth start = j;
531*d8e4cb91STerry Wilmarth i = 0;
532*d8e4cb91STerry Wilmarth } else {
533*d8e4cb91STerry Wilmarth if (i == 0)
534*d8e4cb91STerry Wilmarth start = j;
535*d8e4cb91STerry Wilmarth j++;
536*d8e4cb91STerry Wilmarth i++;
537*d8e4cb91STerry Wilmarth }
538*d8e4cb91STerry Wilmarth }
539*d8e4cb91STerry Wilmarth
540*d8e4cb91STerry Wilmarth return i == len;
541*d8e4cb91STerry Wilmarth } // __kmp_str_contains
542*d8e4cb91STerry Wilmarth
__kmp_str_match_false(char const * data)5433041982dSJonathan Peyton int __kmp_str_match_false(char const *data) {
5447cc577a4SJonathan Peyton int result =
5453041982dSJonathan Peyton __kmp_str_match("false", 1, data) || __kmp_str_match("off", 2, data) ||
5463041982dSJonathan Peyton __kmp_str_match("0", 1, data) || __kmp_str_match(".false.", 2, data) ||
54760eec6feSJonathan Peyton __kmp_str_match(".f.", 2, data) || __kmp_str_match("no", 1, data) ||
54860eec6feSJonathan Peyton __kmp_str_match("disabled", 0, data);
5497cc577a4SJonathan Peyton return result;
5507cc577a4SJonathan Peyton } // __kmp_str_match_false
5517cc577a4SJonathan Peyton
__kmp_str_match_true(char const * data)5523041982dSJonathan Peyton int __kmp_str_match_true(char const *data) {
5537cc577a4SJonathan Peyton int result =
5543041982dSJonathan Peyton __kmp_str_match("true", 1, data) || __kmp_str_match("on", 2, data) ||
5553041982dSJonathan Peyton __kmp_str_match("1", 1, data) || __kmp_str_match(".true.", 2, data) ||
55660eec6feSJonathan Peyton __kmp_str_match(".t.", 2, data) || __kmp_str_match("yes", 1, data) ||
55760eec6feSJonathan Peyton __kmp_str_match("enabled", 0, data);
5587cc577a4SJonathan Peyton return result;
5597cc577a4SJonathan Peyton } // __kmp_str_match_true
5607cc577a4SJonathan Peyton
__kmp_str_replace(char * str,char search_for,char replace_with)5613041982dSJonathan Peyton void __kmp_str_replace(char *str, char search_for, char replace_with) {
5627cc577a4SJonathan Peyton char *found = NULL;
5637cc577a4SJonathan Peyton
5647cc577a4SJonathan Peyton found = strchr(str, search_for);
5657cc577a4SJonathan Peyton while (found) {
5667cc577a4SJonathan Peyton *found = replace_with;
5677cc577a4SJonathan Peyton found = strchr(found + 1, search_for);
568bd3a7633SJonathan Peyton }
5697cc577a4SJonathan Peyton } // __kmp_str_replace
5707cc577a4SJonathan Peyton
__kmp_str_split(char * str,char delim,char ** head,char ** tail)5713041982dSJonathan Peyton void __kmp_str_split(char *str, // I: String to split.
5727cc577a4SJonathan Peyton char delim, // I: Character to split on.
5737cc577a4SJonathan Peyton char **head, // O: Pointer to head (may be NULL).
5747cc577a4SJonathan Peyton char **tail // O: Pointer to tail (may be NULL).
5757cc577a4SJonathan Peyton ) {
5767cc577a4SJonathan Peyton char *h = str;
5777cc577a4SJonathan Peyton char *t = NULL;
5787cc577a4SJonathan Peyton if (str != NULL) {
5797cc577a4SJonathan Peyton char *ptr = strchr(str, delim);
5807cc577a4SJonathan Peyton if (ptr != NULL) {
5817cc577a4SJonathan Peyton *ptr = 0;
5827cc577a4SJonathan Peyton t = ptr + 1;
583bd3a7633SJonathan Peyton }
584bd3a7633SJonathan Peyton }
5857cc577a4SJonathan Peyton if (head != NULL) {
5867cc577a4SJonathan Peyton *head = h;
587bd3a7633SJonathan Peyton }
5887cc577a4SJonathan Peyton if (tail != NULL) {
5897cc577a4SJonathan Peyton *tail = t;
590bd3a7633SJonathan Peyton }
5917cc577a4SJonathan Peyton } // __kmp_str_split
5927cc577a4SJonathan Peyton
5933041982dSJonathan Peyton /* strtok_r() is not available on Windows* OS. This function reimplements
5943041982dSJonathan Peyton strtok_r(). */
__kmp_str_token(char * str,char const * delim,char ** buf)5953041982dSJonathan Peyton char *__kmp_str_token(
5967cc577a4SJonathan Peyton char *str, // String to split into tokens. Note: String *is* modified!
5977cc577a4SJonathan Peyton char const *delim, // Delimiters.
5987cc577a4SJonathan Peyton char **buf // Internal buffer.
5997cc577a4SJonathan Peyton ) {
6007cc577a4SJonathan Peyton char *token = NULL;
6017cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
6027cc577a4SJonathan Peyton // On Windows* OS there is no strtok_r() function. Let us implement it.
6037cc577a4SJonathan Peyton if (str != NULL) {
6047cc577a4SJonathan Peyton *buf = str; // First call, initialize buf.
605bd3a7633SJonathan Peyton }
6067cc577a4SJonathan Peyton *buf += strspn(*buf, delim); // Skip leading delimiters.
6077cc577a4SJonathan Peyton if (**buf != 0) { // Rest of the string is not yet empty.
6087cc577a4SJonathan Peyton token = *buf; // Use it as result.
6097cc577a4SJonathan Peyton *buf += strcspn(*buf, delim); // Skip non-delimiters.
6107cc577a4SJonathan Peyton if (**buf != 0) { // Rest of the string is not yet empty.
6117cc577a4SJonathan Peyton **buf = 0; // Terminate token here.
6127cc577a4SJonathan Peyton *buf += 1; // Advance buf to start with the next token next time.
613bd3a7633SJonathan Peyton }
614bd3a7633SJonathan Peyton }
6157cc577a4SJonathan Peyton #else
6167cc577a4SJonathan Peyton // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
6177cc577a4SJonathan Peyton token = strtok_r(str, delim, buf);
6187cc577a4SJonathan Peyton #endif
6197cc577a4SJonathan Peyton return token;
620bd3a7633SJonathan Peyton } // __kmp_str_token
6217cc577a4SJonathan Peyton
__kmp_str_to_int(char const * str,char sentinel)6223041982dSJonathan Peyton int __kmp_str_to_int(char const *str, char sentinel) {
6237cc577a4SJonathan Peyton int result, factor;
6247cc577a4SJonathan Peyton char const *t;
6257cc577a4SJonathan Peyton
6267cc577a4SJonathan Peyton result = 0;
6277cc577a4SJonathan Peyton
6287cc577a4SJonathan Peyton for (t = str; *t != '\0'; ++t) {
6297cc577a4SJonathan Peyton if (*t < '0' || *t > '9')
6307cc577a4SJonathan Peyton break;
6317cc577a4SJonathan Peyton result = (result * 10) + (*t - '0');
6327cc577a4SJonathan Peyton }
6337cc577a4SJonathan Peyton
6347cc577a4SJonathan Peyton switch (*t) {
6357cc577a4SJonathan Peyton case '\0': /* the current default for no suffix is bytes */
6367cc577a4SJonathan Peyton factor = 1;
6377cc577a4SJonathan Peyton break;
6383041982dSJonathan Peyton case 'b':
6393041982dSJonathan Peyton case 'B': /* bytes */
6407cc577a4SJonathan Peyton ++t;
6417cc577a4SJonathan Peyton factor = 1;
6427cc577a4SJonathan Peyton break;
6433041982dSJonathan Peyton case 'k':
6443041982dSJonathan Peyton case 'K': /* kilo-bytes */
6457cc577a4SJonathan Peyton ++t;
6467cc577a4SJonathan Peyton factor = 1024;
6477cc577a4SJonathan Peyton break;
6483041982dSJonathan Peyton case 'm':
6493041982dSJonathan Peyton case 'M': /* mega-bytes */
6507cc577a4SJonathan Peyton ++t;
6517cc577a4SJonathan Peyton factor = (1024 * 1024);
6527cc577a4SJonathan Peyton break;
6537cc577a4SJonathan Peyton default:
6547cc577a4SJonathan Peyton if (*t != sentinel)
6557cc577a4SJonathan Peyton return (-1);
6567cc577a4SJonathan Peyton t = "";
6577cc577a4SJonathan Peyton factor = 1;
6587cc577a4SJonathan Peyton }
6597cc577a4SJonathan Peyton
6607cc577a4SJonathan Peyton if (result > (INT_MAX / factor))
6617cc577a4SJonathan Peyton result = INT_MAX;
6627cc577a4SJonathan Peyton else
6637cc577a4SJonathan Peyton result *= factor;
6647cc577a4SJonathan Peyton
6657cc577a4SJonathan Peyton return (*t != 0 ? 0 : result);
6667cc577a4SJonathan Peyton } // __kmp_str_to_int
6677cc577a4SJonathan Peyton
6683041982dSJonathan Peyton /* The routine parses input string. It is expected it is a unsigned integer with
6693041982dSJonathan Peyton optional unit. Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb"
6703041982dSJonathan Peyton or "m" for megabytes, ..., "yb" or "y" for yottabytes. :-) Unit name is
6713041982dSJonathan Peyton case-insensitive. The routine returns 0 if everything is ok, or error code:
6723041982dSJonathan Peyton -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
6733041982dSJonathan Peyton value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown
6743041982dSJonathan Peyton unit *size is set to zero. */
__kmp_str_to_size(char const * str,size_t * out,size_t dfactor,char const ** error)6753041982dSJonathan Peyton void __kmp_str_to_size( // R: Error code.
6763041982dSJonathan Peyton char const *str, // I: String of characters, unsigned number and unit ("b",
6773041982dSJonathan Peyton // "kb", etc).
6787cc577a4SJonathan Peyton size_t *out, // O: Parsed number.
6797cc577a4SJonathan Peyton size_t dfactor, // I: The factor if none of the letters specified.
6807cc577a4SJonathan Peyton char const **error // O: Null if everything is ok, error message otherwise.
6817cc577a4SJonathan Peyton ) {
6827cc577a4SJonathan Peyton
6837cc577a4SJonathan Peyton size_t value = 0;
6847cc577a4SJonathan Peyton size_t factor = 0;
6857cc577a4SJonathan Peyton int overflow = 0;
6867cc577a4SJonathan Peyton int i = 0;
6877cc577a4SJonathan Peyton int digit;
6887cc577a4SJonathan Peyton
6897cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(str != NULL);
6907cc577a4SJonathan Peyton
6917cc577a4SJonathan Peyton // Skip spaces.
6927cc577a4SJonathan Peyton while (str[i] == ' ' || str[i] == '\t') {
6937cc577a4SJonathan Peyton ++i;
694bd3a7633SJonathan Peyton }
6957cc577a4SJonathan Peyton
6967cc577a4SJonathan Peyton // Parse number.
6977cc577a4SJonathan Peyton if (str[i] < '0' || str[i] > '9') {
6987cc577a4SJonathan Peyton *error = KMP_I18N_STR(NotANumber);
6997cc577a4SJonathan Peyton return;
700bd3a7633SJonathan Peyton }
7017cc577a4SJonathan Peyton do {
7027cc577a4SJonathan Peyton digit = str[i] - '0';
7037cc577a4SJonathan Peyton overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
7047cc577a4SJonathan Peyton value = (value * 10) + digit;
7057cc577a4SJonathan Peyton ++i;
7067cc577a4SJonathan Peyton } while (str[i] >= '0' && str[i] <= '9');
7077cc577a4SJonathan Peyton
7087cc577a4SJonathan Peyton // Skip spaces.
7097cc577a4SJonathan Peyton while (str[i] == ' ' || str[i] == '\t') {
7107cc577a4SJonathan Peyton ++i;
711bd3a7633SJonathan Peyton }
7127cc577a4SJonathan Peyton
7137cc577a4SJonathan Peyton // Parse unit.
7147cc577a4SJonathan Peyton #define _case(ch, exp) \
7157cc577a4SJonathan Peyton case ch: \
7167cc577a4SJonathan Peyton case ch - ('a' - 'A'): { \
7177cc577a4SJonathan Peyton size_t shift = (exp)*10; \
7187cc577a4SJonathan Peyton ++i; \
7197cc577a4SJonathan Peyton if (shift < sizeof(size_t) * 8) { \
7207cc577a4SJonathan Peyton factor = (size_t)(1) << shift; \
7217cc577a4SJonathan Peyton } else { \
7227cc577a4SJonathan Peyton overflow = 1; \
723bd3a7633SJonathan Peyton } \
7247cc577a4SJonathan Peyton } break;
7257cc577a4SJonathan Peyton switch (str[i]) {
7267cc577a4SJonathan Peyton _case('k', 1); // Kilo
7277cc577a4SJonathan Peyton _case('m', 2); // Mega
7287cc577a4SJonathan Peyton _case('g', 3); // Giga
7297cc577a4SJonathan Peyton _case('t', 4); // Tera
7307cc577a4SJonathan Peyton _case('p', 5); // Peta
7317cc577a4SJonathan Peyton _case('e', 6); // Exa
7327cc577a4SJonathan Peyton _case('z', 7); // Zetta
7337cc577a4SJonathan Peyton _case('y', 8); // Yotta
7347cc577a4SJonathan Peyton // Oops. No more units...
735bd3a7633SJonathan Peyton }
7367cc577a4SJonathan Peyton #undef _case
7377cc577a4SJonathan Peyton if (str[i] == 'b' || str[i] == 'B') { // Skip optional "b".
7387cc577a4SJonathan Peyton if (factor == 0) {
7397cc577a4SJonathan Peyton factor = 1;
7407cc577a4SJonathan Peyton }
7417cc577a4SJonathan Peyton ++i;
742bd3a7633SJonathan Peyton }
7437cc577a4SJonathan Peyton if (!(str[i] == ' ' || str[i] == '\t' || str[i] == 0)) { // Bad unit
7447cc577a4SJonathan Peyton *error = KMP_I18N_STR(BadUnit);
7457cc577a4SJonathan Peyton return;
746bd3a7633SJonathan Peyton }
7477cc577a4SJonathan Peyton
7487cc577a4SJonathan Peyton if (factor == 0) {
7497cc577a4SJonathan Peyton factor = dfactor;
7507cc577a4SJonathan Peyton }
7517cc577a4SJonathan Peyton
7527cc577a4SJonathan Peyton // Apply factor.
7537cc577a4SJonathan Peyton overflow = overflow || (value > (KMP_SIZE_T_MAX / factor));
7547cc577a4SJonathan Peyton value *= factor;
7557cc577a4SJonathan Peyton
7567cc577a4SJonathan Peyton // Skip spaces.
7577cc577a4SJonathan Peyton while (str[i] == ' ' || str[i] == '\t') {
7587cc577a4SJonathan Peyton ++i;
759bd3a7633SJonathan Peyton }
7607cc577a4SJonathan Peyton
7617cc577a4SJonathan Peyton if (str[i] != 0) {
7627cc577a4SJonathan Peyton *error = KMP_I18N_STR(IllegalCharacters);
7637cc577a4SJonathan Peyton return;
764bd3a7633SJonathan Peyton }
7657cc577a4SJonathan Peyton
7667cc577a4SJonathan Peyton if (overflow) {
7677cc577a4SJonathan Peyton *error = KMP_I18N_STR(ValueTooLarge);
7687cc577a4SJonathan Peyton *out = KMP_SIZE_T_MAX;
7697cc577a4SJonathan Peyton return;
770bd3a7633SJonathan Peyton }
7717cc577a4SJonathan Peyton
7727cc577a4SJonathan Peyton *error = NULL;
7737cc577a4SJonathan Peyton *out = value;
7747cc577a4SJonathan Peyton } // __kmp_str_to_size
7757cc577a4SJonathan Peyton
__kmp_str_to_uint(char const * str,kmp_uint64 * out,char const ** error)7763041982dSJonathan Peyton void __kmp_str_to_uint( // R: Error code.
7777cc577a4SJonathan Peyton char const *str, // I: String of characters, unsigned number.
7787cc577a4SJonathan Peyton kmp_uint64 *out, // O: Parsed number.
7797cc577a4SJonathan Peyton char const **error // O: Null if everything is ok, error message otherwise.
7807cc577a4SJonathan Peyton ) {
7817cc577a4SJonathan Peyton size_t value = 0;
7827cc577a4SJonathan Peyton int overflow = 0;
7837cc577a4SJonathan Peyton int i = 0;
7847cc577a4SJonathan Peyton int digit;
7857cc577a4SJonathan Peyton
7867cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(str != NULL);
7877cc577a4SJonathan Peyton
7887cc577a4SJonathan Peyton // Skip spaces.
7897cc577a4SJonathan Peyton while (str[i] == ' ' || str[i] == '\t') {
7907cc577a4SJonathan Peyton ++i;
791bd3a7633SJonathan Peyton }
7927cc577a4SJonathan Peyton
7937cc577a4SJonathan Peyton // Parse number.
7947cc577a4SJonathan Peyton if (str[i] < '0' || str[i] > '9') {
7957cc577a4SJonathan Peyton *error = KMP_I18N_STR(NotANumber);
7967cc577a4SJonathan Peyton return;
797bd3a7633SJonathan Peyton }
7987cc577a4SJonathan Peyton do {
7997cc577a4SJonathan Peyton digit = str[i] - '0';
8007cc577a4SJonathan Peyton overflow = overflow || (value > (KMP_SIZE_T_MAX - digit) / 10);
8017cc577a4SJonathan Peyton value = (value * 10) + digit;
8027cc577a4SJonathan Peyton ++i;
8037cc577a4SJonathan Peyton } while (str[i] >= '0' && str[i] <= '9');
8047cc577a4SJonathan Peyton
8057cc577a4SJonathan Peyton // Skip spaces.
8067cc577a4SJonathan Peyton while (str[i] == ' ' || str[i] == '\t') {
8077cc577a4SJonathan Peyton ++i;
808bd3a7633SJonathan Peyton }
8097cc577a4SJonathan Peyton
8107cc577a4SJonathan Peyton if (str[i] != 0) {
8117cc577a4SJonathan Peyton *error = KMP_I18N_STR(IllegalCharacters);
8127cc577a4SJonathan Peyton return;
813bd3a7633SJonathan Peyton }
8147cc577a4SJonathan Peyton
8157cc577a4SJonathan Peyton if (overflow) {
8167cc577a4SJonathan Peyton *error = KMP_I18N_STR(ValueTooLarge);
8177cc577a4SJonathan Peyton *out = (kmp_uint64)-1;
8187cc577a4SJonathan Peyton return;
819bd3a7633SJonathan Peyton }
8207cc577a4SJonathan Peyton
8217cc577a4SJonathan Peyton *error = NULL;
8227cc577a4SJonathan Peyton *out = value;
8237cc577a4SJonathan Peyton } // __kmp_str_to_unit
8247cc577a4SJonathan Peyton
8257cc577a4SJonathan Peyton // end of file //
826