Browse Source

[libc] Rewrite strtoul()

The implementation of strtoul() has a partially unknown provenance.
Rewrite this code to avoid potential licensing uncertainty.

Since we now use -ffunction-sections, there is no need to place
strtoull() in a separate file from strtoul().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
a32b1e9e35
7 changed files with 199 additions and 151 deletions
  1. 5
    4
      src/core/base16.c
  2. 0
    62
      src/core/misc.c
  3. 129
    0
      src/core/string.c
  4. 0
    60
      src/core/strtoull.c
  5. 14
    0
      src/include/ipxe/string.h
  6. 3
    25
      src/include/stdlib.h
  7. 48
    0
      src/tests/string_test.c

+ 5
- 4
src/core/base16.c View File

@@ -20,9 +20,10 @@
20 20
 FILE_LICENCE ( GPL2_OR_LATER );
21 21
 
22 22
 #include <stdint.h>
23
-#include <stdlib.h>
24 23
 #include <stdio.h>
25 24
 #include <errno.h>
25
+#include <assert.h>
26
+#include <ipxe/string.h>
26 27
 #include <ipxe/base16.h>
27 28
 
28 29
 /** @file
@@ -87,13 +88,13 @@ int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
87 88
 
88 89
 		/* Extract digits.  Note that either digit may be NUL,
89 90
 		 * which would be interpreted as an invalid value by
90
-		 * strtoul_charval(); there is therefore no need for an
91
+		 * digit_value(); there is therefore no need for an
91 92
 		 * explicit end-of-string check.
92 93
 		 */
93
-		sixteens = strtoul_charval ( *(encoded++) );
94
+		sixteens = digit_value ( *(encoded++) );
94 95
 		if ( sixteens >= 16 )
95 96
 			return -EINVAL;
96
-		units = strtoul_charval ( *(encoded++) );
97
+		units = digit_value ( *(encoded++) );
97 98
 		if ( units >= 16 )
98 99
 			return -EINVAL;
99 100
 

+ 0
- 62
src/core/misc.c View File

@@ -1,62 +0,0 @@
1
-/**************************************************************************
2
-MISC Support Routines
3
-**************************************************************************/
4
-
5
-FILE_LICENCE ( GPL2_OR_LATER );
6
-
7
-#include <stdlib.h>
8
-#include <ctype.h>
9
-#include <byteswap.h>
10
-#include <ipxe/in.h>
11
-#include <ipxe/timer.h>
12
-
13
-unsigned int strtoul_charval ( unsigned int charval ) {
14
-
15
-	if ( charval >= 'a' ) {
16
-		charval = ( charval - 'a' + 10 );
17
-	} else if ( charval >= 'A' ) {
18
-		charval = ( charval - 'A' + 10 );
19
-	} else if ( charval <= '9' ) {
20
-		charval = ( charval - '0' );
21
-	}
22
-
23
-	return charval;
24
-}
25
-
26
-unsigned long strtoul ( const char *p, char **endp, int base ) {
27
-	unsigned long ret = 0;
28
-	int negative = 0;
29
-	unsigned int charval;
30
-
31
-	while ( isspace ( *p ) )
32
-		p++;
33
-
34
-	if ( *p == '-' ) {
35
-		negative = 1;
36
-		p++;
37
-	}
38
-
39
-	base = strtoul_base ( &p, base );
40
-
41
-	while ( 1 ) {
42
-		charval = strtoul_charval ( *p );
43
-		if ( charval >= ( unsigned int ) base )
44
-			break;
45
-		ret = ( ( ret * base ) + charval );
46
-		p++;
47
-	}
48
-
49
-	if ( negative )
50
-		ret = -ret;
51
-
52
-	if ( endp )
53
-		*endp = ( char * ) p;
54
-
55
-	return ( ret );
56
-}
57
-
58
-/*
59
- * Local variables:
60
- *  c-basic-offset: 8
61
- * End:
62
- */

+ 129
- 0
src/core/string.c View File

@@ -366,3 +366,132 @@ char * strndup ( const char *src, size_t max ) {
366 366
         }
367 367
         return dup;
368 368
 }
