xref: /original-bsd/lib/libc/stdlib/strtouq.c (revision 13deef58)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)strtouq.c	5.1 (Berkeley) 06/26/92";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/types.h>
13 
14 #include <limits.h>
15 #include <errno.h>
16 #include <ctype.h>
17 #include <stdlib.h>
18 
19 /*
20  * Convert a string to an unsigned quad integer.
21  *
22  * Ignores `locale' stuff.  Assumes that the upper and lower case
23  * alphabets and digits are each contiguous.
24  */
25 u_quad_t
26 strtouq(nptr, endptr, base)
27 	const char *nptr;
28 	char **endptr;
29 	register int base;
30 {
31 	register const char *s = nptr;
32 	register u_quad_t acc;
33 	register int c;
34 	register u_quad_t qbase, cutoff;
35 	register int neg, any, cutlim;
36 
37 	/*
38 	 * See strtoq for comments as to the logic used.
39 	 */
40 	s = nptr;
41 	do {
42 		c = *s++;
43 	} while (isspace(c));
44 	if (c == '-') {
45 		neg = 1;
46 		c = *s++;
47 	} else {
48 		neg = 0;
49 		if (c == '+')
50 			c = *s++;
51 	}
52 	if ((base == 0 || base == 16) &&
53 	    c == '0' && (*s == 'x' || *s == 'X')) {
54 		c = s[1];
55 		s += 2;
56 		base = 16;
57 	}
58 	if (base == 0)
59 		base = c == '0' ? 8 : 10;
60 	qbase = (unsigned)base;
61 	cutoff = (u_quad_t)UQUAD_MAX / qbase;
62 	cutlim = (u_quad_t)UQUAD_MAX % qbase;
63 	for (acc = 0, any = 0;; c = *s++) {
64 		if (isdigit(c))
65 			c -= '0';
66 		else if (isalpha(c))
67 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
68 		else
69 			break;
70 		if (c >= base)
71 			break;
72 		if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
73 			any = -1;
74 		else {
75 			any = 1;
76 			acc *= qbase;
77 			acc += c;
78 		}
79 	}
80 	if (any < 0) {
81 		acc = UQUAD_MAX;
82 		errno = ERANGE;
83 	} else if (neg)
84 		acc = -acc;
85 	if (endptr != 0)
86 		*endptr = any ? s - 1 : (char *)nptr;
87 	return (acc);
88 }
89