blob: b5f700551e486d5cfd8e8a7535accabbde3d9839 [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
2 * kmp_str.c -- String manipulation routines.
Jim Cownie5e8470a2013-09-27 10:38:44 +00003 */
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
80void
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
93void
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
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000115 KMP_MEMCPY_S( buffer->str, buffer->size, buffer->bulk, buffer->used + 1 );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000116 } 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
132void
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
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000145 KMP_MEMCPY_S( buffer->str, buffer->size, buffer->bulk, buffer->used + 1 );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000146 }; // if
147
148} // __kmp_str_buf_detach
149
150
151void
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
166void
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 );
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000176 KMP_MEMCPY( buffer->str + buffer->used, str, len );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000177 buffer->str[ buffer->used + len ] = 0;
178 buffer->used += len;
179 KMP_STR_BUF_INVARIANT( buffer );
180} // __kmp_str_buf_cat
181
182
183void
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
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000214 rc = KMP_VSNPRINTF( buffer->str + buffer->used, free, format, args );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000215 #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
Alp Toker8f2d3f02014-02-24 10:40:15 +0000227 // Error occurred, buffer is too small.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000228 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
249void
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
269void
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;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000278 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
290void
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
325void
326__kmp_str_fname_free(
327 kmp_str_fname_t * fname
328) {
Jim Cownie181b4bb2013-12-23 17:28:57 +0000329 __kmp_str_free( (char const **)( & fname->path ) );
330 __kmp_str_free( (char const **)( & fname->dir ) );
331 __kmp_str_free( (char const **)( & fname->base ) );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000332} // kmp_str_fname_free
333
334
335int
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
363kmp_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
418void
419__kmp_str_loc_free(
420 kmp_str_loc_t * loc
421) {
422 __kmp_str_fname_free( & loc->fname );
423 KMP_INTERNAL_FREE( loc->_bulk );
424 loc->_bulk = NULL;
425 loc->file = NULL;
426 loc->func = NULL;
427} // kmp_str_loc_free
428
429
430
431/*
432 This function is intended to compare file names. On Windows* OS file names are case-insensitive,
433 so functions performs case-insensitive comparison. On Linux* OS it performs case-sensitive
434 comparison.
435 Note: The function returns *true* if strings are *equal*.
436*/
437
438int
439__kmp_str_eqf( // True, if strings are equal, false otherwise.
440 char const * lhs, // First string.
441 char const * rhs // Second string.
442) {
443 int result;
444 #if KMP_OS_WINDOWS
445 result = ( _stricmp( lhs, rhs ) == 0 );
446 #else
447 result = ( strcmp( lhs, rhs ) == 0 );
448 #endif
449 return result;
450} // __kmp_str_eqf
451
452
453/*
454 This function is like sprintf, but it *allocates* new buffer, which must be freed eventually by
455 __kmp_str_free(). The function is very convenient for constructing strings, it successfully
456 replaces strdup(), strcat(), it frees programmer from buffer allocations and helps to avoid
457 buffer overflows. Examples:
458
459 str = __kmp_str_format( "%s", orig ); // strdup(), do not care about buffer size.
460 __kmp_str_free( & str );
461 str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), do not care about buffer size.
462 __kmp_str_free( & str );
463 str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
464 __kmp_str_free( & str );
465
466 Performance note:
467 This function allocates memory with malloc() calls, so do not call it from
468 performance-critical code. In performance-critical code consider using kmp_str_buf_t
469 instead, since it uses stack-allocated buffer for short strings.
470
471 Why does this function use malloc()?
472 1. __kmp_allocate() returns cache-aligned memory allocated with malloc(). There are no
473 reasons in using __kmp_allocate() for strings due to extra overhead while cache-aligned
474 memory is not necessary.
475 2. __kmp_thread_malloc() cannot be used because it requires pointer to thread structure.
476 We need to perform string operations during library startup (for example, in
477 __kmp_register_library_startup()) when no thread structures are allocated yet.
478 So standard malloc() is the only available option.
479*/
480
481// TODO: Find and replace all regular free() with __kmp_str_free().
482
483char *
484__kmp_str_format( // Allocated string.
485 char const * format, // Format string.
486 ... // Other parameters.
487) {
488
489 va_list args;
490 int size = 512;
491 char * buffer = NULL;
492 int rc;
493
494 // Allocate buffer.
495 buffer = (char *) KMP_INTERNAL_MALLOC( size );
496 if ( buffer == NULL ) {
497 KMP_FATAL( MemoryAllocFailed );
498 }; // if
499
500 for ( ; ; ) {
501
502 // Try to format string.
503 va_start( args, format );
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000504 rc = KMP_VSNPRINTF( buffer, size, format, args );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000505 va_end( args );
506
507 // No errors, string has been formatted.
508 if ( rc >= 0 && rc < size ) {
509 break;
510 }; // if
511
Alp Toker8f2d3f02014-02-24 10:40:15 +0000512 // Error occurred, buffer is too small.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000513 if ( rc >= 0 ) {
514 // C99-conforming implementation of vsnprintf returns required buffer size.
515 size = rc + 1;
516 } else {
517 // Older implementations just return -1.
518 size = size * 2;
519 }; // if
520
521 // Enlarge buffer and try again.
522 buffer = (char *) KMP_INTERNAL_REALLOC( buffer, size );
523 if ( buffer == NULL ) {
524 KMP_FATAL( MemoryAllocFailed );
525 }; // if
526
527 }; // forever
528
529 return buffer;
530
531} // func __kmp_str_format
532
533
534void
535__kmp_str_free(
536 char const * * str
537) {
538 KMP_DEBUG_ASSERT( str != NULL );
539 KMP_INTERNAL_FREE( (void *) * str );
540 * str = NULL;
541} // func __kmp_str_free
542
543
544/* If len is zero, returns true iff target and data have exact case-insensitive match.
545 If len is negative, returns true iff target is a case-insensitive substring of data.
546 If len is positive, returns true iff target is a case-insensitive substring of data or
547 vice versa, and neither is shorter than len.
548*/
549int
550__kmp_str_match(
551 char const * target,
552 int len,
553 char const * data
554) {
555 int i;
556 if ( target == NULL || data == NULL ) {
557 return FALSE;
558 }; // if
559 for ( i = 0; target[i] && data[i]; ++ i ) {
560 if ( TOLOWER( target[i] ) != TOLOWER( data[i] ) ) {
561 return FALSE;
562 }; // if
563 }; // for i
564 return ( ( len > 0 ) ? i >= len : ( ! target[i] && ( len || ! data[i] ) ) );
565} // __kmp_str_match
566
567
568int
569__kmp_str_match_false( char const * data ) {
570 int result =
571 __kmp_str_match( "false", 1, data ) ||
572 __kmp_str_match( "off", 2, data ) ||
573 __kmp_str_match( "0", 1, data ) ||
574 __kmp_str_match( ".false.", 2, data ) ||
575 __kmp_str_match( ".f.", 2, data ) ||
576 __kmp_str_match( "no", 1, data );
577 return result;
578} // __kmp_str_match_false
579
580
581int
582__kmp_str_match_true( char const * data ) {
583 int result =
584 __kmp_str_match( "true", 1, data ) ||
585 __kmp_str_match( "on", 2, data ) ||
586 __kmp_str_match( "1", 1, data ) ||
587 __kmp_str_match( ".true.", 2, data ) ||
588 __kmp_str_match( ".t.", 2, data ) ||
589 __kmp_str_match( "yes", 1, data );
590 return result;
591} // __kmp_str_match_true
592
593void
594__kmp_str_replace(
595 char * str,
596 char search_for,
597 char replace_with
598) {
599
600 char * found = NULL;
601
602 found = strchr( str, search_for );
603 while ( found ) {
604 * found = replace_with;
605 found = strchr( found + 1, search_for );
606 }; // while
607
608} // __kmp_str_replace
609
610
611void
612__kmp_str_split(
613 char * str, // I: String to split.
614 char delim, // I: Character to split on.
615 char ** head, // O: Pointer to head (may be NULL).
616 char ** tail // O: Pointer to tail (may be NULL).
617) {
618 char * h = str;
619 char * t = NULL;
620 if ( str != NULL ) {
621 char * ptr = strchr( str, delim );
622 if ( ptr != NULL ) {
623 * ptr = 0;
624 t = ptr + 1;
625 }; // if
626 }; // if
627 if ( head != NULL ) {
628 * head = h;
629 }; // if
630 if ( tail != NULL ) {
631 * tail = t;
632 }; // if
633} // __kmp_str_split
634
635/*
636 strtok_r() is not available on Windows* OS. This function reimplements strtok_r().
637*/
638char *
639__kmp_str_token(
640 char * str, // String to split into tokens. Note: String *is* modified!
641 char const * delim, // Delimiters.
642 char ** buf // Internal buffer.
643) {
644 char * token = NULL;
645 #if KMP_OS_WINDOWS
646 // On Windows* OS there is no strtok_r() function. Let us implement it.
647 if ( str != NULL ) {
648 * buf = str; // First call, initialize buf.
649 }; // if
650 * buf += strspn( * buf, delim ); // Skip leading delimiters.
651 if ( ** buf != 0 ) { // Rest of the string is not yet empty.
652 token = * buf; // Use it as result.
653 * buf += strcspn( * buf, delim ); // Skip non-delimiters.
654 if ( ** buf != 0 ) { // Rest of the string is not yet empty.
655 ** buf = 0; // Terminate token here.
656 * buf += 1; // Advance buf to start with the next token next time.
657 }; // if
658 }; // if
659 #else
660 // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
661 token = strtok_r( str, delim, buf );
662 #endif
663 return token;
664}; // __kmp_str_token
665
666
667int
668__kmp_str_to_int(
669 char const * str,
670 char sentinel
671) {
672 int result, factor;
673 char const * t;
674
675 result = 0;
676
677 for (t = str; *t != '\0'; ++t) {
678 if (*t < '0' || *t > '9')
679 break;
680 result = (result * 10) + (*t - '0');
681 }
682
683 switch (*t) {
684 case '\0': /* the current default for no suffix is bytes */
685 factor = 1;
686 break;
687 case 'b': case 'B': /* bytes */
688 ++t;
689 factor = 1;
690 break;
691 case 'k': case 'K': /* kilo-bytes */
692 ++t;
693 factor = 1024;
694 break;
695 case 'm': case 'M': /* mega-bytes */
696 ++t;
697 factor = (1024 * 1024);
698 break;
699 default:
700 if(*t != sentinel)
701 return (-1);
702 t = "";
703 factor = 1;
704 }
705
706 if (result > (INT_MAX / factor))
707 result = INT_MAX;
708 else
709 result *= factor;
710
711 return (*t != 0 ? 0 : result);
712
713} // __kmp_str_to_int
714
715
716/*
717 The routine parses input string. It is expected it is a unsigned integer with optional unit.
718 Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb" or "m" for megabytes, ..., "yb"
719 or "y" for yottabytes. :-) Unit name is case-insensitive. The routine returns 0 if everything is
720 ok, or error code: -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
721 value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown unit *size is set
722 to zero.
723*/
724void
725__kmp_str_to_size( // R: Error code.
726 char const * str, // I: String of characters, unsigned number and unit ("b", "kb", etc).
727 size_t * out, // O: Parsed number.
728 size_t dfactor, // I: The factor if none of the letters specified.
729 char const * * error // O: Null if everything is ok, error message otherwise.
730) {
731
732 size_t value = 0;
733 size_t factor = 0;
734 int overflow = 0;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000735 int i = 0;
736 int digit;
737
738
739 KMP_DEBUG_ASSERT( str != NULL );
740
741 // Skip spaces.
742 while ( str[ i ] == ' ' || str[ i ] == '\t') {
743 ++ i;
744 }; // while
745
746 // Parse number.
747 if ( str[ i ] < '0' || str[ i ] > '9' ) {
748 * error = KMP_I18N_STR( NotANumber );
749 return;
750 }; // if
751 do {
752 digit = str[ i ] - '0';
753 overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
754 value = ( value * 10 ) + digit;
755 ++ i;
756 } while ( str[ i ] >= '0' && str[ i ] <= '9' );
757
758 // Skip spaces.
759 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
760 ++ i;
761 }; // while
762
763 // Parse unit.
764 #define _case( ch, exp ) \
765 case ch : \
766 case ch - ( 'a' - 'A' ) : { \
767 size_t shift = (exp) * 10; \
768 ++ i; \
769 if ( shift < sizeof( size_t ) * 8 ) { \
770 factor = (size_t)( 1 ) << shift; \
771 } else { \
772 overflow = 1; \
773 }; \
774 } break;
775 switch ( str[ i ] ) {
776 _case( 'k', 1 ); // Kilo
777 _case( 'm', 2 ); // Mega
778 _case( 'g', 3 ); // Giga
779 _case( 't', 4 ); // Tera
780 _case( 'p', 5 ); // Peta
781 _case( 'e', 6 ); // Exa
782 _case( 'z', 7 ); // Zetta
783 _case( 'y', 8 ); // Yotta
784 // Oops. No more units...
785 }; // switch
786 #undef _case
787 if ( str[ i ] == 'b' || str[ i ] == 'B' ) { // Skip optional "b".
788 if ( factor == 0 ) {
789 factor = 1;
790 }
791 ++ i;
792 }; // if
793 if ( ! ( str[ i ] == ' ' || str[ i ] == '\t' || str[ i ] == 0 ) ) { // Bad unit
794 * error = KMP_I18N_STR( BadUnit );
795 return;
796 }; // if
797
798 if ( factor == 0 ) {
799 factor = dfactor;
800 }
801
802 // Apply factor.
803 overflow = overflow || ( value > ( KMP_SIZE_T_MAX / factor ) );
804 value *= factor;
805
806 // Skip spaces.
807 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
808 ++ i;
809 }; // while
810
811 if ( str[ i ] != 0 ) {
812 * error = KMP_I18N_STR( IllegalCharacters );
813 return;
814 }; // if
815
816 if ( overflow ) {
817 * error = KMP_I18N_STR( ValueTooLarge );
818 * out = KMP_SIZE_T_MAX;
819 return;
820 }; // if
821
822 * error = NULL;
823 * out = value;
824
825} // __kmp_str_to_size
826
827
828void
829__kmp_str_to_uint( // R: Error code.
830 char const * str, // I: String of characters, unsigned number.
831 kmp_uint64 * out, // O: Parsed number.
832 char const * * error // O: Null if everything is ok, error message otherwise.
833) {
834
835 size_t value = 0;
836 int overflow = 0;
837 int i = 0;
838 int digit;
839
840
841 KMP_DEBUG_ASSERT( str != NULL );
842
843 // Skip spaces.
844 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
845 ++ i;
846 }; // while
847
848 // Parse number.
849 if ( str[ i ] < '0' || str[ i ] > '9' ) {
850 * error = KMP_I18N_STR( NotANumber );
851 return;
852 }; // if
853 do {
854 digit = str[ i ] - '0';
855 overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
856 value = ( value * 10 ) + digit;
857 ++ i;
858 } while ( str[ i ] >= '0' && str[ i ] <= '9' );
859
860 // Skip spaces.
861 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
862 ++ i;
863 }; // while
864
865 if ( str[ i ] != 0 ) {
866 * error = KMP_I18N_STR( IllegalCharacters );
867 return;
868 }; // if
869
870 if ( overflow ) {
871 * error = KMP_I18N_STR( ValueTooLarge );
872 * out = (kmp_uint64) -1;
873 return;
874 }; // if
875
876 * error = NULL;
877 * out = value;
878
879} // __kmp_str_to_unit
880
881
882
883// end of file //