blob: 0bcd40ccc3666c5b87001beb199713053d782976 [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;
278 int rc;
279 if ( size > 0 ) {
280 while ( ( size % 1024 == 0 ) && ( u + 1 < units ) ) {
281 size = size / 1024;
282 ++ u;
283 }; // while
284 }; // if
285
286 __kmp_str_buf_print( buf, "%" KMP_SIZE_T_SPEC "%s", size, names[ u ] );
287
288} // __kmp_str_buf_print_size
289
290
291void
292__kmp_str_fname_init(
293 kmp_str_fname_t * fname,
294 char const * path
295) {
296
297 fname->path = NULL;
298 fname->dir = NULL;
299 fname->base = NULL;
300
301 if ( path != NULL ) {
302 char * slash = NULL; // Pointer to the last character of dir.
303 char * base = NULL; // Pointer to the beginning of basename.
304 fname->path = __kmp_str_format( "%s", path );
305 // Original code used strdup() function to copy a string, but on Windows* OS Intel(R) 64 it
306 // causes assertioon id debug heap, so I had to replace strdup with __kmp_str_format().
307 if ( KMP_OS_WINDOWS ) {
308 __kmp_str_replace( fname->path, '\\', '/' );
309 }; // if
310 fname->dir = __kmp_str_format( "%s", fname->path );
311 slash = strrchr( fname->dir, '/' );
312 if ( KMP_OS_WINDOWS && slash == NULL ) { // On Windows* OS, if slash not found,
313 char first = TOLOWER( fname->dir[ 0 ] ); // look for drive.
314 if ( 'a' <= first && first <= 'z' && fname->dir[ 1 ] == ':' ) {
315 slash = & fname->dir[ 1 ];
316 }; // if
317 }; // if
318 base = ( slash == NULL ? fname->dir : slash + 1 );
319 fname->base = __kmp_str_format( "%s", base ); // Copy basename
320 * base = 0; // and truncate dir.
321 }; // if
322
323} // kmp_str_fname_init
324
325
326void
327__kmp_str_fname_free(
328 kmp_str_fname_t * fname
329) {
Jim Cownie181b4bb2013-12-23 17:28:57 +0000330 __kmp_str_free( (char const **)( & fname->path ) );
331 __kmp_str_free( (char const **)( & fname->dir ) );
332 __kmp_str_free( (char const **)( & fname->base ) );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000333} // kmp_str_fname_free
334
335
336int
337__kmp_str_fname_match(
338 kmp_str_fname_t const * fname,
339 char const * pattern
340) {
341
342 int dir_match = 1;
343 int base_match = 1;
344
345 if ( pattern != NULL ) {
346 kmp_str_fname_t ptrn;
347 __kmp_str_fname_init( & ptrn, pattern );
348 dir_match =
349 strcmp( ptrn.dir, "*/" ) == 0
350 ||
351 ( fname->dir != NULL && __kmp_str_eqf( fname->dir, ptrn.dir ) );
352 base_match =
353 strcmp( ptrn.base, "*" ) == 0
354 ||
355 ( fname->base != NULL && __kmp_str_eqf( fname->base, ptrn.base ) );
356 __kmp_str_fname_free( & ptrn );
357 }; // if
358
359 return dir_match && base_match;
360
361} // __kmp_str_fname_match
362
363
364kmp_str_loc_t
365__kmp_str_loc_init(
366 char const * psource,
367 int init_fname
368) {
369
370 kmp_str_loc_t loc;
371
372 loc._bulk = NULL;
373 loc.file = NULL;
374 loc.func = NULL;
375 loc.line = 0;
376 loc.col = 0;
377
378 if ( psource != NULL ) {
379
380 char * str = NULL;
381 char * dummy = NULL;
382 char * line = NULL;
383 char * col = NULL;
384
385 // Copy psource to keep it intact.
386 loc._bulk = __kmp_str_format( "%s", psource );
387
388 // Parse psource string: ";file;func;line;col;;"
389 str = loc._bulk;
390 __kmp_str_split( str, ';', & dummy, & str );
391 __kmp_str_split( str, ';', & loc.file, & str );
392 __kmp_str_split( str, ';', & loc.func, & str );
393 __kmp_str_split( str, ';', & line, & str );
394 __kmp_str_split( str, ';', & col, & str );
395
396 // Convert line and col into numberic values.
397 if ( line != NULL ) {
398 loc.line = atoi( line );
399 if ( loc.line < 0 ) {
400 loc.line = 0;
401 }; // if
402 }; // if
403 if ( col != NULL ) {
404 loc.col = atoi( col );
405 if ( loc.col < 0 ) {
406 loc.col = 0;
407 }; // if
408 }; // if
409
410 }; // if
411
412 __kmp_str_fname_init( & loc.fname, init_fname ? loc.file : NULL );
413
414 return loc;
415
416} // kmp_str_loc_init
417
418
419void
420__kmp_str_loc_free(
421 kmp_str_loc_t * loc
422) {
423 __kmp_str_fname_free( & loc->fname );
424 KMP_INTERNAL_FREE( loc->_bulk );
425 loc->_bulk = NULL;
426 loc->file = NULL;
427 loc->func = NULL;
428} // kmp_str_loc_free
429
430
431
432/*
433 This function is intended to compare file names. On Windows* OS file names are case-insensitive,
434 so functions performs case-insensitive comparison. On Linux* OS it performs case-sensitive
435 comparison.
436 Note: The function returns *true* if strings are *equal*.
437*/
438
439int
440__kmp_str_eqf( // True, if strings are equal, false otherwise.
441 char const * lhs, // First string.
442 char const * rhs // Second string.
443) {
444 int result;
445 #if KMP_OS_WINDOWS
446 result = ( _stricmp( lhs, rhs ) == 0 );
447 #else
448 result = ( strcmp( lhs, rhs ) == 0 );
449 #endif
450 return result;
451} // __kmp_str_eqf
452
453
454/*
455 This function is like sprintf, but it *allocates* new buffer, which must be freed eventually by
456 __kmp_str_free(). The function is very convenient for constructing strings, it successfully
457 replaces strdup(), strcat(), it frees programmer from buffer allocations and helps to avoid
458 buffer overflows. Examples:
459
460 str = __kmp_str_format( "%s", orig ); // strdup(), do not care about buffer size.
461 __kmp_str_free( & str );
462 str = __kmp_str_format( "%s%s", orig1, orig2 ); // strcat(), do not care about buffer size.
463 __kmp_str_free( & str );
464 str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
465 __kmp_str_free( & str );
466
467 Performance note:
468 This function allocates memory with malloc() calls, so do not call it from
469 performance-critical code. In performance-critical code consider using kmp_str_buf_t
470 instead, since it uses stack-allocated buffer for short strings.
471
472 Why does this function use malloc()?
473 1. __kmp_allocate() returns cache-aligned memory allocated with malloc(). There are no
474 reasons in using __kmp_allocate() for strings due to extra overhead while cache-aligned
475 memory is not necessary.
476 2. __kmp_thread_malloc() cannot be used because it requires pointer to thread structure.
477 We need to perform string operations during library startup (for example, in
478 __kmp_register_library_startup()) when no thread structures are allocated yet.
479 So standard malloc() is the only available option.
480*/
481
482// TODO: Find and replace all regular free() with __kmp_str_free().
483
484char *
485__kmp_str_format( // Allocated string.
486 char const * format, // Format string.
487 ... // Other parameters.
488) {
489
490 va_list args;
491 int size = 512;
492 char * buffer = NULL;
493 int rc;
494
495 // Allocate buffer.
496 buffer = (char *) KMP_INTERNAL_MALLOC( size );
497 if ( buffer == NULL ) {
498 KMP_FATAL( MemoryAllocFailed );
499 }; // if
500
501 for ( ; ; ) {
502
503 // Try to format string.
504 va_start( args, format );
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000505 rc = KMP_VSNPRINTF( buffer, size, format, args );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000506 va_end( args );
507
508 // No errors, string has been formatted.
509 if ( rc >= 0 && rc < size ) {
510 break;
511 }; // if
512
Alp Toker8f2d3f02014-02-24 10:40:15 +0000513 // Error occurred, buffer is too small.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000514 if ( rc >= 0 ) {
515 // C99-conforming implementation of vsnprintf returns required buffer size.
516 size = rc + 1;
517 } else {
518 // Older implementations just return -1.
519 size = size * 2;
520 }; // if
521
522 // Enlarge buffer and try again.
523 buffer = (char *) KMP_INTERNAL_REALLOC( buffer, size );
524 if ( buffer == NULL ) {
525 KMP_FATAL( MemoryAllocFailed );
526 }; // if
527
528 }; // forever
529
530 return buffer;
531
532} // func __kmp_str_format
533
534
535void
536__kmp_str_free(
537 char const * * str
538) {
539 KMP_DEBUG_ASSERT( str != NULL );
540 KMP_INTERNAL_FREE( (void *) * str );
541 * str = NULL;
542} // func __kmp_str_free
543
544
545/* If len is zero, returns true iff target and data have exact case-insensitive match.
546 If len is negative, returns true iff target is a case-insensitive substring of data.
547 If len is positive, returns true iff target is a case-insensitive substring of data or
548 vice versa, and neither is shorter than len.
549*/
550int
551__kmp_str_match(
552 char const * target,
553 int len,
554 char const * data
555) {
556 int i;
557 if ( target == NULL || data == NULL ) {
558 return FALSE;
559 }; // if
560 for ( i = 0; target[i] && data[i]; ++ i ) {
561 if ( TOLOWER( target[i] ) != TOLOWER( data[i] ) ) {
562 return FALSE;
563 }; // if
564 }; // for i
565 return ( ( len > 0 ) ? i >= len : ( ! target[i] && ( len || ! data[i] ) ) );
566} // __kmp_str_match
567
568
569int
570__kmp_str_match_false( char const * data ) {
571 int result =
572 __kmp_str_match( "false", 1, data ) ||
573 __kmp_str_match( "off", 2, data ) ||
574 __kmp_str_match( "0", 1, data ) ||
575 __kmp_str_match( ".false.", 2, data ) ||
576 __kmp_str_match( ".f.", 2, data ) ||
577 __kmp_str_match( "no", 1, data );
578 return result;
579} // __kmp_str_match_false
580
581
582int
583__kmp_str_match_true( char const * data ) {
584 int result =
585 __kmp_str_match( "true", 1, data ) ||
586 __kmp_str_match( "on", 2, data ) ||
587 __kmp_str_match( "1", 1, data ) ||
588 __kmp_str_match( ".true.", 2, data ) ||
589 __kmp_str_match( ".t.", 2, data ) ||
590 __kmp_str_match( "yes", 1, data );
591 return result;
592} // __kmp_str_match_true
593
594void
595__kmp_str_replace(
596 char * str,
597 char search_for,
598 char replace_with
599) {
600
601 char * found = NULL;
602
603 found = strchr( str, search_for );
604 while ( found ) {
605 * found = replace_with;
606 found = strchr( found + 1, search_for );
607 }; // while
608
609} // __kmp_str_replace
610
611
612void
613__kmp_str_split(
614 char * str, // I: String to split.
615 char delim, // I: Character to split on.
616 char ** head, // O: Pointer to head (may be NULL).
617 char ** tail // O: Pointer to tail (may be NULL).
618) {
619 char * h = str;
620 char * t = NULL;
621 if ( str != NULL ) {
622 char * ptr = strchr( str, delim );
623 if ( ptr != NULL ) {
624 * ptr = 0;
625 t = ptr + 1;
626 }; // if
627 }; // if
628 if ( head != NULL ) {
629 * head = h;
630 }; // if
631 if ( tail != NULL ) {
632 * tail = t;
633 }; // if
634} // __kmp_str_split
635
636/*
637 strtok_r() is not available on Windows* OS. This function reimplements strtok_r().
638*/
639char *
640__kmp_str_token(
641 char * str, // String to split into tokens. Note: String *is* modified!
642 char const * delim, // Delimiters.
643 char ** buf // Internal buffer.
644) {
645 char * token = NULL;
646 #if KMP_OS_WINDOWS
647 // On Windows* OS there is no strtok_r() function. Let us implement it.
648 if ( str != NULL ) {
649 * buf = str; // First call, initialize buf.
650 }; // if
651 * buf += strspn( * buf, delim ); // Skip leading delimiters.
652 if ( ** buf != 0 ) { // Rest of the string is not yet empty.
653 token = * buf; // Use it as result.
654 * buf += strcspn( * buf, delim ); // Skip non-delimiters.
655 if ( ** buf != 0 ) { // Rest of the string is not yet empty.
656 ** buf = 0; // Terminate token here.
657 * buf += 1; // Advance buf to start with the next token next time.
658 }; // if
659 }; // if
660 #else
661 // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
662 token = strtok_r( str, delim, buf );
663 #endif
664 return token;
665}; // __kmp_str_token
666
667
668int
669__kmp_str_to_int(
670 char const * str,
671 char sentinel
672) {
673 int result, factor;
674 char const * t;
675
676 result = 0;
677
678 for (t = str; *t != '\0'; ++t) {
679 if (*t < '0' || *t > '9')
680 break;
681 result = (result * 10) + (*t - '0');
682 }
683
684 switch (*t) {
685 case '\0': /* the current default for no suffix is bytes */
686 factor = 1;
687 break;
688 case 'b': case 'B': /* bytes */
689 ++t;
690 factor = 1;
691 break;
692 case 'k': case 'K': /* kilo-bytes */
693 ++t;
694 factor = 1024;
695 break;
696 case 'm': case 'M': /* mega-bytes */
697 ++t;
698 factor = (1024 * 1024);
699 break;
700 default:
701 if(*t != sentinel)
702 return (-1);
703 t = "";
704 factor = 1;
705 }
706
707 if (result > (INT_MAX / factor))
708 result = INT_MAX;
709 else
710 result *= factor;
711
712 return (*t != 0 ? 0 : result);
713
714} // __kmp_str_to_int
715
716
717/*
718 The routine parses input string. It is expected it is a unsigned integer with optional unit.
719 Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb" or "m" for megabytes, ..., "yb"
720 or "y" for yottabytes. :-) Unit name is case-insensitive. The routine returns 0 if everything is
721 ok, or error code: -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
722 value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown unit *size is set
723 to zero.
724*/
725void
726__kmp_str_to_size( // R: Error code.
727 char const * str, // I: String of characters, unsigned number and unit ("b", "kb", etc).
728 size_t * out, // O: Parsed number.
729 size_t dfactor, // I: The factor if none of the letters specified.
730 char const * * error // O: Null if everything is ok, error message otherwise.
731) {
732
733 size_t value = 0;
734 size_t factor = 0;
735 int overflow = 0;
736 int bad_unit = 0;
737 int i = 0;
738 int digit;
739
740
741 KMP_DEBUG_ASSERT( str != NULL );
742
743 // Skip spaces.
744 while ( str[ i ] == ' ' || str[ i ] == '\t') {
745 ++ i;
746 }; // while
747
748 // Parse number.
749 if ( str[ i ] < '0' || str[ i ] > '9' ) {
750 * error = KMP_I18N_STR( NotANumber );
751 return;
752 }; // if
753 do {
754 digit = str[ i ] - '0';
755 overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
756 value = ( value * 10 ) + digit;
757 ++ i;
758 } while ( str[ i ] >= '0' && str[ i ] <= '9' );
759
760 // Skip spaces.
761 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
762 ++ i;
763 }; // while
764
765 // Parse unit.
766 #define _case( ch, exp ) \
767 case ch : \
768 case ch - ( 'a' - 'A' ) : { \
769 size_t shift = (exp) * 10; \
770 ++ i; \
771 if ( shift < sizeof( size_t ) * 8 ) { \
772 factor = (size_t)( 1 ) << shift; \
773 } else { \
774 overflow = 1; \
775 }; \
776 } break;
777 switch ( str[ i ] ) {
778 _case( 'k', 1 ); // Kilo
779 _case( 'm', 2 ); // Mega
780 _case( 'g', 3 ); // Giga
781 _case( 't', 4 ); // Tera
782 _case( 'p', 5 ); // Peta
783 _case( 'e', 6 ); // Exa
784 _case( 'z', 7 ); // Zetta
785 _case( 'y', 8 ); // Yotta
786 // Oops. No more units...
787 }; // switch
788 #undef _case
789 if ( str[ i ] == 'b' || str[ i ] == 'B' ) { // Skip optional "b".
790 if ( factor == 0 ) {
791 factor = 1;
792 }
793 ++ i;
794 }; // if
795 if ( ! ( str[ i ] == ' ' || str[ i ] == '\t' || str[ i ] == 0 ) ) { // Bad unit
796 * error = KMP_I18N_STR( BadUnit );
797 return;
798 }; // if
799
800 if ( factor == 0 ) {
801 factor = dfactor;
802 }
803
804 // Apply factor.
805 overflow = overflow || ( value > ( KMP_SIZE_T_MAX / factor ) );
806 value *= factor;
807
808 // Skip spaces.
809 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
810 ++ i;
811 }; // while
812
813 if ( str[ i ] != 0 ) {
814 * error = KMP_I18N_STR( IllegalCharacters );
815 return;
816 }; // if
817
818 if ( overflow ) {
819 * error = KMP_I18N_STR( ValueTooLarge );
820 * out = KMP_SIZE_T_MAX;
821 return;
822 }; // if
823
824 * error = NULL;
825 * out = value;
826
827} // __kmp_str_to_size
828
829
830void
831__kmp_str_to_uint( // R: Error code.
832 char const * str, // I: String of characters, unsigned number.
833 kmp_uint64 * out, // O: Parsed number.
834 char const * * error // O: Null if everything is ok, error message otherwise.
835) {
836
837 size_t value = 0;
838 int overflow = 0;
839 int i = 0;
840 int digit;
841
842
843 KMP_DEBUG_ASSERT( str != NULL );
844
845 // Skip spaces.
846 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
847 ++ i;
848 }; // while
849
850 // Parse number.
851 if ( str[ i ] < '0' || str[ i ] > '9' ) {
852 * error = KMP_I18N_STR( NotANumber );
853 return;
854 }; // if
855 do {
856 digit = str[ i ] - '0';
857 overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
858 value = ( value * 10 ) + digit;
859 ++ i;
860 } while ( str[ i ] >= '0' && str[ i ] <= '9' );
861
862 // Skip spaces.
863 while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
864 ++ i;
865 }; // while
866
867 if ( str[ i ] != 0 ) {
868 * error = KMP_I18N_STR( IllegalCharacters );
869 return;
870 }; // if
871
872 if ( overflow ) {
873 * error = KMP_I18N_STR( ValueTooLarge );
874 * out = (kmp_uint64) -1;
875 return;
876 }; // if
877
878 * error = NULL;
879 * out = value;
880
881} // __kmp_str_to_unit
882
883
884
885// end of file //