[process] Include process name in debug messages
[ipxe.git] / src / core / string.c
1 /*
2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31
32 /** @file
33 *
34 * String functions
35 *
36 */
37
38 /**
39 * Fill memory region
40 *
41 * @v dest Destination region
42 * @v character Fill character
43 * @v len Length
44 * @ret dest Destination region
45 */
46 void * generic_memset ( void *dest, int character, size_t len ) {
47 uint8_t *dest_bytes = dest;
48
49 while ( len-- )
50 *(dest_bytes++) = character;
51 return dest;
52 }
53
54 /**
55 * Copy memory region
56 *
57 * @v dest Destination region
58 * @v src Source region
59 * @v len Length
60 * @ret dest Destination region
61 */
62 void * generic_memcpy ( void *dest, const void *src, size_t len ) {
63 const uint8_t *src_bytes = src;
64 uint8_t *dest_bytes = dest;
65
66 while ( len-- )
67 *(dest_bytes++) = *(src_bytes++);
68 return dest;
69 }
70
71 /**
72 * Copy (possibly overlapping) memory region
73 *
74 * @v dest Destination region
75 * @v src Source region
76 * @v len Length
77 * @ret dest Destination region
78 */
79 void * generic_memmove ( void *dest, const void *src, size_t len ) {
80 const uint8_t *src_bytes = ( src + len );
81 uint8_t *dest_bytes = ( dest + len );
82
83 if ( dest < src )
84 return generic_memcpy ( dest, src, len );
85 while ( len-- )
86 *(--dest_bytes) = *(--src_bytes);
87 return dest;
88 }
89
90 /**
91 * Compare memory regions
92 *
93 * @v first First region
94 * @v second Second region
95 * @v len Length
96 * @ret diff Difference
97 */
98 int memcmp ( const void *first, const void *second, size_t len ) {
99 const uint8_t *first_bytes = first;
100 const uint8_t *second_bytes = second;
101 int diff;
102
103 while ( len-- ) {
104 diff = ( *(second_bytes++) - *(first_bytes++) );
105 if ( diff )
106 return diff;
107 }
108 return 0;
109 }
110
111 /**
112 * Find character within a memory region
113 *
114 * @v src Source region
115 * @v character Character to find
116 * @v len Length
117 * @ret found Found character, or NULL if not found
118 */
119 void * memchr ( const void *src, int character, size_t len ) {
120 const uint8_t *src_bytes = src;
121
122 for ( ; len-- ; src_bytes++ ) {
123 if ( *src_bytes == character )
124 return ( ( void * ) src_bytes );
125 }
126 return NULL;
127 }
128
129 /**
130 * Swap memory regions
131 *
132 * @v first First region
133 * @v second Second region
134 * @v len Length
135 * @ret first First region
136 */
137 void * memswap ( void *first, void *second, size_t len ) {
138 uint8_t *first_bytes = first;
139 uint8_t *second_bytes = second;
140 uint8_t temp;
141
142 for ( ; len-- ; first_bytes++, second_bytes++ ) {
143 temp = *first_bytes;
144 *first_bytes = *second_bytes;
145 *second_bytes = temp;
146 }
147 return first;
148 }
149
150 /**
151 * Compare strings
152 *
153 * @v first First string
154 * @v second Second string
155 * @ret diff Difference
156 */
157 int strcmp ( const char *first, const char *second ) {
158
159 return strncmp ( first, second, ~( ( size_t ) 0 ) );
160 }
161
162 /**
163 * Compare strings
164 *
165 * @v first First string
166 * @v second Second string
167 * @v max Maximum length to compare
168 * @ret diff Difference
169 */
170 int strncmp ( const char *first, const char *second, size_t max ) {
171 const uint8_t *first_bytes = ( ( const uint8_t * ) first );
172 const uint8_t *second_bytes = ( ( const uint8_t * ) second );
173 int diff;
174
175 for ( ; max-- ; first_bytes++, second_bytes++ ) {
176 diff = ( *second_bytes - *first_bytes );
177 if ( diff )
178 return diff;
179 if ( ! *first_bytes )
180 return 0;
181 }
182 return 0;
183 }
184
185 /**
186 * Compare case-insensitive strings
187 *
188 * @v first First string
189 * @v second Second string
190 * @ret diff Difference
191 */
192 int strcasecmp ( const char *first, const char *second ) {
193 const uint8_t *first_bytes = ( ( const uint8_t * ) first );
194 const uint8_t *second_bytes = ( ( const uint8_t * ) second );
195 int diff;
196
197 for ( ; ; first_bytes++, second_bytes++ ) {
198 diff = ( toupper ( *second_bytes ) -
199 toupper ( *first_bytes ) );
200 if ( diff )
201 return diff;
202 if ( ! *first_bytes )
203 return 0;
204 }
205 }
206
207 /**
208 * Get length of string
209 *
210 * @v src String
211 * @ret len Length
212 */
213 size_t strlen ( const char *src ) {
214
215 return strnlen ( src, ~( ( size_t ) 0 ) );
216 }
217
218 /**
219 * Get length of string
220 *
221 * @v src String
222 * @v max Maximum length
223 * @ret len Length
224 */
225 size_t strnlen ( const char *src, size_t max ) {
226 const uint8_t *src_bytes = ( ( const uint8_t * ) src );
227 size_t len = 0;
228
229 while ( max-- && *(src_bytes++) )
230 len++;
231 return len;
232 }
233
234 /**
235 * Find character within a string
236 *
237 * @v src String
238 * @v character Character to find
239 * @ret found Found character, or NULL if not found
240 */
241 char * strchr ( const char *src, int character ) {
242 const uint8_t *src_bytes = ( ( const uint8_t * ) src );
243
244 for ( ; ; src_bytes++ ) {
245 if ( *src_bytes == character )
246 return ( ( char * ) src_bytes );
247 if ( ! *src_bytes )
248 return NULL;
249 }
250 }
251
252 /**
253 * Find rightmost character within a string
254 *
255 * @v src String
256 * @v character Character to find
257 * @ret found Found character, or NULL if not found
258 */
259 char * strrchr ( const char *src, int character ) {
260 const uint8_t *src_bytes = ( ( const uint8_t * ) src );
261 const uint8_t *start = src_bytes;
262
263 while ( *src_bytes )
264 src_bytes++;
265 for ( src_bytes-- ; src_bytes >= start ; src_bytes-- ) {
266 if ( *src_bytes == character )
267 return ( ( char * ) src_bytes );
268 }
269 return NULL;
270 }
271
272 /**
273 * Find substring
274 *
275 * @v haystack String
276 * @v needle Substring
277 * @ret found Found substring, or NULL if not found
278 */
279 char * strstr ( const char *haystack, const char *needle ) {
280 size_t len = strlen ( needle );
281
282 for ( ; *haystack ; haystack++ ) {
283 if ( memcmp ( haystack, needle, len ) == 0 )
284 return ( ( char * ) haystack );
285 }
286 return NULL;
287 }
288
289 /**
290 * Copy string
291 *
292 * @v dest Destination string
293 * @v src Source string
294 * @ret dest Destination string
295 */
296 char * strcpy ( char *dest, const char *src ) {
297 const uint8_t *src_bytes = ( ( const uint8_t * ) src );
298 uint8_t *dest_bytes = ( ( uint8_t * ) dest );
299
300 /* We cannot use strncpy(), since that would pad the destination */
301 for ( ; ; src_bytes++, dest_bytes++ ) {
302 *dest_bytes = *src_bytes;
303 if ( ! *dest_bytes )
304 break;
305 }
306 return dest;
307 }
308
309 /**
310 * Copy string
311 *
312 * @v dest Destination string
313 * @v src Source string
314 * @v max Maximum length
315 * @ret dest Destination string
316 */
317 char * strncpy ( char *dest, const char *src, size_t max ) {
318 const uint8_t *src_bytes = ( ( const uint8_t * ) src );
319 uint8_t *dest_bytes = ( ( uint8_t * ) dest );
320
321 for ( ; max ; max--, src_bytes++, dest_bytes++ ) {
322 *dest_bytes = *src_bytes;
323 if ( ! *dest_bytes )
324 break;
325 }
326 while ( max-- )
327 *(dest_bytes++) = '\0';
328 return dest;
329 }
330
331 /**
332 * Concatenate string
333 *
334 * @v dest Destination string
335 * @v src Source string
336 * @ret dest Destination string
337 */
338 char * strcat ( char *dest, const char *src ) {
339
340 strcpy ( ( dest + strlen ( dest ) ), src );
341 return dest;
342 }
343
344 /**
345 * Duplicate string
346 *
347 * @v src Source string
348 * @ret dup Duplicated string, or NULL if allocation failed
349 */
350 char * strdup ( const char *src ) {
351
352 return strndup ( src, ~( ( size_t ) 0 ) );
353 }
354
355 /**
356 * Duplicate string
357 *
358 * @v src Source string
359 * @v max Maximum length
360 * @ret dup Duplicated string, or NULL if allocation failed
361 */
362 char * strndup ( const char *src, size_t max ) {
363 size_t len = strnlen ( src, max );
364 char *dup;
365
366 dup = malloc ( len + 1 /* NUL */ );
367 if ( dup ) {
368 memcpy ( dup, src, len );
369 dup[len] = '\0';
370 }
371 return dup;
372 }
373
374 /**
375 * Calculate digit value
376 *
377 * @v character Digit character
378 * @ret digit Digit value
379 *
380 * Invalid digits will be returned as a value greater than or equal to
381 * the numeric base.
382 */
383 unsigned int digit_value ( unsigned int character ) {
384
385 if ( character >= 'a' )
386 return ( character - ( 'a' - 10 ) );
387 if ( character >= 'A' )
388 return ( character - ( 'A' - 10 ) );
389 if ( character <= '9' )
390 return ( character - '0' );
391 return character;
392 }
393
394 /**
395 * Preprocess string for strtoul() or strtoull()
396 *
397 * @v string String
398 * @v negate Final value should be negated
399 * @v base Numeric base
400 * @ret string Remaining string
401 */
402 static const char * strtoul_pre ( const char *string, int *negate, int *base ) {
403
404 /* Skip any leading whitespace */
405 while ( isspace ( *string ) )
406 string++;
407
408 /* Process arithmetic sign, if present */
409 *negate = 0;
410 if ( *string == '-' ) {
411 string++;
412 *negate = 1;
413 } else if ( *string == '+' ) {
414 string++;
415 }
416
417 /* Process base, if present */
418 if ( *base == 0 ) {
419 *base = 10;
420 if ( *string == '0' ) {
421 string++;
422 *base = 8;
423 if ( ( *string & ~0x20 ) == 'X' ) {
424 string++;
425 *base = 16;
426 }
427 }
428 }
429
430 return string;
431 }
432
433 /**
434 * Convert string to numeric value
435 *
436 * @v string String
437 * @v endp End pointer (or NULL)
438 * @v base Numeric base (or zero to autodetect)
439 * @ret value Numeric value
440 */
441 unsigned long strtoul ( const char *string, char **endp, int base ) {
442 unsigned long value = 0;
443 unsigned int digit;
444 int negate;
445
446 /* Preprocess string */
447 string = strtoul_pre ( string, &negate, &base );
448
449 /* Process digits */
450 for ( ; ; string++ ) {
451 digit = digit_value ( *string );
452 if ( digit >= ( unsigned int ) base )
453 break;
454 value = ( ( value * base ) + digit );
455 }
456
457 /* Negate value if, applicable */
458 if ( negate )
459 value = -value;
460
461 /* Fill in end pointer, if applicable */
462 if ( endp )
463 *endp = ( ( char * ) string );
464
465 return value;
466 }
467
468 /**
469 * Convert string to numeric value
470 *
471 * @v string String
472 * @v endp End pointer (or NULL)
473 * @v base Numeric base (or zero to autodetect)
474 * @ret value Numeric value
475 */
476 unsigned long long strtoull ( const char *string, char **endp, int base ) {
477 unsigned long long value = 0;
478 unsigned int digit;
479 int negate;
480
481 /* Preprocess string */
482 string = strtoul_pre ( string, &negate, &base );
483
484 /* Process digits */
485 for ( ; ; string++ ) {
486 digit = digit_value ( *string );
487 if ( digit >= ( unsigned int ) base )
488 break;
489 value = ( ( value * base ) + digit );
490 }
491
492 /* Negate value if, applicable */
493 if ( negate )
494 value = -value;
495
496 /* Fill in end pointer, if applicable */
497 if ( endp )
498 *endp = ( ( char * ) string );
499
500 return value;
501 }