1 /*
2  * kmp_str.cpp -- String manipulation routines.
3  */
4 
5 
6 //===----------------------------------------------------------------------===//
7 //
8 //                     The LLVM Compiler Infrastructure
9 //
10 // This file is dual licensed under the MIT and the University of Illinois Open
11 // Source Licenses. See LICENSE.txt for details.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 
16 #include "kmp_str.h"
17 
18 #include <stdarg.h>    // va_*
19 #include <stdio.h>     // vsnprintf()
20 #include <stdlib.h>    // malloc(), realloc()
21 
22 #include "kmp.h"
23 #include "kmp_i18n.h"
24 
25 /*
26     ------------------------------------------------------------------------------------------------
27     String buffer.
28     ------------------------------------------------------------------------------------------------
29 
30     Usage:
31 
32         // Declare buffer and initialize it.
33         kmp_str_buf_t  buffer;
34 	__kmp_str_buf_init( & buffer );
35 
36         // Print to buffer.
37         __kmp_str_buf_print( & buffer, "Error in file \"%s\" line %d\n", "foo.c", 12 );
38         __kmp_str_buf_print( & buffer, "    <%s>\n", line );
39 
40         // Use buffer contents. buffer.str is a pointer to data, buffer.used is a number of printed
41         // characters (not including terminating zero).
42         write( fd, buffer.str, buffer.used );
43 
44         // Free buffer.
45         __kmp_str_buf_free( & buffer );
46 
47         // Alternatively, you can detach allocated memory from buffer:
48         __kmp_str_buf_detach( & buffer );
49         return buffer.str;    // That memory should be freed eventually.
50 
51 
52     Notes:
53 
54         * Buffer users may use buffer.str and buffer.used. Users should not change any fields of
55           buffer directly.
56 
57         * buffer.str is never NULL. If buffer is empty, buffer.str points to empty string ("").
58 
59         * For performance reasons, buffer uses stack memory (buffer.bulk) first. If stack memory is
60           exhausted, buffer allocates memory on heap by malloc(), and reallocates it by realloc()
61           as amount of used memory grows.
62 
63         * Buffer doubles amount of allocated memory each time it is exhausted.
64 
65     ------------------------------------------------------------------------------------------------
66 */
67 
68 // TODO: __kmp_str_buf_print() can use thread local memory allocator.
69 
70 #define KMP_STR_BUF_INVARIANT( b )                                                                \
71     {                                                                                             \
72         KMP_DEBUG_ASSERT( (b)->str != NULL );                                                     \
73         KMP_DEBUG_ASSERT( (b)->size >= sizeof( (b)->bulk ) );                                     \
74         KMP_DEBUG_ASSERT( (b)->size % sizeof( (b)->bulk ) == 0 );                                 \
75         KMP_DEBUG_ASSERT( (unsigned)(b)->used < (b)->size );                                      \
76         KMP_DEBUG_ASSERT( (b)->size == sizeof( (b)->bulk ) ? (b)->str == & (b)->bulk[ 0 ] : 1 );  \
77         KMP_DEBUG_ASSERT( (b)->size > sizeof( (b)->bulk ) ? (b)->str != & (b)->bulk[ 0 ] : 1 );   \
78     }
79 
80 void
81  __kmp_str_buf_clear(
82      kmp_str_buf_t * buffer
83 ) {
84     KMP_STR_BUF_INVARIANT( buffer );
85     if ( buffer->used > 0 ) {
86         buffer->used = 0;
87         buffer->str[ 0 ] = 0;
88     }; // if
89     KMP_STR_BUF_INVARIANT( buffer );
90 } // __kmp_str_buf_clear
91 
92 
93 void
94 __kmp_str_buf_reserve(
95     kmp_str_buf_t * buffer,
96     int             size
97 ) {
98 
99     KMP_STR_BUF_INVARIANT( buffer );
100     KMP_DEBUG_ASSERT( size >= 0 );
101 
102     if ( buffer->size < (unsigned int)size ) {
103 
104         // Calculate buffer size.
105         do {
106             buffer->size *= 2;
107         } while ( buffer->size < (unsigned int)size );
108 
109         // Enlarge buffer.
110         if ( buffer->str == & buffer->bulk[ 0 ] ) {
111             buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size );
112             if ( buffer->str == NULL ) {
113 		KMP_FATAL( MemoryAllocFailed );
114             }; // if
115             KMP_MEMCPY_S( buffer->str, buffer->size, buffer->bulk, buffer->used + 1 );
116         } else {
117             buffer->str = (char *) KMP_INTERNAL_REALLOC( buffer->str, buffer->size );
118             if ( buffer->str == NULL ) {
119 		KMP_FATAL( MemoryAllocFailed );
120             }; // if
121         }; // if
122 
123     }; // if
124 
125     KMP_DEBUG_ASSERT( buffer->size > 0 );
126     KMP_DEBUG_ASSERT( buffer->size >= (unsigned)size );
127     KMP_STR_BUF_INVARIANT( buffer );
128 
129 } // __kmp_str_buf_reserve
130 
131 
132 void
133 __kmp_str_buf_detach(
134     kmp_str_buf_t *  buffer
135 ) {
136 
137     KMP_STR_BUF_INVARIANT( buffer );
138 
139     // If internal bulk is used, allocate memory and copy it.
140     if ( buffer->size <= sizeof( buffer->bulk ) ) {
141         buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size );
142         if ( buffer->str == NULL ) {
143 		KMP_FATAL( MemoryAllocFailed );
144         }; // if
145         KMP_MEMCPY_S( buffer->str, buffer->size, buffer->bulk, buffer->used + 1 );
146     }; // if
147 
148 } // __kmp_str_buf_detach
149 
150 
151 void
152 __kmp_str_buf_free(
153     kmp_str_buf_t * buffer
154 ) {
155     KMP_STR_BUF_INVARIANT( buffer );
156     if ( buffer->size > sizeof( buffer->bulk ) ) {
157         KMP_INTERNAL_FREE( buffer->str );
158     }; // if
159     buffer->str  = buffer->bulk;
160     buffer->size = sizeof( buffer->bulk );
161     buffer->used = 0;
162     KMP_STR_BUF_INVARIANT( buffer );
163 } // __kmp_str_buf_free
164 
165 
166 void
167 __kmp_str_buf_cat(
168     kmp_str_buf_t * buffer,
169     char const *    str,
170     int             len
171 ) {
172     KMP_STR_BUF_INVARIANT( buffer );
173     KMP_DEBUG_ASSERT( str != NULL );
174     KMP_DEBUG_ASSERT( len >= 0 );
175     __kmp_str_buf_reserve( buffer, buffer->used + len + 1 );
176     KMP_MEMCPY( buffer->str + buffer->used, str, len );
177     buffer->str[ buffer->used + len ] = 0;
178     buffer->used += len;
179     KMP_STR_BUF_INVARIANT( buffer );
180 } // __kmp_str_buf_cat
181 
182 
183 void
184 __kmp_str_buf_vprint(
185     kmp_str_buf_t *  buffer,
186     char const *     format,
187     va_list          args
188 ) {
189 
190     KMP_STR_BUF_INVARIANT( buffer );
191 
192     for ( ; ; ) {
193 
194         int const free = buffer->size - buffer->used;
195         int       rc;
196         int       size;
197 
198         // Try to format string.
199         {
200             /*
201                 On Linux* OS Intel(R) 64, vsnprintf() modifies args argument, so vsnprintf() crashes if it
202                 is called for the second time with the same args. To prevent the crash, we have to
203                 pass a fresh intact copy of args to vsnprintf() on each iteration.
204 
205                 Unfortunately, standard va_copy() macro is not available on Windows* OS. However, it
206                 seems vsnprintf() does not modify args argument on Windows* OS.
207             */
208 
209             #if ! KMP_OS_WINDOWS
210                 va_list _args;
211                 __va_copy( _args, args );  // Make copy of args.
212                 #define args _args         // Substitute args with its copy, _args.
213             #endif // KMP_OS_WINDOWS
214             rc = KMP_VSNPRINTF( buffer->str + buffer->used, free, format, args );
215             #if ! KMP_OS_WINDOWS
216                 #undef args                // Remove substitution.
217                 va_end( _args );
218             #endif // KMP_OS_WINDOWS
219         }
220 
221         // No errors, string has been formatted.
222         if ( rc >= 0 && rc < free ) {
223             buffer->used += rc;
224             break;
225         }; // if
226 
227         // Error occurred, buffer is too small.
228         if ( rc >= 0 ) {
229             // C99-conforming implementation of vsnprintf returns required buffer size.
230             size = buffer->used + rc + 1;
231         } else {
232             // Older implementations just return -1. Double buffer size.
233             size = buffer->size * 2;
234         }; // if
235 
236         // Enlarge buffer.
237         __kmp_str_buf_reserve( buffer, size );
238 
239         // And try again.
240 
241     }; // forever
242 
243     KMP_DEBUG_ASSERT( buffer->size > 0 );
244     KMP_STR_BUF_INVARIANT( buffer );
245 
246 } // __kmp_str_buf_vprint
247 
248 
249 void
250 __kmp_str_buf_print(
251     kmp_str_buf_t *  buffer,
252     char const *     format,
253     ...
254 ) {
255 
256     va_list args;
257     va_start( args, format );
258     __kmp_str_buf_vprint( buffer, format, args );
259     va_end( args );
260 
261 } // __kmp_str_buf_print
262 
263 
264 /*
265     The function prints specified size to buffer. Size is expressed using biggest possible unit, for
266     example 1024 is printed as "1k".
267 */
268 
269 void
270 __kmp_str_buf_print_size(
271     kmp_str_buf_t * buf,
272     size_t          size
273 ) {
274 
275     char const * names[] = { "", "k", "M", "G", "T", "P", "E", "Z", "Y" };
276     int const    units   = sizeof( names ) / sizeof( char const * );
277     int          u       = 0;
278     if ( size > 0 ) {
279         while ( ( size % 1024 == 0 ) && ( u + 1 < units ) ) {
280             size = size / 1024;
281             ++ u;
282         }; // while
283     }; // if
284 
285     __kmp_str_buf_print( buf, "%" KMP_SIZE_T_SPEC "%s", size, names[ u ] );
286 
287 } // __kmp_str_buf_print_size
288 
289 
290 void
291 __kmp_str_fname_init(
292     kmp_str_fname_t * fname,
293     char const *      path
294 ) {
295 
296     fname->path = NULL;
297     fname->dir  = NULL;
298     fname->base = NULL;
299 
300     if ( path != NULL ) {
301         char * slash = NULL;    // Pointer to the last character of dir.
302         char * base  = NULL;    // Pointer to the beginning of basename.
303         fname->path = __kmp_str_format( "%s", path );
304             // Original code used strdup() function to copy a string, but on Windows* OS Intel(R) 64 it
305             // causes assertioon id debug heap, so I had to replace strdup with __kmp_str_format().
306         if ( KMP_OS_WINDOWS ) {
307             __kmp_str_replace( fname->path, '\\', '/' );
308         }; // if
309         fname->dir = __kmp_str_format( "%s", fname->path );
310         slash = strrchr( fname->dir, '/' );
311         if ( KMP_OS_WINDOWS && slash == NULL ) {           // On Windows* OS, if slash not found,
312             char first = TOLOWER( fname->dir[ 0 ] );     // look for drive.
313             if ( 'a' <= first && first <= 'z' && fname->dir[ 1 ] == ':' ) {
314                 slash = & fname->dir[ 1 ];
315             }; // if
316         }; // if
317         base = ( slash == NULL ? fname->dir : slash + 1 );
318         fname->base = __kmp_str_format( "%s", base );    // Copy basename
319         * base = 0;                    // and truncate dir.
320     }; // if
321 
322 } // kmp_str_fname_init
323 
324 
325 void
326 __kmp_str_fname_free(
327     kmp_str_fname_t * fname
328 ) {
329     __kmp_str_free( (char const **)( & fname->path ) );
330     __kmp_str_free( (char const **)( & fname->dir  ) );
331     __kmp_str_free( (char const **)( & fname->base ) );
332 } // kmp_str_fname_free
333 
334 
335 int
336 __kmp_str_fname_match(
337     kmp_str_fname_t const * fname,
338     char const *            pattern
339 ) {
340 
341     int dir_match  = 1;
342     int base_match = 1;
343 
344     if ( pattern != NULL ) {
345         kmp_str_fname_t ptrn;
346         __kmp_str_fname_init( & ptrn, pattern );
347         dir_match =
348             strcmp( ptrn.dir, "*/" ) == 0
349             ||
350             ( fname->dir != NULL && __kmp_str_eqf( fname->dir, ptrn.dir ) );
351         base_match =
352             strcmp( ptrn.base, "*" ) == 0
353             ||
354             ( fname->base != NULL && __kmp_str_eqf( fname->base, ptrn.base ) );
355         __kmp_str_fname_free( & ptrn );
356     }; // if
357 
358     return dir_match && base_match;
359 
360 } // __kmp_str_fname_match
361 
362 
363 kmp_str_loc_t
364 __kmp_str_loc_init(
365     char const * psource,
366     int          init_fname
367 ) {
368 
369     kmp_str_loc_t loc;
370 
371     loc._bulk = NULL;
372     loc.file  = NULL;
373     loc.func  = NULL;
374     loc.line  = 0;
375     loc.col   = 0;
376 
377     if ( psource != NULL ) {
378 
379         char * str   = NULL;
380         char * dummy = NULL;
381         char * line  = NULL;
382         char * col   = NULL;
383 
384         // Copy psource to keep it intact.
385         loc._bulk = __kmp_str_format( "%s", psource );
386 
387         // Parse psource string: ";file;func;line;col;;"
388         str = loc._bulk;
389         __kmp_str_split( str, ';', & dummy,    & str );
390         __kmp_str_split( str, ';', & loc.file, & str );
391         __kmp_str_split( str, ';', & loc.func, & str );
392         __kmp_str_split( str, ';', & line,     & str );
393         __kmp_str_split( str, ';', & col,      & str );
394 
395         // Convert line and col into numberic values.
396         if ( line != NULL ) {
397             loc.line = atoi( line );
398             if ( loc.line < 0 ) {
399                 loc.line = 0;
400             }; // if
401         }; // if
402         if ( col != NULL ) {
403             loc.col = atoi( col );
404             if ( loc.col < 0 ) {
405                 loc.col = 0;
406             }; // if
407         }; // if
408 
409     }; // if
410 
411     __kmp_str_fname_init( & loc.fname, init_fname ? loc.file : NULL );
412 
413     return loc;
414 
415 } // kmp_str_loc_init
416 
417 
418 void
419 __kmp_str_loc_free(
420     kmp_str_loc_t * loc
421 ) {
422     __kmp_str_fname_free( & loc->fname );
423     __kmp_str_free((const char **) &(loc->_bulk));
424     loc->file  = NULL;
425     loc->func  = NULL;
426 } // kmp_str_loc_free
427 
428 
429 
430 /*
431     This function is intended to compare file names. On Windows* OS file names are case-insensitive,
432     so functions performs case-insensitive comparison. On Linux* OS it performs case-sensitive
433     comparison.
434     Note: The function returns *true* if strings are *equal*.
435 */
436 
437 int
438 __kmp_str_eqf(         // True, if strings are equal, false otherwise.
439     char const * lhs,  // First string.
440     char const * rhs   // Second string.
441 ) {
442     int result;
443     #if KMP_OS_WINDOWS
444         result = ( _stricmp( lhs, rhs ) == 0 );
445     #else
446         result = ( strcmp( lhs, rhs ) == 0 );
447     #endif
448     return result;
449 } // __kmp_str_eqf
450 
451 
452 /*
453     This function is like sprintf, but it *allocates* new buffer, which must be freed eventually by
454     __kmp_str_free(). The function is very convenient for constructing strings, it successfully
455     replaces strdup(), strcat(), it frees programmer from buffer allocations and helps to avoid
456     buffer overflows. Examples:
457 
458         str = __kmp_str_format( "%s", orig );              // strdup(), do not care about buffer size.
459         __kmp_str_free( & str );
460         str = __kmp_str_format( "%s%s", orig1, orig2 );    // strcat(), do not care about buffer size.
461         __kmp_str_free( & str );
462         str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
463         __kmp_str_free( & str );
464 
465     Performance note:
466         This function allocates memory with malloc() calls, so do not call it from
467         performance-critical code. In performance-critical code consider using kmp_str_buf_t
468         instead, since it uses stack-allocated buffer for short strings.
469 
470     Why does this function use malloc()?
471         1. __kmp_allocate() returns cache-aligned memory allocated with malloc(). There are no
472            reasons in using __kmp_allocate() for strings due to extra overhead while cache-aligned
473            memory is not necessary.
474         2. __kmp_thread_malloc() cannot be used because it requires pointer to thread structure.
475            We need to perform string operations during library startup (for example, in
476            __kmp_register_library_startup()) when no thread structures are allocated yet.
477     So standard malloc() is the only available option.
478 */
479 
480 char *
481 __kmp_str_format(           // Allocated string.
482     char const * format,    // Format string.
483     ...                     // Other parameters.
484 ) {
485 
486     va_list args;
487     int     size   = 512;
488     char *  buffer = NULL;
489     int     rc;
490 
491     // Allocate buffer.
492     buffer = (char *) KMP_INTERNAL_MALLOC( size );
493     if ( buffer == NULL ) {
494 	KMP_FATAL( MemoryAllocFailed );
495     }; // if
496 
497     for ( ; ; ) {
498 
499         // Try to format string.
500         va_start( args, format );
501         rc = KMP_VSNPRINTF( buffer, size, format, args );
502         va_end( args );
503 
504         // No errors, string has been formatted.
505         if ( rc >= 0 && rc < size ) {
506             break;
507         }; // if
508 
509         // Error occurred, buffer is too small.
510         if ( rc >= 0 ) {
511             // C99-conforming implementation of vsnprintf returns required buffer size.
512             size = rc + 1;
513         } else {
514             // Older implementations just return -1.
515             size = size * 2;
516         }; // if
517 
518         // Enlarge buffer and try again.
519         buffer = (char *) KMP_INTERNAL_REALLOC( buffer, size );
520         if ( buffer == NULL ) {
521     	    KMP_FATAL( MemoryAllocFailed );
522         }; // if
523 
524     }; // forever
525 
526     return buffer;
527 
528 } // func __kmp_str_format
529 
530 
531 void
532 __kmp_str_free(
533     char const * * str
534 ) {
535     KMP_DEBUG_ASSERT( str != NULL );
536     KMP_INTERNAL_FREE( (void *) * str );
537     * str = NULL;
538 } // func __kmp_str_free
539 
540 
541 /* If len is zero, returns true iff target and data have exact case-insensitive match.
542    If len is negative, returns true iff target is a case-insensitive substring of data.
543    If len is positive, returns true iff target is a case-insensitive substring of data or
544      vice versa, and neither is shorter than len.
545 */
546 int
547 __kmp_str_match(
548     char const * target,
549     int          len,
550     char const * data
551 ) {
552     int i;
553     if ( target == NULL || data == NULL ) {
554         return FALSE;
555     }; // if
556     for ( i = 0; target[i] && data[i]; ++ i ) {
557         if ( TOLOWER( target[i] ) != TOLOWER( data[i] ) ) {
558             return FALSE;
559         }; // if
560     }; // for i
561     return ( ( len > 0 ) ? i >= len : ( ! target[i] && ( len || ! data[i] ) ) );
562 } // __kmp_str_match
563 
564 
565 int
566 __kmp_str_match_false( char const * data ) {
567     int result =
568         __kmp_str_match( "false",   1, data ) ||
569         __kmp_str_match( "off",     2, data ) ||
570         __kmp_str_match( "0",       1, data ) ||
571         __kmp_str_match( ".false.", 2, data ) ||
572         __kmp_str_match( ".f.",     2, data ) ||
573         __kmp_str_match( "no",      1, data );
574     return result;
575 } // __kmp_str_match_false
576 
577 
578 int
579 __kmp_str_match_true( char const * data ) {
580     int result =
581         __kmp_str_match( "true",   1, data ) ||
582         __kmp_str_match( "on",     2, data ) ||
583         __kmp_str_match( "1",      1, data ) ||
584         __kmp_str_match( ".true.", 2, data ) ||
585         __kmp_str_match( ".t.",    2, data ) ||
586         __kmp_str_match( "yes",    1, data );
587     return result;
588 } // __kmp_str_match_true
589 
590 void
591 __kmp_str_replace(
592     char * str,
593     char   search_for,
594     char   replace_with
595 ) {
596 
597     char * found = NULL;
598 
599     found = strchr( str, search_for );
600     while ( found ) {
601         * found = replace_with;
602         found = strchr( found + 1, search_for );
603     }; // while
604 
605 } // __kmp_str_replace
606 
607 
608 void
609 __kmp_str_split(
610     char *  str,    // I: String to split.
611     char    delim,  // I: Character to split on.
612     char ** head,   // O: Pointer to head (may be NULL).
613     char ** tail    // O: Pointer to tail (may be NULL).
614 ) {
615     char * h = str;
616     char * t = NULL;
617     if ( str != NULL ) {
618         char * ptr = strchr( str, delim );
619         if ( ptr != NULL ) {
620             * ptr  = 0;
621             t = ptr + 1;
622         }; // if
623     }; // if
624     if ( head != NULL ) {
625         * head = h;
626     }; // if
627     if ( tail != NULL ) {
628         * tail = t;
629     }; // if
630 } // __kmp_str_split
631 
632 /*
633     strtok_r() is not available on Windows* OS. This function reimplements strtok_r().
634 */
635 char *
636 __kmp_str_token(
637     char *       str,   // String to split into tokens. Note: String *is* modified!
638     char const * delim, // Delimiters.
639     char **      buf    // Internal buffer.
640 ) {
641     char * token = NULL;
642     #if KMP_OS_WINDOWS
643         // On Windows* OS there is no strtok_r() function. Let us implement it.
644         if ( str != NULL ) {
645             * buf = str;                       // First call, initialize buf.
646         }; // if
647         * buf += strspn( * buf, delim );       // Skip leading delimiters.
648         if ( ** buf != 0 ) {                   // Rest of the string is not yet empty.
649             token = * buf;                     // Use it as result.
650             * buf += strcspn( * buf, delim );  // Skip non-delimiters.
651             if ( ** buf != 0 ) {               // Rest of the string is not yet empty.
652                 ** buf = 0;                    // Terminate token here.
653                 * buf += 1;                    // Advance buf to start with the next token next time.
654             }; // if
655         }; // if
656     #else
657         // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
658         token = strtok_r( str, delim, buf );
659     #endif
660     return token;
661 }; // __kmp_str_token
662 
663 
664 int
665 __kmp_str_to_int(
666     char const * str,
667     char         sentinel
668 ) {
669     int result, factor;
670     char const * t;
671 
672     result = 0;
673 
674     for (t = str; *t != '\0'; ++t) {
675         if (*t < '0' || *t > '9')
676             break;
677         result = (result * 10) + (*t - '0');
678     }
679 
680     switch (*t) {
681     case '\0':          /* the current default for no suffix is bytes */
682 	factor = 1;
683         break;
684     case 'b': case 'B': /* bytes */
685 	++t;
686 	factor = 1;
687         break;
688     case 'k': case 'K': /* kilo-bytes */
689 	++t;
690 	factor = 1024;
691         break;
692     case 'm': case 'M': /* mega-bytes */
693 	++t;
694 	factor = (1024 * 1024);
695         break;
696     default:
697 	if(*t != sentinel)
698 	    return (-1);
699 	t = "";
700 	factor = 1;
701     }
702 
703     if (result > (INT_MAX / factor))
704 	result = INT_MAX;
705     else
706 	result *= factor;
707 
708     return (*t != 0 ? 0 : result);
709 
710 } // __kmp_str_to_int
711 
712 
713 /*
714     The routine parses input string. It is expected it is a unsigned integer with optional unit.
715     Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb" or "m" for megabytes, ..., "yb"
716     or "y" for yottabytes. :-) Unit name is case-insensitive. The routine returns 0 if everything is
717     ok, or error code: -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
718     value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown unit *size is set
719     to zero.
720 */
721 void
722 __kmp_str_to_size(         // R: Error code.
723     char const *   str,    // I: String of characters, unsigned number and unit ("b", "kb", etc).
724     size_t *       out,    // O: Parsed number.
725     size_t         dfactor, // I: The factor if none of the letters specified.
726     char const * * error   // O: Null if everything is ok, error message otherwise.
727 ) {
728 
729     size_t value    = 0;
730     size_t factor   = 0;
731     int    overflow = 0;
732     int    i        = 0;
733     int    digit;
734 
735 
736     KMP_DEBUG_ASSERT( str != NULL );
737 
738     // Skip spaces.
739     while ( str[ i ] == ' ' || str[ i ] == '\t') {
740         ++ i;
741     }; // while
742 
743     // Parse number.
744     if ( str[ i ] < '0' || str[ i ] > '9' ) {
745         * error = KMP_I18N_STR( NotANumber );
746         return;
747     }; // if
748     do {
749         digit = str[ i ] - '0';
750         overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
751         value = ( value * 10 ) + digit;
752         ++ i;
753     } while ( str[ i ] >= '0' && str[ i ] <= '9' );
754 
755     // Skip spaces.
756     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
757         ++ i;
758     }; // while
759 
760     // Parse unit.
761     #define _case( ch, exp )                            \
762         case ch :                                       \
763         case ch - ( 'a' - 'A' ) : {                     \
764             size_t shift = (exp) * 10;                  \
765             ++ i;                                       \
766             if ( shift < sizeof( size_t ) * 8 ) {       \
767                 factor = (size_t)( 1 ) << shift;        \
768             } else {                                    \
769                 overflow = 1;                           \
770             };                                          \
771         } break;
772     switch ( str[ i ] ) {
773         _case( 'k', 1 ); // Kilo
774         _case( 'm', 2 ); // Mega
775         _case( 'g', 3 ); // Giga
776         _case( 't', 4 ); // Tera
777         _case( 'p', 5 ); // Peta
778         _case( 'e', 6 ); // Exa
779         _case( 'z', 7 ); // Zetta
780         _case( 'y', 8 ); // Yotta
781         // Oops. No more units...
782     }; // switch
783     #undef _case
784     if ( str[ i ] == 'b' || str[ i ] == 'B' ) {    // Skip optional "b".
785 	if ( factor == 0 ) {
786 	    factor = 1;
787 	}
788         ++ i;
789     }; // if
790     if ( ! ( str[ i ] == ' ' || str[ i ] == '\t' || str[ i ] == 0 ) ) { // Bad unit
791         * error = KMP_I18N_STR( BadUnit );
792         return;
793     }; // if
794 
795     if ( factor == 0 ) {
796 	factor = dfactor;
797     }
798 
799     // Apply factor.
800     overflow = overflow || ( value > ( KMP_SIZE_T_MAX / factor ) );
801     value *= factor;
802 
803     // Skip spaces.
804     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
805         ++ i;
806     }; // while
807 
808     if ( str[ i ] != 0 ) {
809         * error = KMP_I18N_STR( IllegalCharacters );
810         return;
811     }; // if
812 
813     if ( overflow ) {
814         * error = KMP_I18N_STR( ValueTooLarge );
815         * out = KMP_SIZE_T_MAX;
816         return;
817     }; // if
818 
819     * error = NULL;
820     * out = value;
821 
822 } // __kmp_str_to_size
823 
824 
825 void
826 __kmp_str_to_uint(         // R: Error code.
827     char const *   str,    // I: String of characters, unsigned number.
828     kmp_uint64 *   out,    // O: Parsed number.
829     char const * * error   // O: Null if everything is ok, error message otherwise.
830 ) {
831 
832     size_t value    = 0;
833     int    overflow = 0;
834     int    i        = 0;
835     int    digit;
836 
837 
838     KMP_DEBUG_ASSERT( str != NULL );
839 
840     // Skip spaces.
841     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
842         ++ i;
843     }; // while
844 
845     // Parse number.
846     if ( str[ i ] < '0' || str[ i ] > '9' ) {
847         * error = KMP_I18N_STR( NotANumber );
848         return;
849     }; // if
850     do {
851         digit = str[ i ] - '0';
852         overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
853         value = ( value * 10 ) + digit;
854         ++ i;
855     } while ( str[ i ] >= '0' && str[ i ] <= '9' );
856 
857     // Skip spaces.
858     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
859         ++ i;
860     }; // while
861 
862     if ( str[ i ] != 0 ) {
863         * error = KMP_I18N_STR( IllegalCharacters );
864         return;
865     }; // if
866 
867     if ( overflow ) {
868         * error = KMP_I18N_STR( ValueTooLarge );
869         * out = (kmp_uint64) -1;
870         return;
871     }; // if
872 
873     * error = NULL;
874     * out = value;
875 
876 } // __kmp_str_to_unit
877 
878 
879 
880 // end of file //
881