iPXE
string.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stddef.h>
00027 #include <stdint.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <ctype.h>
00031 
00032 /** @file
00033  *
00034  * String functions
00035  *
00036  */
00037 
00038 /**
00039  * Fill memory region
00040  *
00041  * @v dest              Destination region
00042  * @v character         Fill character
00043  * @v len               Length
00044  * @ret dest            Destination region
00045  */
00046 void * generic_memset ( void *dest, int character, size_t len ) {
00047         uint8_t *dest_bytes = dest;
00048 
00049         while ( len-- )
00050                 *(dest_bytes++) = character;
00051         return dest;
00052 }
00053 
00054 /**
00055  * Copy memory region
00056  *
00057  * @v dest              Destination region
00058  * @v src               Source region
00059  * @v len               Length
00060  * @ret dest            Destination region
00061  */
00062 void * generic_memcpy ( void *dest, const void *src, size_t len ) {
00063         const uint8_t *src_bytes = src;
00064         uint8_t *dest_bytes = dest;
00065 
00066         while ( len-- )
00067                 *(dest_bytes++) = *(src_bytes++);
00068         return dest;
00069 }
00070 
00071 /**
00072  * Copy (possibly overlapping) memory region
00073  *
00074  * @v dest              Destination region
00075  * @v src               Source region
00076  * @v len               Length
00077  * @ret dest            Destination region
00078  */
00079 void * generic_memmove ( void *dest, const void *src, size_t len ) {
00080         const uint8_t *src_bytes = ( src + len );
00081         uint8_t *dest_bytes = ( dest + len );
00082 
00083         if ( dest < src )
00084                 return generic_memcpy ( dest, src, len );
00085         while ( len-- )
00086                 *(--dest_bytes) = *(--src_bytes);
00087         return dest;
00088 }
00089 
00090 /**
00091  * Compare memory regions
00092  *
00093  * @v first             First region
00094  * @v second            Second region
00095  * @v len               Length
00096  * @ret diff            Difference
00097  */
00098 int memcmp ( const void *first, const void *second, size_t len ) {
00099         const uint8_t *first_bytes = first;
00100         const uint8_t *second_bytes = second;
00101         int diff;
00102 
00103         while ( len-- ) {
00104                 diff = ( *(second_bytes++) - *(first_bytes++) );
00105                 if ( diff )
00106                         return diff;
00107         }
00108         return 0;
00109 }
00110 
00111 /**
00112  * Find character within a memory region
00113  *
00114  * @v src               Source region
00115  * @v character         Character to find
00116  * @v len               Length
00117  * @ret found           Found character, or NULL if not found
00118  */
00119 void * memchr ( const void *src, int character, size_t len ) {
00120         const uint8_t *src_bytes = src;
00121 
00122         for ( ; len-- ; src_bytes++ ) {
00123                 if ( *src_bytes == character )
00124                         return ( ( void * ) src_bytes );
00125         }
00126         return NULL;
00127 }
00128 
00129 /**
00130  * Swap memory regions
00131  *
00132  * @v first             First region
00133  * @v second            Second region
00134  * @v len               Length
00135  * @ret first           First region
00136  */
00137 void * memswap ( void *first, void *second, size_t len ) {
00138         uint8_t *first_bytes = first;
00139         uint8_t *second_bytes = second;
00140         uint8_t temp;
00141 
00142         for ( ; len-- ; first_bytes++, second_bytes++ ) {
00143                 temp = *first_bytes;
00144                 *first_bytes = *second_bytes;
00145                 *second_bytes = temp;
00146         }
00147         return first;
00148 }
00149 
00150 /**
00151  * Compare strings
00152  *
00153  * @v first             First string
00154  * @v second            Second string
00155  * @ret diff            Difference
00156  */
00157 int strcmp ( const char *first, const char *second ) {
00158 
00159         return strncmp ( first, second, ~( ( size_t ) 0 ) );
00160 }
00161 
00162 /**
00163  * Compare strings
00164  *
00165  * @v first             First string
00166  * @v second            Second string
00167  * @v max               Maximum length to compare
00168  * @ret diff            Difference
00169  */
00170 int strncmp ( const char *first, const char *second, size_t max ) {
00171         const uint8_t *first_bytes = ( ( const uint8_t * ) first );
00172         const uint8_t *second_bytes = ( ( const uint8_t * ) second );
00173         int diff;
00174 
00175         for ( ; max-- ; first_bytes++, second_bytes++ ) {
00176                 diff = ( *second_bytes - *first_bytes );
00177                 if ( diff )
00178                         return diff;
00179                 if ( ! *first_bytes )
00180                         return 0;
00181         }
00182         return 0;
00183 }
00184 
00185 /**
00186  * Compare case-insensitive strings
00187  *
00188  * @v first             First string
00189  * @v second            Second string
00190  * @ret diff            Difference
00191  */
00192 int strcasecmp ( const char *first, const char *second ) {
00193         const uint8_t *first_bytes = ( ( const uint8_t * ) first );
00194         const uint8_t *second_bytes = ( ( const uint8_t * ) second );
00195         int diff;
00196 
00197         for ( ; ; first_bytes++, second_bytes++ ) {
00198                 diff = ( toupper ( *second_bytes ) -
00199                          toupper ( *first_bytes ) );
00200                 if ( diff )
00201                         return diff;
00202                 if ( ! *first_bytes )
00203                         return 0;
00204         }
00205 }
00206 
00207 /**
00208  * Get length of string
00209  *
00210  * @v src               String
00211  * @ret len             Length
00212  */
00213 size_t strlen ( const char *src ) {
00214 
00215         return strnlen ( src, ~( ( size_t ) 0 ) );
00216 }
00217 
00218 /**
00219  * Get length of string
00220  *
00221  * @v src               String
00222  * @v max               Maximum length
00223  * @ret len             Length
00224  */
00225 size_t strnlen ( const char *src, size_t max ) {
00226         const uint8_t *src_bytes = ( ( const uint8_t * ) src );
00227         size_t len = 0;
00228 
00229         while ( max-- && *(src_bytes++) )
00230                 len++;
00231         return len;
00232 }
00233 
00234 /**
00235  * Find character within a string
00236  *
00237  * @v src               String
00238  * @v character         Character to find
00239  * @ret found           Found character, or NULL if not found
00240  */
00241 char * strchr ( const char *src, int character ) {
00242         const uint8_t *src_bytes = ( ( const uint8_t * ) src );
00243 
00244         for ( ; ; src_bytes++ ) {
00245                 if ( *src_bytes == character )
00246                         return ( ( char * ) src_bytes );
00247                 if ( ! *src_bytes )
00248                         return NULL;
00249         }
00250 }
00251 
00252 /**
00253  * Find rightmost character within a string
00254  *
00255  * @v src               String
00256  * @v character         Character to find
00257  * @ret found           Found character, or NULL if not found
00258  */
00259 char * strrchr ( const char *src, int character ) {
00260         const uint8_t *src_bytes = ( ( const uint8_t * ) src );
00261         const uint8_t *start = src_bytes;
00262 
00263         while ( *src_bytes )
00264                 src_bytes++;
00265         for ( src_bytes-- ; src_bytes >= start ; src_bytes-- ) {
00266                 if ( *src_bytes == character )
00267                         return ( ( char * ) src_bytes );
00268         }
00269         return NULL;
00270 }
00271 
00272 /**
00273  * Find substring
00274  *
00275  * @v haystack          String
00276  * @v needle            Substring
00277  * @ret found           Found substring, or NULL if not found
00278  */
00279 char * strstr ( const char *haystack, const char *needle ) {
00280         size_t len = strlen ( needle );
00281 
00282         for ( ; *haystack ; haystack++ ) {
00283                 if ( memcmp ( haystack, needle, len ) == 0 )
00284                         return ( ( char * ) haystack );
00285         }
00286         return NULL;
00287 }
00288 
00289 /**
00290  * Copy string
00291  *
00292  * @v dest              Destination string
00293  * @v src               Source string
00294  * @ret dest            Destination string
00295  */
00296 char * strcpy ( char *dest, const char *src ) {
00297         const uint8_t *src_bytes = ( ( const uint8_t * ) src );
00298         uint8_t *dest_bytes = ( ( uint8_t * ) dest );
00299 
00300         /* We cannot use strncpy(), since that would pad the destination */
00301         for ( ; ; src_bytes++, dest_bytes++ ) {
00302                 *dest_bytes = *src_bytes;
00303                 if ( ! *dest_bytes )
00304                         break;
00305         }
00306         return dest;
00307 }
00308 
00309 /**
00310  * Copy string
00311  *
00312  * @v dest              Destination string
00313  * @v src               Source string
00314  * @v max               Maximum length
00315  * @ret dest            Destination string
00316  */
00317 char * strncpy ( char *dest, const char *src, size_t max ) {
00318         const uint8_t *src_bytes = ( ( const uint8_t * ) src );
00319         uint8_t *dest_bytes = ( ( uint8_t * ) dest );
00320 
00321         for ( ; max ; max--, src_bytes++, dest_bytes++ ) {
00322                 *dest_bytes = *src_bytes;
00323                 if ( ! *dest_bytes )
00324                         break;
00325         }
00326         while ( max-- )
00327                 *(dest_bytes++) = '\0';
00328         return dest;
00329 }
00330 
00331 /**
00332  * Concatenate string
00333  *
00334  * @v dest              Destination string
00335  * @v src               Source string
00336  * @ret dest            Destination string
00337  */
00338 char * strcat ( char *dest, const char *src ) {
00339 
00340         strcpy ( ( dest + strlen ( dest ) ), src );
00341         return dest;
00342 }
00343 
00344 /**
00345  * Duplicate string
00346  *
00347  * @v src               Source string
00348  * @ret dup             Duplicated string, or NULL if allocation failed
00349  */
00350 char * strdup ( const char *src ) {
00351 
00352         return strndup ( src, ~( ( size_t ) 0 ) );
00353 }
00354 
00355 /**
00356  * Duplicate string
00357  *
00358  * @v src               Source string
00359  * @v max               Maximum length
00360  * @ret dup             Duplicated string, or NULL if allocation failed
00361  */
00362 char * strndup ( const char *src, size_t max ) {
00363         size_t len = strnlen ( src, max );
00364         char *dup;
00365 
00366         dup = malloc ( len + 1 /* NUL */ );
00367         if ( dup ) {
00368                 memcpy ( dup, src, len );
00369                 dup[len] = '\0';
00370         }
00371         return dup;
00372 }
00373 
00374 /**
00375  * Calculate digit value
00376  *
00377  * @v character         Digit character
00378  * @ret digit           Digit value
00379  *
00380  * Invalid digits will be returned as a value greater than or equal to
00381  * the numeric base.
00382  */
00383 unsigned int digit_value ( unsigned int character ) {
00384 
00385         if ( character >= 'a' )
00386                 return ( character - ( 'a' - 10 ) );
00387         if ( character >= 'A' )
00388                 return ( character - ( 'A' - 10 ) );
00389         if ( character <= '9' )
00390                 return ( character - '0' );
00391         return character;
00392 }
00393 
00394 /**
00395  * Preprocess string for strtoul() or strtoull()
00396  *
00397  * @v string            String
00398  * @v negate            Final value should be negated
00399  * @v base              Numeric base
00400  * @ret string          Remaining string
00401  */
00402 static const char * strtoul_pre ( const char *string, int *negate, int *base ) {
00403 
00404         /* Skip any leading whitespace */
00405         while ( isspace ( *string ) )
00406                 string++;
00407 
00408         /* Process arithmetic sign, if present */
00409         *negate = 0;
00410         if ( *string == '-' ) {
00411                 string++;
00412                 *negate = 1;
00413         } else if ( *string == '+' ) {
00414                 string++;
00415         }
00416 
00417         /* Process base, if present */
00418         if ( *base == 0 ) {
00419                 *base = 10;
00420                 if ( *string == '0' ) {
00421                         string++;
00422                         *base = 8;
00423                         if ( ( *string & ~0x20 ) == 'X' ) {
00424                                 string++;
00425                                 *base = 16;
00426                         }
00427                 }
00428         }
00429 
00430         return string;
00431 }
00432 
00433 /**
00434  * Convert string to numeric value
00435  *
00436  * @v string            String
00437  * @v endp              End pointer (or NULL)
00438  * @v base              Numeric base (or zero to autodetect)
00439  * @ret value           Numeric value
00440  */
00441 unsigned long strtoul ( const char *string, char **endp, int base ) {
00442         unsigned long value = 0;
00443         unsigned int digit;
00444         int negate;
00445 
00446         /* Preprocess string */
00447         string = strtoul_pre ( string, &negate, &base );
00448 
00449         /* Process digits */
00450         for ( ; ; string++ ) {
00451                 digit = digit_value ( *string );
00452                 if ( digit >= ( unsigned int ) base )
00453                         break;
00454                 value = ( ( value * base ) + digit );
00455         }
00456 
00457         /* Negate value if, applicable */
00458         if ( negate )
00459                 value = -value;
00460 
00461         /* Fill in end pointer, if applicable */
00462         if ( endp )
00463                 *endp = ( ( char * ) string );
00464 
00465         return value;
00466 }
00467 
00468 /**
00469  * Convert string to numeric value
00470  *
00471  * @v string            String
00472  * @v endp              End pointer (or NULL)
00473  * @v base              Numeric base (or zero to autodetect)
00474  * @ret value           Numeric value
00475  */
00476 unsigned long long strtoull ( const char *string, char **endp, int base ) {
00477         unsigned long long value = 0;
00478         unsigned int digit;
00479         int negate;
00480 
00481         /* Preprocess string */
00482         string = strtoul_pre ( string, &negate, &base );
00483 
00484         /* Process digits */
00485         for ( ; ; string++ ) {
00486                 digit = digit_value ( *string );
00487                 if ( digit >= ( unsigned int ) base )
00488                         break;
00489                 value = ( ( value * base ) + digit );
00490         }
00491 
00492         /* Negate value if, applicable */
00493         if ( negate )
00494                 value = -value;
00495 
00496         /* Fill in end pointer, if applicable */
00497         if ( endp )
00498                 *endp = ( ( char * ) string );
00499 
00500         return value;
00501 }