369
+
370
+/**
371
+ * Calculate digit value
372
+ *
373
+ * @v character		Digit character
374
+ * @ret digit		Digit value
375
+ *
376
+ * Invalid digits will be returned as a value greater than or equal to
377
+ * the numeric base.
378
+ */
379
+unsigned int digit_value ( unsigned int character ) {
380
+
381
+	if ( character >= 'a' )
382
+		return ( character - ( 'a' - 10 ) );
383
+	if ( character >= 'A' )
384
+		return ( character - ( 'A' - 10 ) );
385
+	if ( character <= '9' )
386
+		return ( character - '0' );
387
+	return character;
388
+}
389
+
390
+/**
391
+ * Preprocess string for strtoul() or strtoull()
392
+ *
393
+ * @v string		String
394
+ * @v negate		Final value should be negated
395
+ * @v base		Numeric base
396
+ * @ret string		Remaining string
397
+ */
398
+static const char * strtoul_pre ( const char *string, int *negate, int *base ) {
399
+
400
+	/* Skip any leading whitespace */
401
+	while ( isspace ( *string ) )
402
+		string++;
403
+
404
+	/* Process arithmetic sign, if present */
405
+	*negate = 0;
406
+	if ( *string == '-' ) {
407
+		string++;
408
+		*negate = 1;
409
+	} else if ( *string == '+' ) {
410
+		string++;
411
+	}
412
+
413
+	/* Process base, if present */
414
+	if ( *base == 0 ) {
415
+		*base = 10;
416
+		if ( *string == '0' ) {
417
+			string++;
418
+			*base = 8;
419
+			if ( ( *string & ~0x20 ) == 'X' ) {
420
+				string++;
421
+				*base = 16;
422
+			}
423
+		}
424
+	}
425
+
426
+	return string;
427
+}
428
+
429
+/**
430
+ * Convert string to numeric value
431
+ *
432
+ * @v string		String
433
+ * @v endp		End pointer (or NULL)
434
+ * @v base		Numeric base (or zero to autodetect)
435
+ * @ret value		Numeric value
436
+ */
437
+unsigned long strtoul ( const char *string, char **endp, int base ) {
438
+	unsigned long value = 0;
439
+	unsigned int digit;
440
+	int negate;
441
+
442
+	/* Preprocess string */
443
+	string = strtoul_pre ( string, &negate, &base );
444
+
445
+	/* Process digits */
446
+	for ( ; ; string++ ) {
447
+		digit = digit_value ( *string );
448
+		if ( digit >= ( unsigned int ) base )
449
+			break;
450
+		value = ( ( value * base ) + digit );
451
+	}
452
+
453
+	/* Negate value if, applicable */
454
+	if ( negate )
455
+		value = -value;
456
+
457
+	/* Fill in end pointer, if applicable */
458
+	if ( endp )
459
+		*endp = ( ( char * ) string );
460
+
461
+	return value;
462
+}
463
+
464
+/**
465
+ * Convert string to numeric value
466
+ *
467
+ * @v string		String
468
+ * @v endp		End pointer (or NULL)
469
+ * @v base		Numeric base (or zero to autodetect)
470
+ * @ret value		Numeric value
471
+ */
472
+unsigned long long strtoull ( const char *string, char **endp, int base ) {
473
+	unsigned long long value = 0;
474
+	unsigned int digit;
475
+	int negate;
476
+
477
+	/* Preprocess string */
478
+	string = strtoul_pre ( string, &negate, &base );
479
+
480
+	/* Process digits */
481
+	for ( ; ; string++ ) {
482
+		digit = digit_value ( *string );
483
+		if ( digit >= ( unsigned int ) base )
484
+			break;
485
+		value = ( ( value * base ) + digit );
486
+	}
487
+
488
+	/* Negate value if, applicable */
489
+	if ( negate )
490
+		value = -value;
491
+
492
+	/* Fill in end pointer, if applicable */
493
+	if ( endp )
494
+		*endp = ( ( char * ) string );
495
+
496
+	return value;
497
+}

+ 0
- 60
src/core/strtoull.c View File

@@ -1,60 +0,0 @@
1
-/*
2
- * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>
3
- * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com>
4
- *
5
- * This program is free software; you can redistribute it and/or
6
- * modify it under the terms of the GNU General Public License as
7
- * published by the Free Software Foundation; either version 2 of the
8
- * License, or any later version.
9
- *
10
- * This program is distributed in the hope that it will be useful, but
11
- * WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
- * General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program; if not, write to the Free Software
17
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
- */
19
-
20
-FILE_LICENCE ( GPL2_OR_LATER );
21
-
22
-#include <stdlib.h>
23
-#include <ctype.h>
24
-
25
-/*
26
- * Despite being exactly the same as strtoul() except the long long instead of
27
- * long it ends up being much bigger so provide a separate implementation in a
28
- * separate object so that it won't be linked in if not used.
29
- */
30
-unsigned long long strtoull ( const char *p, char **endp, int base ) {
31
-	unsigned long long ret = 0;
32
-	int negative = 0;
33
-	unsigned int charval;
34
-
35
-	while ( isspace ( *p ) )
36
-		p++;
37
-
38
-	if ( *p == '-' ) {
39
-		negative = 1;
40
-		p++;
41
-	}
42
-
43
-	base = strtoul_base ( &p, base );
44
-
45
-	while ( 1 ) {
46
-		charval = strtoul_charval ( *p );
47
-		if ( charval >= ( unsigned int ) base )
48
-			break;
49
-		ret = ( ( ret * base ) + charval );
50
-		p++;
51
-	}
52
-
53
-	if ( negative )
54
-		ret = -ret;
55
-
56
-	if ( endp )
57
-		*endp = ( char * ) p;
58
-
59
-	return ( ret );
60
-}

+ 14
- 0
src/include/ipxe/string.h View File

