Embedded Artistry libc
C Standard Library Support for Bare-metal Systems
strtoll.c
Go to the documentation of this file.
1 /* $NetBSD: strtoll.c,v 1.4 2005/05/16 11:27:58 lukem Exp $ */
2 /* from NetBSD: strtoll.c,v 1.6 2003/10/27 00:12:42 lukem Exp */
3 
4 /*-
5  * Copyright (c) 1992, 1993
6  * The Regents of the University of California. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <ctype.h>
34 #include <limits.h>
35 #include <stdlib.h>
36 
37 /*
38  * Convert a string to a long long integer.
39  *
40  * Ignores `locale' stuff. Assumes that the upper and lower case
41  * alphabets and digits are each contiguous.
42  */
43 long long int strtoll(const char* nptr, char** endptr, int base)
44 {
45  const char* s;
46  /* LONGLONG */
47  long long int acc, cutoff;
48  int c;
49  int neg, any, cutlim;
50 
51  /* endptr may be NULL */
52 
53  // check base
54  if(base < 0 || base > 36)
55  {
56  // errno = EINVAL
57 
58  if(endptr)
59  {
60  *endptr = (char*)(uintptr_t)nptr;
61  }
62 
63  return 0;
64  }
65 
66 #ifdef __GNUC__
67  /* This outrageous construct just to shut up a GCC warning. */
68  (void)&acc;
69  (void)&cutoff;
70 #endif
71 
72  /*
73  * Skip white space and pick up leading +/- sign if any.
74  * If base is 0, allow 0x for hex and 0 for octal, else
75  * assume decimal; if base is already 16, allow 0x.
76  */
77  s = nptr;
78  do
79  {
80  c = (unsigned char)*s++;
81  } while(isspace(c));
82  if(c == '-')
83  {
84  neg = 1;
85  c = *s++;
86  }
87  else
88  {
89  neg = 0;
90  if(c == '+')
91  {
92  {
93  c = *s++;
94  }
95  }
96  }
97  if((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X'))
98  {
99  c = s[1];
100  s += 2;
101  base = 16;
102  }
103  if(base == 0)
104  {
105  {
106  base = c == '0' ? 8 : 10;
107  }
108  }
109 
110  /*
111  * Compute the cutoff value between legal numbers and illegal
112  * numbers. That is the largest legal value, divided by the
113  * base. An input number that is greater than this value, if
114  * followed by a legal input character, is too big. One that
115  * is equal to this value may be valid or not; the limit
116  * between valid and invalid numbers is then based on the last
117  * digit. For instance, if the range for long longs is
118  * [-9223372036854775808..9223372036854775807] and the input base
119  * is 10, cutoff will be set to 922337203685477580 and cutlim to
120  * either 7 (neg==0) or 8 (neg==1), meaning that if we have
121  * accumulated a value > 922337203685477580, or equal but the
122  * next digit is > 7 (or 8), the number is too big, and we will
123  * return a range error.
124  *
125  * Set any if any `digits' consumed; make it negative to indicate
126  * overflow.
127  */
128  cutoff = neg ? LLONG_MIN : LLONG_MAX;
129  cutlim = (int)(cutoff % base);
130  cutoff /= base;
131  if(neg)
132  {
133  if(cutlim > 0)
134  {
135  cutlim -= base;
136  cutoff += 1;
137  }
138  cutlim = -cutlim;
139  }
140  for(acc = 0, any = 0;; c = (unsigned char)*s++)
141  {
142  if(isdigit(c))
143  {
144  {
145  c -= '0';
146  }
147  }
148  else if(isalpha(c))
149  {
150  {
151  c -= isupper(c) ? 'A' - 10 : 'a' - 10;
152  }
153  }
154  else
155  {
156  {
157  break;
158  }
159  }
160  if(c >= base)
161  {
162  {
163  break;
164  }
165  }
166  if(any < 0)
167  {
168  {
169  continue;
170  }
171  }
172  if(neg)
173  {
174  if(acc < cutoff || (acc == cutoff && c > cutlim))
175  {
176  any = -1;
177  acc = LLONG_MIN;
178  // errno = ERANGE;
179  }
180  else
181  {
182  any = 1;
183  acc *= base;
184  acc -= c;
185  }
186  }
187  else
188  {
189  if(acc > cutoff || (acc == cutoff && c > cutlim))
190  {
191  any = -1;
192  acc = LLONG_MAX;
193  // errno = ERANGE;
194  }
195  else
196  {
197  any = 1;
198  acc *= base;
199  acc += c;
200  }
201  }
202  }
203  if(endptr != 0)
204  {
205  /* LINTED interface specification */
206  *endptr = (char*)(uintptr_t)(any ? s - 1 : nptr);
207  }
208  return (acc);
209 }
int isupper(int ch)
Checks if the given character is an uppercase character.
Definition: isupper.c:5
int isalpha(int ch)
Checks if the given character is an alphabetic character.
Definition: isalpha.c:5
#define LLONG_MIN
Definition: limits.h:64
long long int strtoll(const char *nptr, char **endptr, int base)
Definition: strtoll.c:43
int isspace(int ch)
Checks if the given character is a whitespace character.
Definition: isspace.c:5
int isdigit(int ch)
Checks if the given character is a numeric character.
Definition: isdigit.c:5