/src/server/strings/my_strtoll10.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #define MAX_NEGATIVE_NUMBER ((ulonglong) 0x8000000000000000ULL) |
33 | 0 | #define INIT_CNT 9 |
34 | 0 | #define LFACTOR 1000000000ULL |
35 | 0 | #define LFACTOR1 10000000000ULL |
36 | 0 | #define LFACTOR2 100000000000ULL |
37 | | |
38 | | static 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 | | |
86 | | longlong my_strtoll10(const char *nptr, char **endptr, int *error) |
87 | 0 | { |
88 | 0 | const char *s, *end, *start, *n_end, *true_end; |
89 | 0 | char *dummy; |
90 | 0 | uchar c; |
91 | 0 | unsigned long i, j, k; |
92 | 0 | ulonglong li; |
93 | 0 | int negative; |
94 | 0 | ulong cutoff, cutoff2, cutoff3; |
95 | |
|
96 | 0 | s= nptr; |
97 | | /* If fixed length string */ |
98 | 0 | if (endptr) |
99 | 0 | { |
100 | 0 | end= *endptr; |
101 | | /* Skip leading spaces */ |
102 | 0 | for ( ; s < end && my_isspace(&my_charset_latin1, *s) ; ) |
103 | 0 | s++; |
104 | |
|
105 | 0 | if (s == end) |
106 | 0 | goto no_conv; |
107 | 0 | } |
108 | 0 | else |
109 | 0 | { |
110 | 0 | endptr= &dummy; /* Easier end test */ |
111 | | /* Skip leading spaces */ |
112 | 0 | for ( ; ; s++) |
113 | 0 | { |
114 | 0 | if (!*s) |
115 | 0 | goto no_conv; |
116 | 0 | if (!my_isspace(&my_charset_latin1, *s)) |
117 | 0 | break; |
118 | 0 | } |
119 | | |
120 | | /* This number must be big to guard against a lot of pre-zeros */ |
121 | 0 | end= s+65535; /* Can't be longer than this */ |
122 | 0 | } |
123 | | |
124 | | /* Check for a sign. */ |
125 | 0 | negative= 0; |
126 | 0 | if (*s == '-') |
127 | 0 | { |
128 | 0 | *error= -1; /* Mark as negative number */ |
129 | 0 | negative= 1; |
130 | 0 | if (++s == end) |
131 | 0 | goto no_conv; |
132 | 0 | cutoff= MAX_NEGATIVE_NUMBER / LFACTOR2; |
133 | 0 | cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100; |
134 | 0 | cutoff3= MAX_NEGATIVE_NUMBER % 100; |
135 | 0 | } |
136 | 0 | else |
137 | 0 | { |
138 | 0 | *error= 0; |
139 | 0 | if (*s == '+') |
140 | 0 | { |
141 | 0 | if (++s == end) |
142 | 0 | goto no_conv; |
143 | 0 | } |
144 | 0 | cutoff= ULONGLONG_MAX / LFACTOR2; |
145 | 0 | cutoff2= ULONGLONG_MAX % LFACTOR2 / 100; |
146 | 0 | cutoff3= ULONGLONG_MAX % 100; |
147 | 0 | } |
148 | | |
149 | | /* Handle case where we have a lot of pre-zero */ |
150 | 0 | if (*s == '0') |
151 | 0 | { |
152 | 0 | i= 0; |
153 | 0 | do |
154 | 0 | { |
155 | 0 | if (++s == end) |
156 | 0 | goto end_i; /* Return 0 */ |
157 | 0 | } |
158 | 0 | while (*s == '0'); |
159 | 0 | n_end= s+ INIT_CNT; |
160 | 0 | } |
161 | 0 | else |
162 | 0 | { |
163 | | /* Read first digit to check that it's a valid number */ |
164 | 0 | if ((c= (*s-'0')) > 9) |
165 | 0 | goto no_conv; |
166 | 0 | i= c; |
167 | 0 | n_end= ++s+ INIT_CNT-1; |
168 | 0 | } |
169 | | |
170 | | /* Handle first 9 digits and store them in i */ |
171 | 0 | if (n_end > end) |
172 | 0 | n_end= end; |
173 | 0 | for (; s != n_end ; s++) |
174 | 0 | { |
175 | 0 | if ((c= (*s-'0')) > 9) |
176 | 0 | goto end_i; |
177 | 0 | i= i*10+c; |
178 | 0 | } |
179 | 0 | if (s == end) |
180 | 0 | goto end_i; |
181 | | |
182 | | /* Handle next 9 digits and store them in j */ |
183 | 0 | j= 0; |
184 | 0 | start= s; /* Used to know how much to shift i */ |
185 | 0 | n_end= true_end= s + INIT_CNT; |
186 | 0 | if (n_end > end) |
187 | 0 | n_end= end; |
188 | 0 | do |
189 | 0 | { |
190 | 0 | if ((c= (*s-'0')) > 9) |
191 | 0 | goto end_i_and_j; |
192 | 0 | j= j*10+c; |
193 | 0 | } while (++s != n_end); |
194 | 0 | if (s == end) |
195 | 0 | { |
196 | 0 | if (s != true_end) |
197 | 0 | goto end_i_and_j; |
198 | 0 | goto end3; |
199 | 0 | } |
200 | 0 | if ((c= (*s-'0')) > 9) |
201 | 0 | goto end3; |
202 | | |
203 | | /* Handle the next 1 or 2 digits and store them in k */ |
204 | 0 | k=c; |
205 | 0 | if (++s == end || (c= (*s-'0')) > 9) |
206 | 0 | goto end4; |
207 | 0 | k= k*10+c; |
208 | 0 | *endptr= (char*) ++s; |
209 | | |
210 | | /* number string should have ended here */ |
211 | 0 | if (s != end && (c= (*s-'0')) <= 9) |
212 | 0 | goto overflow; |
213 | | |
214 | | /* Check that we didn't get an overflow with the last digit */ |
215 | 0 | if (i > cutoff || (i == cutoff && (j > cutoff2 || (j == cutoff2 && |
216 | 0 | k > cutoff3)))) |
217 | 0 | goto overflow; |
218 | 0 | li=i*LFACTOR2+ (ulonglong) j*100 + k; |
219 | 0 | return (longlong) li; |
220 | | |
221 | 0 | overflow: /* *endptr is set here */ |
222 | 0 | *error= MY_ERRNO_ERANGE; |
223 | 0 | return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX; |
224 | | |
225 | 0 | end_i: |
226 | 0 | *endptr= (char*) s; |
227 | 0 | return (negative ? ((longlong) -(long) i) : (longlong) i); |
228 | | |
229 | 0 | end_i_and_j: |
230 | 0 | li= (ulonglong) i * lfactor[(uint) (s-start)] + j; |
231 | 0 | *endptr= (char*) s; |
232 | 0 | return (negative ? -((longlong) li) : (longlong) li); |
233 | | |
234 | 0 | end3: |
235 | 0 | li=(ulonglong) i*LFACTOR+ (ulonglong) j; |
236 | 0 | *endptr= (char*) s; |
237 | 0 | return (negative ? -((longlong) li) : (longlong) li); |
238 | | |
239 | 0 | end4: |
240 | 0 | li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k; |
241 | 0 | *endptr= (char*) s; |
242 | 0 | if (negative) |
243 | 0 | { |
244 | 0 | if (li > MAX_NEGATIVE_NUMBER) |
245 | 0 | goto overflow; |
246 | 0 | return -((longlong) li); |
247 | 0 | } |
248 | 0 | return (longlong) li; |
249 | | |
250 | 0 | no_conv: |
251 | | /* There was no number to convert. */ |
252 | 0 | *error= MY_ERRNO_EDOM; |
253 | 0 | *endptr= (char *) nptr; |
254 | 0 | return 0; |
255 | 0 | } |