@@ -0,0 +1,14 @@
1
+#ifndef _IPXE_STRING_H
2
+#define _IPXE_STRING_H
3
+
4
+/** @file
5
+ *
6
+ * String functions
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+extern unsigned int digit_value ( unsigned int digit );
13
+
14
+#endif /* _IPXE_STRING_H */

+ 3
- 25
src/include/stdlib.h View File

@@ -13,31 +13,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
13 13
  ****************************************************************************
14 14
  */
15 15
 
16
-static inline int strtoul_base ( const char **pp, int base )
17
-{
18
-	const char *p = *pp;
19
-
20
-	if ( base == 0 ) {
21
-		base = 10;
22
-		if ( *p == '0' ) {
23
-			p++;
24
-			base = 8;
25
-			if ( ( *p | 0x20 ) == 'x' ) {
26
-				p++;
27
-				base = 16;
28
-			}
29
-		}
30
-	}
31
-
32
-	*pp = p;
33
-
34
-	return base;
35
-}
36
-
37
-extern unsigned int strtoul_charval ( unsigned int charval );
38
-extern unsigned long strtoul ( const char *p, char **endp, int base );
39
-extern unsigned long long strtoull ( const char *p, char **endp, int base );
40
-
16
+extern unsigned long strtoul ( const char *string, char **endp, int base );
17
+extern unsigned long long strtoull ( const char *string, char **endp,
18
+				     int base );
41 19
 
42 20
 /*****************************************************************************
43 21
  *

+ 48
- 0
src/tests/string_test.c View File

@@ -31,8 +31,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
31 31
 
32 32
 #include <stdint.h>
33 33
 #include <stdlib.h>
34
+#include <stdio.h>
34 35
 #include <string.h>
35 36
 #include <strings.h>
37
+#include <ipxe/string.h>
36 38
 #include <ipxe/test.h>
37 39
 
38 40
 /**
@@ -242,6 +244,52 @@ static void string_test_exec ( void ) {
242 244
 		ok ( dest == buf );
243 245
 		ok ( strcmp ( buf, "append this" ) == 0 );
244 246
 	}
247
+
248
+	/* Test digit_value() */
249
+	{
250
+		unsigned int i;
251
+		char buf[2];
252
+		for ( i = 0 ; i < 16 ; i++ ) {
253
+			snprintf ( buf, sizeof ( buf ), "%x", i );
254
+			ok ( digit_value ( buf[0] ) == i );
255
+			snprintf ( buf, sizeof ( buf ), "%X", i );
256
+			ok ( digit_value ( buf[0] ) == i );
257
+		}
258
+		ok ( digit_value ( 0 ) >= 16 );
259
+		ok ( digit_value ( 9 ) >= 16 );
260
+		ok ( digit_value ( '0' - 1 ) >= 16 );
261
+		ok ( digit_value ( '9' + 1 ) >= 16 );
262
+		ok ( digit_value ( 'A' - 1 ) >= 16 );
263
+		ok ( digit_value ( 'F' + 1 ) >= 16 );
264
+		ok ( digit_value ( 'a' - 1 ) >= 16 );
265
+		ok ( digit_value ( 'f' + 1 ) >= 16 );
266
+	}
267
+
268
+	/* Test strtoul() */
269
+	ok ( strtoul ( "12345", NULL, 0 ) == 12345UL );
270
+	ok ( strtoul ( "  741", NULL, 10 ) == 741UL );
271
+	ok ( strtoul ( " 555a", NULL, 0 ) == 555UL );
272
+	ok ( strtoul ( " 555a", NULL, 16 ) == 0x555aUL );
273
+	ok ( strtoul ( "-12", NULL, 0 ) == -12UL );
274
+	ok ( strtoul ( "+3", NULL, 0 ) == 3UL );
275
+	ok ( strtoul ( "721", NULL, 0 ) == 721UL );
276
+	ok ( strtoul ( "721", NULL, 8 ) == 0721UL );
277
+	ok ( strtoul ( "0721", NULL, 0 ) == 0721UL );
278
+	ok ( strtoul ( "", NULL, 0 ) == 0UL );
279
+	ok ( strtoul ( "\t0xcAfe", NULL, 0 ) == 0xcafeUL );
280
+	ok ( strtoul ( "0xffffffff", NULL, 0 ) == 0xffffffffUL );
281
+	{
282
+		static const char string[] = "123aHa.world";
283
+		char *endp;
284
+		ok ( strtoul ( string, &endp, 0 ) == 123UL );
285
+		ok ( endp == &string[3] );
286
+		ok ( strtoul ( string, &endp, 16 ) == 0x123aUL );
287
+		ok ( endp == &string[4] );
288
+		ok ( strtoul ( string, &endp, 26 ) ==
289
+		     ( ( ( ( ( 1 * 26 + 2 ) * 26 + 3 ) * 26 + 10 ) * 26
290
+			 + 17 ) * 26 + 10 ) );
291
+		ok ( endp == &string[6] );
292
+	}
245 293
 }
246 294
 
247 295
 /** String self-test */

Loading…
Cancel
Save