kmp_str.c

Go to the documentation of this file.
00001 /*
00002  * kmp_str.c -- String manipulation routines.
00003  * $Revision: 42181 $
00004  * $Date: 2013-03-26 15:04:45 -0500 (Tue, 26 Mar 2013) $
00005  */
00006 
00007 /* <copyright>
00008     Copyright (c) 1997-2013 Intel Corporation.  All Rights Reserved.
00009 
00010     Redistribution and use in source and binary forms, with or without
00011     modification, are permitted provided that the following conditions
00012     are met:
00013 
00014       * Redistributions of source code must retain the above copyright
00015         notice, this list of conditions and the following disclaimer.
00016       * Redistributions in binary form must reproduce the above copyright
00017         notice, this list of conditions and the following disclaimer in the
00018         documentation and/or other materials provided with the distribution.
00019       * Neither the name of Intel Corporation nor the names of its
00020         contributors may be used to endorse or promote products derived
00021         from this software without specific prior written permission.
00022 
00023     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00026     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 
00035 
00036 ------------------------------------------------------------------------
00037 
00038     Portions of this software are protected under the following patents:
00039         U.S. Patent 5,812,852
00040         U.S. Patent 6,792,599
00041         U.S. Patent 7,069,556
00042         U.S. Patent 7,328,433
00043         U.S. Patent 7,500,242
00044 
00045 </copyright> */
00046 
00047 #include "kmp_str.h"
00048 
00049 #include <stdarg.h>    // va_*
00050 #include <stdio.h>     // vsnprintf()
00051 #include <stdlib.h>    // malloc(), realloc()
00052 
00053 #include "kmp.h"
00054 #include "kmp_i18n.h"
00055 
00056 /*
00057     ------------------------------------------------------------------------------------------------
00058     String buffer.
00059     ------------------------------------------------------------------------------------------------
00060 
00061     Usage:
00062 
00063         // Declare buffer and initialize it.
00064         kmp_str_buf_t  buffer;
00065     __kmp_str_buf_init( & buffer );
00066 
00067         // Print to buffer.
00068         __kmp_str_buf_print( & buffer, "Error in file \"%s\" line %d\n", "foo.c", 12 );
00069         __kmp_str_buf_print( & buffer, "    <%s>\n", line );
00070 
00071         // Use buffer contents. buffer.str is a pointer to data, buffer.used is a number of printed
00072         // characters (not including terminating zero).
00073         write( fd, buffer.str, buffer.used );
00074 
00075         // Free buffer.
00076         __kmp_str_buf_free( & buffer );
00077 
00078         // Alternatively, you can detach allocated memory from buffer:
00079         __kmp_str_buf_detach( & buffer );
00080         return buffer.str;    // That memory should be freed eventually.
00081 
00082 
00083     Notes:
00084 
00085         * Buffer users may use buffer.str and buffer.used. Users should not change any fields of
00086           buffer directly.
00087 
00088         * buffer.str is never NULL. If buffer is empty, buffer.str points to empty string ("").
00089 
00090         * For performance reasons, buffer uses stack memory (buffer.bulk) first. If stack memory is
00091           exhausted, buffer allocates memory on heap by malloc(), and reallocates it by realloc()
00092           as amount of used memory grows.
00093 
00094         * Buffer doubles amount of allocated memory each time it is exhausted.
00095 
00096     ------------------------------------------------------------------------------------------------
00097 */
00098 
00099 // TODO: __kmp_str_buf_print() can use thread local memory allocator.
00100 
00101 #define KMP_STR_BUF_INVARIANT( b )                                                                \
00102     {                                                                                             \
00103         KMP_DEBUG_ASSERT( (b)->str != NULL );                                                     \
00104         KMP_DEBUG_ASSERT( (b)->size >= sizeof( (b)->bulk ) );                                     \
00105         KMP_DEBUG_ASSERT( (b)->size % sizeof( (b)->bulk ) == 0 );                                 \
00106         KMP_DEBUG_ASSERT( (b)->used < (b)->size );                                                \
00107         KMP_DEBUG_ASSERT( (b)->size == sizeof( (b)->bulk ) ? (b)->str == & (b)->bulk[ 0 ] : 1 );  \
00108         KMP_DEBUG_ASSERT( (b)->size > sizeof( (b)->bulk ) ? (b)->str != & (b)->bulk[ 0 ] : 1 );   \
00109     }
00110 
00111 void
00112  __kmp_str_buf_clear(
00113      kmp_str_buf_t * buffer
00114 ) {
00115     KMP_STR_BUF_INVARIANT( buffer );
00116     if ( buffer->used > 0 ) {
00117         buffer->used = 0;
00118         buffer->str[ 0 ] = 0;
00119     }; // if
00120     KMP_STR_BUF_INVARIANT( buffer );
00121 } // __kmp_str_buf_clear
00122 
00123 
00124 void
00125 __kmp_str_buf_reserve(
00126     kmp_str_buf_t * buffer,
00127     int             size
00128 ) {
00129 
00130     KMP_STR_BUF_INVARIANT( buffer );
00131     KMP_DEBUG_ASSERT( size >= 0 );
00132 
00133     if ( buffer->size < size ) {
00134 
00135         // Calculate buffer size.
00136         do {
00137             buffer->size *= 2;
00138         } while ( buffer->size < size );
00139 
00140         // Enlarge buffer.
00141         if ( buffer->str == & buffer->bulk[ 0 ] ) {
00142             buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size );
00143             if ( buffer->str == NULL ) {
00144         KMP_FATAL( MemoryAllocFailed );
00145             }; // if
00146             memcpy( buffer->str, buffer->bulk, buffer->used + 1 );
00147         } else {
00148             buffer->str = (char *) KMP_INTERNAL_REALLOC( buffer->str, buffer->size );
00149             if ( buffer->str == NULL ) {
00150         KMP_FATAL( MemoryAllocFailed );
00151             }; // if
00152         }; // if
00153 
00154     }; // if
00155 
00156     KMP_DEBUG_ASSERT( buffer->size > 0 );
00157     KMP_DEBUG_ASSERT( buffer->size >= size );
00158     KMP_STR_BUF_INVARIANT( buffer );
00159 
00160 } // __kmp_str_buf_reserve
00161 
00162 
00163 void
00164 __kmp_str_buf_detach(
00165     kmp_str_buf_t *  buffer
00166 ) {
00167 
00168     KMP_STR_BUF_INVARIANT( buffer );
00169 
00170     // If internal bulk is used, allocate memory and copy it.
00171     if ( buffer->size <= sizeof( buffer->bulk ) ) {
00172         buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size );
00173         if ( buffer->str == NULL ) {
00174         KMP_FATAL( MemoryAllocFailed );
00175         }; // if
00176         memcpy( buffer->str, buffer->bulk, buffer->used + 1 );
00177     }; // if
00178 
00179 } // __kmp_str_buf_detach
00180 
00181 
00182 void
00183 __kmp_str_buf_free(
00184     kmp_str_buf_t * buffer
00185 ) {
00186     KMP_STR_BUF_INVARIANT( buffer );
00187     if ( buffer->size > sizeof( buffer->bulk ) ) {
00188         KMP_INTERNAL_FREE( buffer->str );
00189     }; // if
00190     buffer->str  = buffer->bulk;
00191     buffer->size = sizeof( buffer->bulk );
00192     buffer->used = 0;
00193     KMP_STR_BUF_INVARIANT( buffer );
00194 } // __kmp_str_buf_free
00195 
00196 
00197 void
00198 __kmp_str_buf_cat(
00199     kmp_str_buf_t * buffer,
00200     char const *    str,
00201     int             len
00202 ) {
00203     KMP_STR_BUF_INVARIANT( buffer );
00204     KMP_DEBUG_ASSERT( str != NULL );
00205     KMP_DEBUG_ASSERT( len >= 0 );
00206     __kmp_str_buf_reserve( buffer, buffer->used + len + 1 );
00207     memcpy( buffer->str + buffer->used, str, len );
00208     buffer->str[ buffer->used + len ] = 0;
00209     buffer->used += len;
00210     KMP_STR_BUF_INVARIANT( buffer );
00211 } // __kmp_str_buf_cat
00212 
00213 
00214 void
00215 __kmp_str_buf_vprint(
00216     kmp_str_buf_t *  buffer,
00217     char const *     format,
00218     va_list          args
00219 ) {
00220 
00221     KMP_STR_BUF_INVARIANT( buffer );
00222 
00223     for ( ; ; ) {
00224 
00225         int const free = buffer->size - buffer->used;
00226         int       rc;
00227         int       size;
00228 
00229         // Try to format string.
00230         {
00231             /*
00232                 On Linux* OS Intel(R) 64, vsnprintf() modifies args argument, so vsnprintf() crashes if it
00233                 is called for the second time with the same args. To prevent the crash, we have to
00234                 pass a fresh intact copy of args to vsnprintf() on each iteration.
00235 
00236                 Unfortunately, standard va_copy() macro is not available on Windows* OS. However, it
00237                 seems vsnprintf() does not modify args argument on Windows* OS.
00238             */
00239 
00240             #if ! KMP_OS_WINDOWS
00241                 va_list _args;
00242                 __va_copy( _args, args );  // Make copy of args.
00243                 #define args _args         // Substitute args with its copy, _args.
00244             #endif // KMP_OS_WINDOWS
00245             rc = vsnprintf( buffer->str + buffer->used, free, format, args );
00246             #if ! KMP_OS_WINDOWS
00247                 #undef args                // Remove substitution.
00248                 va_end( _args );
00249             #endif // KMP_OS_WINDOWS
00250         }
00251 
00252         // No errors, string has been formatted.
00253         if ( rc >= 0 && rc < free ) {
00254             buffer->used += rc;
00255             break;
00256         }; // if
00257 
00258         // Error occured, buffer is too small.
00259         if ( rc >= 0 ) {
00260             // C99-conforming implementation of vsnprintf returns required buffer size.
00261             size = buffer->used + rc + 1;
00262         } else {
00263             // Older implementations just return -1. Double buffer size.
00264             size = buffer->size * 2;
00265         }; // if
00266 
00267         // Enlarge buffer.
00268         __kmp_str_buf_reserve( buffer, size );
00269 
00270         // And try again.
00271 
00272     }; // forever
00273 
00274     KMP_DEBUG_ASSERT( buffer->size > 0 );
00275     KMP_STR_BUF_INVARIANT( buffer );
00276 
00277 } // __kmp_str_buf_vprint
00278 
00279 
00280 void
00281 __kmp_str_buf_print(
00282     kmp_str_buf_t *  buffer,
00283     char const *     format,
00284     ...
00285 ) {
00286 
00287     va_list args;
00288     va_start( args, format );
00289     __kmp_str_buf_vprint( buffer, format, args );
00290     va_end( args );
00291 
00292 } // __kmp_str_buf_print
00293 
00294 
00295 /*
00296     The function prints specified size to buffer. Size is expressed using biggest possible unit, for
00297     example 1024 is printed as "1k".
00298 */
00299 
00300 void
00301 __kmp_str_buf_print_size(
00302     kmp_str_buf_t * buf,
00303     size_t          size
00304 ) {
00305 
00306     char const * names[] = { "", "k", "M", "G", "T", "P", "E", "Z", "Y" };
00307     int const    units   = sizeof( names ) / sizeof( char const * );
00308     int          u       = 0;
00309     int          rc;
00310     if ( size > 0 ) {
00311         while ( ( size % 1024 == 0 ) && ( u + 1 < units ) ) {
00312             size = size / 1024;
00313             ++ u;
00314         }; // while
00315     }; // if
00316 
00317     __kmp_str_buf_print( buf, "%" KMP_SIZE_T_SPEC "%s", size, names[ u ] );
00318 
00319 } // __kmp_str_buf_print_size
00320 
00321 
00322 void
00323 __kmp_str_fname_init(
00324     kmp_str_fname_t * fname,
00325     char const *      path
00326 ) {
00327 
00328     fname->path = NULL;
00329     fname->dir  = NULL;
00330     fname->base = NULL;
00331 
00332     if ( path != NULL ) {
00333         char * slash = NULL;    // Pointer to the last character of dir.
00334         char * base  = NULL;    // Pointer to the beginning of basename.
00335         fname->path = __kmp_str_format( "%s", path );
00336             // Original code used strdup() function to copy a string, but on Windows* OS Intel(R) 64 it
00337             // causes assertioon id debug heap, so I had to replace strdup with __kmp_str_format().
00338         if ( KMP_OS_WINDOWS ) {
00339             __kmp_str_replace( fname->path, '\\', '/' );
00340         }; // if
00341         fname->dir = __kmp_str_format( "%s", fname->path );
00342         slash = strrchr( fname->dir, '/' );
00343         if ( KMP_OS_WINDOWS && slash == NULL ) {           // On Windows* OS, if slash not found,
00344             char first = TOLOWER( fname->dir[ 0 ] );     // look for drive.
00345             if ( 'a' <= first && first <= 'z' && fname->dir[ 1 ] == ':' ) {
00346                 slash = & fname->dir[ 1 ];
00347             }; // if
00348         }; // if
00349         base = ( slash == NULL ? fname->dir : slash + 1 );
00350         fname->base = __kmp_str_format( "%s", base );    // Copy basename
00351         * base = 0;                    // and truncate dir.
00352     }; // if
00353 
00354 } // kmp_str_fname_init
00355 
00356 
00357 void
00358 __kmp_str_fname_free(
00359     kmp_str_fname_t * fname
00360 ) {
00361     __kmp_str_free( const_cast< char const ** >( & fname->path ) );
00362     __kmp_str_free( const_cast< char const ** >( & fname->dir  ) );
00363     __kmp_str_free( const_cast< char const ** >( & fname->base ) );
00364 } // kmp_str_fname_free
00365 
00366 
00367 int
00368 __kmp_str_fname_match(
00369     kmp_str_fname_t const * fname,
00370     char const *            pattern
00371 ) {
00372 
00373     int dir_match  = 1;
00374     int base_match = 1;
00375 
00376     if ( pattern != NULL ) {
00377         kmp_str_fname_t ptrn;
00378         __kmp_str_fname_init( & ptrn, pattern );
00379         dir_match =
00380             strcmp( ptrn.dir, "*/" ) == 0
00381             ||
00382             ( fname->dir != NULL && __kmp_str_eqf( fname->dir, ptrn.dir ) );
00383         base_match =
00384             strcmp( ptrn.base, "*" ) == 0
00385             ||
00386             ( fname->base != NULL && __kmp_str_eqf( fname->base, ptrn.base ) );
00387         __kmp_str_fname_free( & ptrn );
00388     }; // if
00389 
00390     return dir_match && base_match;
00391 
00392 } // __kmp_str_fname_match
00393 
00394 
00395 kmp_str_loc_t
00396 __kmp_str_loc_init(
00397     char const * psource,
00398     int          init_fname
00399 ) {
00400 
00401     kmp_str_loc_t loc;
00402 
00403     loc._bulk = NULL;
00404     loc.file  = NULL;
00405     loc.func  = NULL;
00406     loc.line  = 0;
00407     loc.col   = 0;
00408 
00409     if ( psource != NULL ) {
00410 
00411         char * str   = NULL;
00412         char * dummy = NULL;
00413         char * line  = NULL;
00414         char * col   = NULL;
00415 
00416         // Copy psource to keep it intact.
00417         loc._bulk = __kmp_str_format( "%s", psource );
00418 
00419         // Parse psource string: ";file;func;line;col;;"
00420         str = loc._bulk;
00421         __kmp_str_split( str, ';', & dummy,    & str );
00422         __kmp_str_split( str, ';', & loc.file, & str );
00423         __kmp_str_split( str, ';', & loc.func, & str );
00424         __kmp_str_split( str, ';', & line,     & str );
00425         __kmp_str_split( str, ';', & col,      & str );
00426 
00427         // Convert line and col into numberic values.
00428         if ( line != NULL ) {
00429             loc.line = atoi( line );
00430             if ( loc.line < 0 ) {
00431                 loc.line = 0;
00432             }; // if
00433         }; // if
00434         if ( col != NULL ) {
00435             loc.col = atoi( col );
00436             if ( loc.col < 0 ) {
00437                 loc.col = 0;
00438             }; // if
00439         }; // if
00440 
00441     }; // if
00442 
00443     __kmp_str_fname_init( & loc.fname, init_fname ? loc.file : NULL );
00444 
00445     return loc;
00446 
00447 } // kmp_str_loc_init
00448 
00449 
00450 void
00451 __kmp_str_loc_free(
00452     kmp_str_loc_t * loc
00453 ) {
00454     __kmp_str_fname_free( & loc->fname );
00455     KMP_INTERNAL_FREE( loc->_bulk );
00456     loc->_bulk = NULL;
00457     loc->file  = NULL;
00458     loc->func  = NULL;
00459 } // kmp_str_loc_free
00460 
00461 
00462 
00463 /*
00464     This function is intended to compare file names. On Windows* OS file names are case-insensitive,
00465     so functions performs case-insensitive comparison. On Linux* OS it performs case-sensitive
00466     comparison.
00467     Note: The function returns *true* if strings are *equal*.
00468 */
00469 
00470 int
00471 __kmp_str_eqf(         // True, if strings are equal, false otherwise.
00472     char const * lhs,  // First string.
00473     char const * rhs   // Second string.
00474 ) {
00475     int result;
00476     #if KMP_OS_WINDOWS
00477         result = ( _stricmp( lhs, rhs ) == 0 );
00478     #else
00479         result = ( strcmp( lhs, rhs ) == 0 );
00480     #endif
00481     return result;
00482 } // __kmp_str_eqf
00483 
00484 
00485 /*
00486     This function is like sprintf, but it *allocates* new buffer, which must be freed eventually by
00487     __kmp_str_free(). The function is very convenient for constructing strings, it successfully
00488     replaces strdup(), strcat(), it frees programmer from buffer allocations and helps to avoid
00489     buffer overflows. Examples:
00490 
00491         str = __kmp_str_format( "%s", orig );              // strdup(), do not care about buffer size.
00492         __kmp_str_free( & str );
00493         str = __kmp_str_format( "%s%s", orig1, orig2 );    // strcat(), do not care about buffer size.
00494         __kmp_str_free( & str );
00495         str = __kmp_str_format( "%s/%s.txt", path, file ); // constructing string.
00496         __kmp_str_free( & str );
00497 
00498     Performance note:
00499         This function allocates memory with malloc() calls, so do not call it from
00500         performance-critical code. In performance-critical code consider using kmp_str_buf_t
00501         instead, since it uses stack-allocated buffer for short strings.
00502 
00503     Why does this function use malloc()?
00504         1. __kmp_allocate() returns cache-aligned memory allocated with malloc(). There are no
00505            reasons in using __kmp_allocate() for strings due to extra overhead while cache-aligned
00506            memory is not necessary.
00507         2. __kmp_thread_malloc() cannot be used because it requires pointer to thread structure.
00508            We need to perform string operations during library startup (for example, in
00509            __kmp_register_library_startup()) when no thread structures are allocated yet.
00510     So standard malloc() is the only available option.
00511 */
00512 
00513 // TODO: Find and replace all regular free() with __kmp_str_free().
00514 
00515 char *
00516 __kmp_str_format(           // Allocated string.
00517     char const * format,    // Format string.
00518     ...                     // Other parameters.
00519 ) {
00520 
00521     va_list args;
00522     int     size   = 512;
00523     char *  buffer = NULL;
00524     int     rc;
00525 
00526     // Allocate buffer.
00527     buffer = (char *) KMP_INTERNAL_MALLOC( size );
00528     if ( buffer == NULL ) {
00529     KMP_FATAL( MemoryAllocFailed );
00530     }; // if
00531 
00532     for ( ; ; ) {
00533 
00534         // Try to format string.
00535         va_start( args, format );
00536         rc = vsnprintf( buffer, size, format, args );
00537         va_end( args );
00538 
00539         // No errors, string has been formatted.
00540         if ( rc >= 0 && rc < size ) {
00541             break;
00542         }; // if
00543 
00544         // Error occured, buffer is too small.
00545         if ( rc >= 0 ) {
00546             // C99-conforming implementation of vsnprintf returns required buffer size.
00547             size = rc + 1;
00548         } else {
00549             // Older implementations just return -1.
00550             size = size * 2;
00551         }; // if
00552 
00553         // Enlarge buffer and try again.
00554         buffer = (char *) KMP_INTERNAL_REALLOC( buffer, size );
00555         if ( buffer == NULL ) {
00556             KMP_FATAL( MemoryAllocFailed );
00557         }; // if
00558 
00559     }; // forever
00560 
00561     return buffer;
00562 
00563 } // func __kmp_str_format
00564 
00565 
00566 void
00567 __kmp_str_free(
00568     char const * * str
00569 ) {
00570     KMP_DEBUG_ASSERT( str != NULL );
00571     KMP_INTERNAL_FREE( (void *) * str );
00572     * str = NULL;
00573 } // func __kmp_str_free
00574 
00575 
00576 /* If len is zero, returns true iff target and data have exact case-insensitive match.
00577    If len is negative, returns true iff target is a case-insensitive substring of data.
00578    If len is positive, returns true iff target is a case-insensitive substring of data or
00579      vice versa, and neither is shorter than len.
00580 */
00581 int
00582 __kmp_str_match(
00583     char const * target,
00584     int          len,
00585     char const * data
00586 ) {
00587     int i;
00588     if ( target == NULL || data == NULL ) {
00589         return FALSE;
00590     }; // if
00591     for ( i = 0; target[i] && data[i]; ++ i ) {
00592         if ( TOLOWER( target[i] ) != TOLOWER( data[i] ) ) {
00593             return FALSE;
00594         }; // if
00595     }; // for i
00596     return ( ( len > 0 ) ? i >= len : ( ! target[i] && ( len || ! data[i] ) ) );
00597 } // __kmp_str_match
00598 
00599 
00600 int
00601 __kmp_str_match_false( char const * data ) {
00602     int result =
00603         __kmp_str_match( "false",   1, data ) ||
00604         __kmp_str_match( "off",     2, data ) ||
00605         __kmp_str_match( "0",       1, data ) ||
00606         __kmp_str_match( ".false.", 2, data ) ||
00607         __kmp_str_match( ".f.",     2, data ) ||
00608         __kmp_str_match( "no",      1, data );
00609     return result;
00610 } // __kmp_str_match_false
00611 
00612 
00613 int
00614 __kmp_str_match_true( char const * data ) {
00615     int result =
00616         __kmp_str_match( "true",   1, data ) ||
00617         __kmp_str_match( "on",     2, data ) ||
00618         __kmp_str_match( "1",      1, data ) ||
00619         __kmp_str_match( ".true.", 2, data ) ||
00620         __kmp_str_match( ".t.",    2, data ) ||
00621         __kmp_str_match( "yes",    1, data );
00622     return result;
00623 } // __kmp_str_match_true
00624 
00625 void
00626 __kmp_str_replace(
00627     char * str,
00628     char   search_for,
00629     char   replace_with
00630 ) {
00631 
00632     char * found = NULL;
00633 
00634     found = strchr( str, search_for );
00635     while ( found ) {
00636         * found = replace_with;
00637         found = strchr( found + 1, search_for );
00638     }; // while
00639 
00640 } // __kmp_str_replace
00641 
00642 
00643 void
00644 __kmp_str_split(
00645     char *  str,    // I: String to split.
00646     char    delim,  // I: Character to split on.
00647     char ** head,   // O: Pointer to head (may be NULL).
00648     char ** tail    // O: Pointer to tail (may be NULL).
00649 ) {
00650     char * h = str;
00651     char * t = NULL;
00652     if ( str != NULL ) {
00653         char * ptr = strchr( str, delim );
00654         if ( ptr != NULL ) {
00655             * ptr  = 0;
00656             t = ptr + 1;
00657         }; // if
00658     }; // if
00659     if ( head != NULL ) {
00660         * head = h;
00661     }; // if
00662     if ( tail != NULL ) {
00663         * tail = t;
00664     }; // if
00665 } // __kmp_str_split
00666 
00667 /*
00668     strtok_r() is not available on Windows* OS. This function reimplements strtok_r().
00669 */
00670 char *
00671 __kmp_str_token(
00672     char *       str,   // String to split into tokens. Note: String *is* modified!
00673     char const * delim, // Delimiters.
00674     char **      buf    // Internal buffer.
00675 ) {
00676     char * token = NULL;
00677     #if KMP_OS_WINDOWS
00678         // On Windows* OS there is no strtok_r() function. Let us implement it.
00679         if ( str != NULL ) {
00680             * buf = str;                       // First call, initialize buf.
00681         }; // if
00682         * buf += strspn( * buf, delim );       // Skip leading delimiters.
00683         if ( ** buf != 0 ) {                   // Rest of the string is not yet empty.
00684             token = * buf;                     // Use it as result.
00685             * buf += strcspn( * buf, delim );  // Skip non-delimiters.
00686             if ( ** buf != 0 ) {               // Rest of the string is not yet empty.
00687                 ** buf = 0;                    // Terminate token here.
00688                 * buf += 1;                    // Advance buf to start with the next token next time.
00689             }; // if
00690         }; // if
00691     #else
00692         // On Linux* OS and OS X*, strtok_r() is available. Let us use it.
00693         token = strtok_r( str, delim, buf );
00694     #endif
00695     return token;
00696 }; // __kmp_str_token
00697 
00698 
00699 int
00700 __kmp_str_to_int(
00701     char const * str,
00702     char         sentinel
00703 ) {
00704     int result, factor;
00705     char const * t;
00706 
00707     result = 0;
00708 
00709     for (t = str; *t != '\0'; ++t) {
00710         if (*t < '0' || *t > '9')
00711             break;
00712         result = (result * 10) + (*t - '0');
00713     }
00714 
00715     switch (*t) {
00716     case '\0':          /* the current default for no suffix is bytes */
00717     factor = 1;
00718         break;
00719     case 'b': case 'B': /* bytes */
00720     ++t;
00721     factor = 1;
00722         break;
00723     case 'k': case 'K': /* kilo-bytes */
00724     ++t;
00725     factor = 1024;
00726         break;
00727     case 'm': case 'M': /* mega-bytes */
00728     ++t;
00729     factor = (1024 * 1024);
00730         break;
00731     default:
00732     if(*t != sentinel)
00733         return (-1);
00734     t = "";
00735     factor = 1;
00736     }
00737 
00738     if (result > (INT_MAX / factor))
00739     result = INT_MAX;
00740     else
00741     result *= factor;
00742 
00743     return (*t != 0 ? 0 : result);
00744 
00745 } // __kmp_str_to_int
00746 
00747 
00748 /*
00749     The routine parses input string. It is expected it is a unsigned integer with optional unit.
00750     Units are: "b" for bytes, "kb" or just "k" for kilobytes, "mb" or "m" for megabytes, ..., "yb"
00751     or "y" for yottabytes. :-) Unit name is case-insensitive. The routine returns 0 if everything is
00752     ok, or error code: -1 in case of overflow, -2 in case of unknown unit. *size is set to parsed
00753     value. In case of overflow *size is set to KMP_SIZE_T_MAX, in case of unknown unit *size is set
00754     to zero.
00755 */
00756 void
00757 __kmp_str_to_size(         // R: Error code.
00758     char const *   str,    // I: String of characters, unsigned number and unit ("b", "kb", etc).
00759     size_t *       out,    // O: Parsed number.
00760     size_t         dfactor, // I: The factor if none of the letters specified.
00761     char const * * error   // O: Null if everything is ok, error message otherwise.
00762 ) {
00763 
00764     size_t value    = 0;
00765     size_t factor   = 0;
00766     int    overflow = 0;
00767     int    bad_unit = 0;
00768     int    i        = 0;
00769     int    digit;
00770 
00771 
00772     KMP_DEBUG_ASSERT( str != NULL );
00773 
00774     // Skip spaces.
00775     while ( str[ i ] == ' ' || str[ i ] == '\t') {
00776         ++ i;
00777     }; // while
00778 
00779     // Parse number.
00780     if ( str[ i ] < '0' || str[ i ] > '9' ) {
00781         * error = KMP_I18N_STR( NotANumber );
00782         return;
00783     }; // if
00784     do {
00785         digit = str[ i ] - '0';
00786         overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
00787         value = ( value * 10 ) + digit;
00788         ++ i;
00789     } while ( str[ i ] >= '0' && str[ i ] <= '9' );
00790 
00791     // Skip spaces.
00792     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
00793         ++ i;
00794     }; // while
00795 
00796     // Parse unit.
00797     #define _case( ch, exp )                            \
00798         case ch :                                       \
00799         case ch - ( 'a' - 'A' ) : {                     \
00800             size_t shift = (exp) * 10;                  \
00801             ++ i;                                       \
00802             if ( shift < sizeof( size_t ) * 8 ) {       \
00803                 factor = (size_t)( 1 ) << shift;        \
00804             } else {                                    \
00805                 overflow = 1;                           \
00806             };                                          \
00807         } break;
00808     switch ( str[ i ] ) {
00809         _case( 'k', 1 ); // Kilo
00810         _case( 'm', 2 ); // Mega
00811         _case( 'g', 3 ); // Giga
00812         _case( 't', 4 ); // Tera
00813         _case( 'p', 5 ); // Peta
00814         _case( 'e', 6 ); // Exa
00815         _case( 'z', 7 ); // Zetta
00816         _case( 'y', 8 ); // Yotta
00817         // Oops. No more units...
00818     }; // switch
00819     #undef _case
00820     if ( str[ i ] == 'b' || str[ i ] == 'B' ) {    // Skip optional "b".
00821     if ( factor == 0 ) {
00822         factor = 1;
00823     }
00824         ++ i;
00825     }; // if
00826     if ( ! ( str[ i ] == ' ' || str[ i ] == '\t' || str[ i ] == 0 ) ) { // Bad unit
00827         * error = KMP_I18N_STR( BadUnit );
00828         return;
00829     }; // if
00830 
00831     if ( factor == 0 ) {
00832     factor = dfactor;
00833     }
00834 
00835     // Apply factor.
00836     overflow = overflow || ( value > ( KMP_SIZE_T_MAX / factor ) );
00837     value *= factor;
00838 
00839     // Skip spaces.
00840     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
00841         ++ i;
00842     }; // while
00843 
00844     if ( str[ i ] != 0 ) {
00845         * error = KMP_I18N_STR( IllegalCharacters );
00846         return;
00847     }; // if
00848 
00849     if ( overflow ) {
00850         * error = KMP_I18N_STR( ValueTooLarge );
00851         * out = KMP_SIZE_T_MAX;
00852         return;
00853     }; // if
00854 
00855     * error = NULL;
00856     * out = value;
00857 
00858 } // __kmp_str_to_size
00859 
00860 
00861 void
00862 __kmp_str_to_uint(         // R: Error code.
00863     char const *   str,    // I: String of characters, unsigned number.
00864     kmp_uint64 *   out,    // O: Parsed number.
00865     char const * * error   // O: Null if everything is ok, error message otherwise.
00866 ) {
00867 
00868     size_t value    = 0;
00869     int    overflow = 0;
00870     int    i        = 0;
00871     int    digit;
00872 
00873 
00874     KMP_DEBUG_ASSERT( str != NULL );
00875 
00876     // Skip spaces.
00877     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
00878         ++ i;
00879     }; // while
00880 
00881     // Parse number.
00882     if ( str[ i ] < '0' || str[ i ] > '9' ) {
00883         * error = KMP_I18N_STR( NotANumber );
00884         return;
00885     }; // if
00886     do {
00887         digit = str[ i ] - '0';
00888         overflow = overflow || ( value > ( KMP_SIZE_T_MAX - digit ) / 10 );
00889         value = ( value * 10 ) + digit;
00890         ++ i;
00891     } while ( str[ i ] >= '0' && str[ i ] <= '9' );
00892 
00893     // Skip spaces.
00894     while ( str[ i ] == ' ' || str[ i ] == '\t' ) {
00895         ++ i;
00896     }; // while
00897 
00898     if ( str[ i ] != 0 ) {
00899         * error = KMP_I18N_STR( IllegalCharacters );
00900         return;
00901     }; // if
00902 
00903     if ( overflow ) {
00904         * error = KMP_I18N_STR( ValueTooLarge );
00905         * out = (kmp_uint64) -1;
00906         return;
00907     }; // if
00908 
00909     * error = NULL;
00910     * out = value;
00911 
00912 } // __kmp_str_to_unit
00913 
00914 
00915 
00916 // end of file //

Generated on 25 Aug 2013 for libomp_oss by  doxygen 1.6.1