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