LLVM OpenMP* Runtime Library
kmp_str.c
1 /*
2  * kmp_str.c -- 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_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 
438 int
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 
483 char *
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 );
504  rc = KMP_VSNPRINTF( buffer, size, format, args );
505  va_end( args );
506 
507  // No errors, string has been formatted.
508  if ( rc >= 0 && rc < size ) {
509  break;
510  }; // if
511 
512  // Error occurred, buffer is too small.
513  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 
534 void
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 */
549 int
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 
568 int
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 
581 int
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 
593 void
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 
611 void
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 */
638 char *
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 
667 int
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 */
724 void
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;
735  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 
828 void
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 //