LLVM OpenMP* Runtime Library
kmp_str.cpp
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 //