2 * kmp_str.cpp -- String manipulation routines.
5 //===----------------------------------------------------------------------===//
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
11 //===----------------------------------------------------------------------===//
15 #include <stdarg.h> // va_*
16 #include <stdio.h> // vsnprintf()
17 #include <stdlib.h> // malloc(), realloc()
26 // Declare buffer and initialize it.
28 __kmp_str_buf_init( & 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);
34 // Use buffer contents. buffer.str is a pointer to data, buffer.used is a
35 // number of printed characters (not including terminating zero).
36 write( fd, buffer.str, buffer.used );
39 __kmp_str_buf_free( & buffer );
41 // Alternatively, you can detach allocated memory from buffer:
42 __kmp_str_buf_detach( & buffer );
43 return buffer.str; // That memory should be freed eventually.
47 * Buffer users may use buffer.str and buffer.used. Users should not change
48 any fields of buffer directly.
49 * buffer.str is never NULL. If buffer is empty, buffer.str points to empty
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.
57 // TODO: __kmp_str_buf_print() can use thread local memory allocator.
59 #define KMP_STR_BUF_INVARIANT(b) \
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); \
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] \
71 void __kmp_str_buf_clear(kmp_str_buf_t
*buffer
) {
72 KMP_STR_BUF_INVARIANT(buffer
);
73 if (buffer
->used
> 0) {
77 KMP_STR_BUF_INVARIANT(buffer
);
78 } // __kmp_str_buf_clear
80 void __kmp_str_buf_reserve(kmp_str_buf_t
*buffer
, size_t size
) {
81 KMP_STR_BUF_INVARIANT(buffer
);
82 KMP_DEBUG_ASSERT(size
>= 0);
84 if (buffer
->size
< (unsigned int)size
) {
85 // Calculate buffer size.
88 } while (buffer
->size
< (unsigned int)size
);
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
);
96 KMP_MEMCPY_S(buffer
->str
, buffer
->size
, buffer
->bulk
, buffer
->used
+ 1);
98 buffer
->str
= (char *)KMP_INTERNAL_REALLOC(buffer
->str
, buffer
->size
);
99 if (buffer
->str
== NULL
) {
100 KMP_FATAL(MemoryAllocFailed
);
105 KMP_DEBUG_ASSERT(buffer
->size
> 0);
106 KMP_DEBUG_ASSERT(buffer
->size
>= (unsigned)size
);
107 KMP_STR_BUF_INVARIANT(buffer
);
108 } // __kmp_str_buf_reserve
110 void __kmp_str_buf_detach(kmp_str_buf_t
*buffer
) {
111 KMP_STR_BUF_INVARIANT(buffer
);
113 // If internal bulk is used, allocate memory and copy it.
114 if (buffer
->size
<= sizeof(buffer
->bulk
)) {
115 buffer
->str
= (char *)KMP_INTERNAL_MALLOC(buffer
->size
);
116 if (buffer
->str
== NULL
) {
117 KMP_FATAL(MemoryAllocFailed
);
119 KMP_MEMCPY_S(buffer
->str
, buffer
->size
, buffer
->bulk
, buffer
->used
+ 1);
121 } // __kmp_str_buf_detach
123 void __kmp_str_buf_free(kmp_str_buf_t
*buffer
) {
124 KMP_STR_BUF_INVARIANT(buffer
);
125 if (buffer
->size
> sizeof(buffer
->bulk
)) {
126 KMP_INTERNAL_FREE(buffer
->str
);
128 buffer
->str
= buffer
->bulk
;
129 buffer
->size
= sizeof(buffer
->bulk
);
131 KMP_STR_BUF_INVARIANT(buffer
);
132 } // __kmp_str_buf_free
134 void __kmp_str_buf_cat(kmp_str_buf_t
*buffer
, char const *str
, size_t len
) {
135 KMP_STR_BUF_INVARIANT(buffer
);
136 KMP_DEBUG_ASSERT(str
!= NULL
);
137 KMP_DEBUG_ASSERT(len
>= 0);
139 __kmp_str_buf_reserve(buffer
, buffer
->used
+ len
+ 1);
140 buffer
->str
[buffer
->used
] = '\0';
141 KMP_STRNCAT_S(buffer
->str
+ buffer
->used
, len
+ 1, str
, len
);
142 __kmp_type_convert(buffer
->used
+ len
, &(buffer
->used
));
143 KMP_STR_BUF_INVARIANT(buffer
);
144 } // __kmp_str_buf_cat
146 void __kmp_str_buf_catbuf(kmp_str_buf_t
*dest
, const kmp_str_buf_t
*src
) {
147 KMP_DEBUG_ASSERT(dest
);
148 KMP_DEBUG_ASSERT(src
);
149 KMP_STR_BUF_INVARIANT(dest
);
150 KMP_STR_BUF_INVARIANT(src
);
151 if (!src
->str
|| !src
->used
)
153 __kmp_str_buf_reserve(dest
, dest
->used
+ src
->used
+ 1);
154 dest
->str
[dest
->used
] = '\0';
155 KMP_STRNCAT_S(dest
->str
+ dest
->used
, src
->used
+ 1, src
->str
, src
->used
);
156 dest
->used
+= src
->used
;
157 KMP_STR_BUF_INVARIANT(dest
);
158 } // __kmp_str_buf_catbuf
160 // Return the number of characters written
161 int __kmp_str_buf_vprint(kmp_str_buf_t
*buffer
, char const *format
,
164 KMP_STR_BUF_INVARIANT(buffer
);
167 int const free
= buffer
->size
- buffer
->used
;
170 // Try to format string.
172 /* On Linux* OS Intel(R) 64, vsnprintf() modifies args argument, so
173 vsnprintf() crashes if it is called for the second time with the same
174 args. To prevent the crash, we have to pass a fresh intact copy of args
175 to vsnprintf() on each iteration.
177 Unfortunately, standard va_copy() macro is not available on Windows*
178 OS. However, it seems vsnprintf() does not modify args argument on
184 va_copy(_args
, args
); // Make copy of args.
185 #define args _args // Substitute args with its copy, _args.
186 #endif // KMP_OS_WINDOWS
187 rc
= KMP_VSNPRINTF(buffer
->str
+ buffer
->used
, free
, format
, args
);
189 #undef args // Remove substitution.
191 #endif // KMP_OS_WINDOWS
194 // No errors, string has been formatted.
195 if (rc
>= 0 && rc
< free
) {
200 // Error occurred, buffer is too small.
202 // C99-conforming implementation of vsnprintf returns required buffer size
203 size
= buffer
->used
+ rc
+ 1;
205 // Older implementations just return -1. Double buffer size.
206 size
= buffer
->size
* 2;
210 __kmp_str_buf_reserve(buffer
, size
);
215 KMP_DEBUG_ASSERT(buffer
->size
> 0);
216 KMP_STR_BUF_INVARIANT(buffer
);
218 } // __kmp_str_buf_vprint
220 // Return the number of characters written
221 int __kmp_str_buf_print(kmp_str_buf_t
*buffer
, char const *format
, ...) {
224 va_start(args
, format
);
225 rc
= __kmp_str_buf_vprint(buffer
, format
, args
);
228 } // __kmp_str_buf_print
230 /* The function prints specified size to buffer. Size is expressed using biggest
231 possible unit, for example 1024 is printed as "1k". */
232 void __kmp_str_buf_print_size(kmp_str_buf_t
*buf
, size_t size
) {
233 char const *names
[] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y"};
234 int const units
= sizeof(names
) / sizeof(char const *);
237 while ((size
% 1024 == 0) && (u
+ 1 < units
)) {
243 __kmp_str_buf_print(buf
, "%" KMP_SIZE_T_SPEC
"%s", size
, names
[u
]);
244 } // __kmp_str_buf_print_size
246 void __kmp_str_fname_init(kmp_str_fname_t
*fname
, char const *path
) {
252 char *slash
= NULL
; // Pointer to the last character of dir.
253 char *base
= NULL
; // Pointer to the beginning of basename.
254 fname
->path
= __kmp_str_format("%s", path
);
255 // Original code used strdup() function to copy a string, but on Windows* OS
256 // Intel(R) 64 it causes assertion id debug heap, so I had to replace
257 // strdup with __kmp_str_format().
258 if (KMP_OS_WINDOWS
) {
259 __kmp_str_replace(fname
->path
, '\\', '/');
261 fname
->dir
= __kmp_str_format("%s", fname
->path
);
262 slash
= strrchr(fname
->dir
, '/');
263 if (KMP_OS_WINDOWS
&&
264 slash
== NULL
) { // On Windows* OS, if slash not found,
265 char first
= (char)TOLOWER(fname
->dir
[0]); // look for drive.
266 if ('a' <= first
&& first
<= 'z' && fname
->dir
[1] == ':') {
267 slash
= &fname
->dir
[1];
270 base
= (slash
== NULL
? fname
->dir
: slash
+ 1);
271 fname
->base
= __kmp_str_format("%s", base
); // Copy basename
272 *base
= 0; // and truncate dir.
275 } // kmp_str_fname_init
277 void __kmp_str_fname_free(kmp_str_fname_t
*fname
) {
278 __kmp_str_free(&fname
->path
);
279 __kmp_str_free(&fname
->dir
);
280 __kmp_str_free(&fname
->base
);
281 } // kmp_str_fname_free
283 int __kmp_str_fname_match(kmp_str_fname_t
const *fname
, char const *pattern
) {
287 if (pattern
!= NULL
) {
288 kmp_str_fname_t ptrn
;
289 __kmp_str_fname_init(&ptrn
, pattern
);
290 dir_match
= strcmp(ptrn
.dir
, "*/") == 0 ||
291 (fname
->dir
!= NULL
&& __kmp_str_eqf(fname
->dir
, ptrn
.dir
));
292 base_match
= strcmp(ptrn
.base
, "*") == 0 ||
293 (fname
->base
!= NULL
&& __kmp_str_eqf(fname
->base
, ptrn
.base
));
294 __kmp_str_fname_free(&ptrn
);
297 return dir_match
&& base_match
;
298 } // __kmp_str_fname_match
300 // Get the numeric fields from source location string.
301 // For clang these fields are Line/Col of the start of the construct.
302 // For icc these are LineBegin/LineEnd of the construct.
303 // Function is fast as it does not duplicate string (which involves memory
304 // allocation), and parses the string in place.
305 void __kmp_str_loc_numbers(char const *Psource
, int *LineBeg
,
308 KMP_DEBUG_ASSERT(LineBeg
);
309 KMP_DEBUG_ASSERT(LineEndOrCol
);
310 // Parse Psource string ";file;func;line;line_end_or_column;;" to get
311 // numbers only, skipping string fields "file" and "func".
313 // Find 1-st semicolon.
314 KMP_DEBUG_ASSERT(Psource
);
316 Str
= strchr(CCAST(char *, Psource
), ';');
318 Str
= strchr(Psource
, ';');
320 // Check returned pointer to see if the format of Psource is broken.
322 // Find 2-nd semicolon.
323 Str
= strchr(Str
+ 1, ';');
326 // Find 3-rd semicolon.
327 Str
= strchr(Str
+ 1, ';');
330 // Read begin line number.
331 *LineBeg
= atoi(Str
+ 1);
332 // Find 4-th semicolon.
333 Str
= strchr(Str
+ 1, ';');
335 // Broken format of input string, cannot read the number.
339 // Read end line or column number.
340 *LineEndOrCol
= atoi(Str
+ 1);
342 // Broken format of input string, cannot read the number.
347 kmp_str_loc_t
__kmp_str_loc_init(char const *psource
, bool init_fname
) {
356 if (psource
!= NULL
) {
362 // Copy psource to keep it intact.
363 loc
._bulk
= __kmp_str_format("%s", psource
);
365 // Parse psource string: ";file;func;line;col;;"
367 __kmp_str_split(str
, ';', &dummy
, &str
);
368 __kmp_str_split(str
, ';', &loc
.file
, &str
);
369 __kmp_str_split(str
, ';', &loc
.func
, &str
);
370 __kmp_str_split(str
, ';', &line
, &str
);
371 __kmp_str_split(str
, ';', &col
, &str
);
373 // Convert line and col into numberic values.
375 loc
.line
= atoi(line
);
388 __kmp_str_fname_init(&loc
.fname
, init_fname
? loc
.file
: NULL
);
391 } // kmp_str_loc_init
393 void __kmp_str_loc_free(kmp_str_loc_t
*loc
) {
394 __kmp_str_fname_free(&loc
->fname
);
395 __kmp_str_free(&(loc
->_bulk
));
398 } // kmp_str_loc_free
400 /* This function is intended to compare file names. On Windows* OS file names
401 are case-insensitive, so functions performs case-insensitive comparison. On
402 Linux* OS it performs case-sensitive comparison. Note: The function returns
403 *true* if strings are *equal*. */
404 int __kmp_str_eqf( // True, if strings are equal, false otherwise.
405 char const *lhs
, // First string.
406 char const *rhs
// Second string.
410 result
= (_stricmp(lhs
, rhs
) == 0);
412 result
= (strcmp(lhs
, rhs
) == 0);
417 /* This function is like sprintf, but it *allocates* new buffer, which must be
418 freed eventually by __kmp_str_free(). The function is very convenient for
419 constructing strings, it successfully replaces strdup(), strcat(), it frees
420 programmer from buffer allocations and helps to avoid buffer overflows.
423 str = __kmp_str_format("%s", orig); //strdup() doesn't care about buffer size
424 __kmp_str_free( & str );
425 str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), doesn't care
426 // about buffer size.
427 __kmp_str_free( & str );
428 str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
429 __kmp_str_free( & str );
432 This function allocates memory with malloc() calls, so do not call it from
433 performance-critical code. In performance-critical code consider using
434 kmp_str_buf_t instead, since it uses stack-allocated buffer for short
437 Why does this function use malloc()?
438 1. __kmp_allocate() returns cache-aligned memory allocated with malloc().
439 There are no reasons in using __kmp_allocate() for strings due to extra
440 overhead while cache-aligned memory is not necessary.
441 2. __kmp_thread_malloc() cannot be used because it requires pointer to thread
442 structure. We need to perform string operations during library startup
443 (for example, in __kmp_register_library_startup()) when no thread
444 structures are allocated yet.
445 So standard malloc() is the only available option.
448 char *__kmp_str_format( // Allocated string.
449 char const *format
, // Format string.
450 ... // Other parameters.
458 buffer
= (char *)KMP_INTERNAL_MALLOC(size
);
459 if (buffer
== NULL
) {
460 KMP_FATAL(MemoryAllocFailed
);
464 // Try to format string.
465 va_start(args
, format
);
466 rc
= KMP_VSNPRINTF(buffer
, size
, format
, args
);
469 // No errors, string has been formatted.
470 if (rc
>= 0 && rc
< size
) {
474 // Error occurred, buffer is too small.
476 // C99-conforming implementation of vsnprintf returns required buffer
480 // Older implementations just return -1.
484 // Enlarge buffer and try again.
485 buffer
= (char *)KMP_INTERNAL_REALLOC(buffer
, size
);
486 if (buffer
== NULL
) {
487 KMP_FATAL(MemoryAllocFailed
);
492 } // func __kmp_str_format
494 void __kmp_str_free(char **str
) {
495 KMP_DEBUG_ASSERT(str
!= NULL
);
496 KMP_INTERNAL_FREE(*str
);
498 } // func __kmp_str_free
500 /* If len is zero, returns true iff target and data have exact case-insensitive
501 match. If len is negative, returns true iff target is a case-insensitive
502 substring of data. If len is positive, returns true iff target is a
503 case-insensitive substring of data or vice versa, and neither is shorter than
505 int __kmp_str_match(char const *target
, int len
, char const *data
) {
507 if (target
== NULL
|| data
== NULL
) {
510 for (i
= 0; target
[i
] && data
[i
]; ++i
) {
511 if (TOLOWER(target
[i
]) != TOLOWER(data
[i
])) {
515 return ((len
> 0) ? i
>= len
: (!target
[i
] && (len
|| !data
[i
])));
518 // If data contains all of target, returns true, otherwise returns false.
519 // len should be the length of target
520 bool __kmp_str_contains(char const *target
, int len
, char const *data
) {
521 int i
= 0, j
= 0, start
= 0;
522 if (target
== NULL
|| data
== NULL
) {
528 if (TOLOWER(target
[i
]) != TOLOWER(data
[j
])) {
541 } // __kmp_str_contains
543 int __kmp_str_match_false(char const *data
) {
545 __kmp_str_match("false", 1, data
) || __kmp_str_match("off", 2, data
) ||
546 __kmp_str_match("0", 1, data
) || __kmp_str_match(".false.", 2, data
) ||
547 __kmp_str_match(".f.", 2, data
) || __kmp_str_match("no", 1, data
) ||
548 __kmp_str_match("disabled", 0, data
);
550 } // __kmp_str_match_false
552 int __kmp_str_match_true(char const *data
) {
554 __kmp_str_match("true", 1, data
) || __kmp_str_match("on", 2, data
) ||
555 __kmp_str_match("1", 1, data
) || __kmp_str_match(".true.", 2, data
) ||
556 __kmp_str_match(".t.", 2, data
) || __kmp_str_match("yes", 1, data
) ||
557 __kmp_str_match("enabled", 0, data
);
559 } // __kmp_str_match_true
561 void __kmp_str_replace(char *str
, char search_for
, char replace_with
) {
564 found
= strchr(str
, search_for
);
566 *found
= replace_with
;
567 found
= strchr(found
+ 1, search_for
);
569 } // __kmp_str_replace
571 void __kmp_str_split(char *str
, // I: String to split.
572 char delim
, // I: Character to split on.
573 char **head
, // O: Pointer to head (may be NULL).
574 char **tail
// O: Pointer to tail (may be NULL).
579 char *ptr
= strchr(str
, delim
);
593 /* strtok_r() is not available on Windows* OS. This function reimplements
595 char *__kmp_str_token(
596 char *str
, // String to split into tokens. Note: String *is* modified!
597 char const *delim
, // Delimiters.
598 char **buf
// Internal buffer.
602 // On Windows* OS there is no strtok_r() function. Let us implement it.
604 *buf
= str
; // First call, initialize buf.
606 *buf
+= strspn(*buf
, delim
); // Skip leading delimiters.
607 if (**buf
!= 0) { // Rest of the string is not yet empty.
608 token
= *buf
; // Use it as result.
609 *buf
+= strcspn(*buf
, delim
); // Skip non-delimiters.
610 if (**buf
!= 0) { // Rest of the string is not yet empty.
611 **buf
= 0; // Terminate token here.
612 *buf
+= 1; // Advance buf to start with the next token next time.
616 // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
617 token
= strtok_r(str
, delim
, buf
);
622 int __kmp_basic_str_to_int(char const *str
) {
628 for (t
= str
; *t
!= '\0'; ++t
) {
629 if (*t
< '0' || *t
> '9')
631 result
= (result
* 10) + (*t
- '0');
637 int __kmp_str_to_int(char const *str
, char sentinel
) {
643 for (t
= str
; *t
!= '\0'; ++t
) {
644 if (*t
< '0' || *t
> '9')
646 result
= (result
* 10) + (*t
- '0');
650 case '\0': /* the current default for no suffix is bytes */
654 case 'B': /* bytes */
659 case 'K': /* kilo-bytes */
664 case 'M': /* mega-bytes */
666 factor
= (1024 * 1024);
675 if (result
> (INT_MAX
/ factor
))
680 return (*t
!= 0 ? 0 : result
);
681 } // __kmp_str_to_int
683 /* The routine parses input string. It is expected it is a unsigned integer with
684 optional unit. Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb"
685 or "m" for megabytes, ..., "yb" or "y" for yottabytes. :-) Unit name is
686 case-insensitive. The routine returns 0 if everything is ok, or error code:
687 -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
688 value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown
689 unit *size is set to zero. */
690 void __kmp_str_to_size( // R: Error code.
691 char const *str
, // I: String of characters, unsigned number and unit ("b",
693 size_t *out
, // O: Parsed number.
694 size_t dfactor
, // I: The factor if none of the letters specified.
695 char const **error
// O: Null if everything is ok, error message otherwise.
704 KMP_DEBUG_ASSERT(str
!= NULL
);
707 while (str
[i
] == ' ' || str
[i
] == '\t') {
712 if (str
[i
] < '0' || str
[i
] > '9') {
713 *error
= KMP_I18N_STR(NotANumber
);
717 digit
= str
[i
] - '0';
718 overflow
= overflow
|| (value
> (KMP_SIZE_T_MAX
- digit
) / 10);
719 value
= (value
* 10) + digit
;
721 } while (str
[i
] >= '0' && str
[i
] <= '9');
724 while (str
[i
] == ' ' || str
[i
] == '\t') {
729 #define _case(ch, exp) \
731 case ch - ('a' - 'A'): { \
732 size_t shift = (exp)*10; \
734 if (shift < sizeof(size_t) * 8) { \
735 factor = (size_t)(1) << shift; \
741 _case('k', 1); // Kilo
742 _case('m', 2); // Mega
743 _case('g', 3); // Giga
744 _case('t', 4); // Tera
745 _case('p', 5); // Peta
746 _case('e', 6); // Exa
747 _case('z', 7); // Zetta
748 _case('y', 8); // Yotta
749 // Oops. No more units...
752 if (str
[i
] == 'b' || str
[i
] == 'B') { // Skip optional "b".
758 if (!(str
[i
] == ' ' || str
[i
] == '\t' || str
[i
] == 0)) { // Bad unit
759 *error
= KMP_I18N_STR(BadUnit
);
768 overflow
= overflow
|| (value
> (KMP_SIZE_T_MAX
/ factor
));
772 while (str
[i
] == ' ' || str
[i
] == '\t') {
777 *error
= KMP_I18N_STR(IllegalCharacters
);
782 *error
= KMP_I18N_STR(ValueTooLarge
);
783 *out
= KMP_SIZE_T_MAX
;
789 } // __kmp_str_to_size
791 void __kmp_str_to_uint( // R: Error code.
792 char const *str
, // I: String of characters, unsigned number.
793 kmp_uint64
*out
, // O: Parsed number.
794 char const **error
// O: Null if everything is ok, error message otherwise.
801 KMP_DEBUG_ASSERT(str
!= NULL
);
804 while (str
[i
] == ' ' || str
[i
] == '\t') {
809 if (str
[i
] < '0' || str
[i
] > '9') {
810 *error
= KMP_I18N_STR(NotANumber
);
814 digit
= str
[i
] - '0';
815 overflow
= overflow
|| (value
> (KMP_SIZE_T_MAX
- digit
) / 10);
816 value
= (value
* 10) + digit
;
818 } while (str
[i
] >= '0' && str
[i
] <= '9');
821 while (str
[i
] == ' ' || str
[i
] == '\t') {
826 *error
= KMP_I18N_STR(IllegalCharacters
);
831 *error
= KMP_I18N_STR(ValueTooLarge
);
832 *out
= (kmp_uint64
)-1;
838 } // __kmp_str_to_unit