1/* Copyright (c) 2003 TXT DataKonsult Ab
2 Copyright (c) 2009, 2013, Monty Program Ab.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must the following disclaimer in
12 the documentation and/or other materials provided with the
13 distribution.
14
15 THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY
16 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
19 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 SUCH DAMAGE.
27*/
28
29#include "strings_def.h"
30#include <my_sys.h> /* Needed for MY_ERRNO_ERANGE */
31
32#define MAX_NEGATIVE_NUMBER ((ulonglong) 0x8000000000000000ULL)
33#define INIT_CNT 9
34#define LFACTOR 1000000000ULL
35#define LFACTOR1 10000000000ULL
36#define LFACTOR2 100000000000ULL
37
38static unsigned long lfactor[9]=
39{
40 1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
41};
42
43/*
44 Convert a string to an to unsigned long long integer value
45
46 SYNOPSIS
47 my_strtoll10()
48 nptr in pointer to the string to be converted
49 endptr in/out pointer to the end of the string/
50 pointer to the stop character
51 error out returned error code
52
53 DESCRIPTION
54 This function takes the decimal representation of integer number
55 from string nptr and converts it to an signed or unsigned
56 long long integer value.
57 Space characters and tab are ignored.
58 A sign character might precede the digit characters. The number
59 may have any number of pre-zero digits.
60
61 The function stops reading the string nptr at the first character
62 that is not a decimal digit. If endptr is not NULL then the function
63 will not read characters after *endptr.
64
65 RETURN VALUES
66 Value of string as a signed/unsigned longlong integer
67
68 if no error and endptr != NULL, it will be set to point at the character
69 after the number
70
71 The error parameter contains information how things went:
72 -1 Number was an ok negative number
73 0 ok
74 ERANGE If the the value of the converted number exceeded the
75 maximum negative/unsigned long long integer.
76 In this case the return value is ~0 if value was
77 positive and LONGLONG_MIN if value was negative.
78 EDOM If the string didn't contain any digits. In this case
79 the return value is 0.
80
81 If endptr is not NULL the function will store the end pointer to
82 the stop character here.
83*/
84
85
86longlong my_strtoll10(const char *nptr, char **endptr, int *error)
87{
88 const char *s, *end, *start, *n_end, *true_end;
89 char *dummy;
90 uchar c;
91 unsigned long i, j, k;
92 ulonglong li;
93 int negative;
94 ulong cutoff, cutoff2, cutoff3;
95
96 s= nptr;
97 /* If fixed length string */
98 if (endptr)
99 {
100 end= *endptr;
101 while (s != end && (*s == ' ' || *s == '\t'))
102 s++;
103 if (s == end)
104 goto no_conv;
105 }
106 else
107 {
108 endptr= &dummy; /* Easier end test */
109 while (*s == ' ' || *s == '\t')
110 s++;
111 if (!*s)
112 goto no_conv;
113 /* This number must be big to guard against a lot of pre-zeros */
114 end= s+65535; /* Can't be longer than this */
115 }
116
117 /* Check for a sign. */
118 negative= 0;
119 if (*s == '-')
120 {
121 *error= -1; /* Mark as negative number */
122 negative= 1;
123 if (++s == end)
124 goto no_conv;
125 cutoff= MAX_NEGATIVE_NUMBER / LFACTOR2;
126 cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
127 cutoff3= MAX_NEGATIVE_NUMBER % 100;
128 }
129 else
130 {
131 *error= 0;
132 if (*s == '+')
133 {
134 if (++s == end)
135 goto no_conv;
136 }
137 cutoff= ULONGLONG_MAX / LFACTOR2;
138 cutoff2= ULONGLONG_MAX % LFACTOR2 / 100;
139 cutoff3= ULONGLONG_MAX % 100;
140 }
141
142 /* Handle case where we have a lot of pre-zero */
143 if (*s == '0')
144 {
145 i= 0;
146 do
147 {
148 if (++s == end)
149 goto end_i; /* Return 0 */
150 }
151 while (*s == '0');
152 n_end= s+ INIT_CNT;
153 }
154 else
155 {
156 /* Read first digit to check that it's a valid number */
157 if ((c= (*s-'0')) > 9)
158 goto no_conv;
159 i= c;
160 n_end= ++s+ INIT_CNT-1;
161 }
162
163 /* Handle first 9 digits and store them in i */
164 if (n_end > end)
165 n_end= end;
166 for (; s != n_end ; s++)
167 {
168 if ((c= (*s-'0')) > 9)
169 goto end_i;
170 i= i*10+c;
171 }
172 if (s == end)
173 goto end_i;
174
175 /* Handle next 9 digits and store them in j */
176 j= 0;
177 start= s; /* Used to know how much to shift i */
178 n_end= true_end= s + INIT_CNT;
179 if (n_end > end)
180 n_end= end;
181 do
182 {
183 if ((c= (*s-'0')) > 9)
184 goto end_i_and_j;
185 j= j*10+c;
186 } while (++s != n_end);
187 if (s == end)
188 {
189 if (s != true_end)
190 goto end_i_and_j;
191 goto end3;
192 }
193 if ((c= (*s-'0')) > 9)
194 goto end3;
195
196 /* Handle the next 1 or 2 digits and store them in k */
197 k=c;
198 if (++s == end || (c= (*s-'0')) > 9)
199 goto end4;
200 k= k*10+c;
201 *endptr= (char*) ++s;
202
203 /* number string should have ended here */
204 if (s != end && (c= (*s-'0')) <= 9)
205 goto overflow;
206
207 /* Check that we didn't get an overflow with the last digit */
208 if (i > cutoff || (i == cutoff && (j > cutoff2 || (j == cutoff2 &&
209 k > cutoff3))))
210 goto overflow;
211 li=i*LFACTOR2+ (ulonglong) j*100 + k;
212 return (longlong) li;
213
214overflow: /* *endptr is set here */
215 *error= MY_ERRNO_ERANGE;
216 return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX;
217
218end_i:
219 *endptr= (char*) s;
220 return (negative ? ((longlong) -(long) i) : (longlong) i);
221
222end_i_and_j:
223 li= (ulonglong) i * lfactor[(uint) (s-start)] + j;
224 *endptr= (char*) s;
225 return (negative ? -((longlong) li) : (longlong) li);
226
227end3:
228 li=(ulonglong) i*LFACTOR+ (ulonglong) j;
229 *endptr= (char*) s;
230 return (negative ? -((longlong) li) : (longlong) li);
231
232end4:
233 li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k;
234 *endptr= (char*) s;
235 if (negative)
236 {
237 if (li > MAX_NEGATIVE_NUMBER)
238 goto overflow;
239 return -((longlong) li);
240 }
241 return (longlong) li;
242
243no_conv:
244 /* There was no number to convert. */
245 *error= MY_ERRNO_EDOM;
246 *endptr= (char *) nptr;
247 return 0;
248}
249