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