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