MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_strtoll10.c
1 /* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include <my_global.h>
17 #include <my_sys.h> /* Needed for MY_ERRNO_ERANGE */
18 #include <m_string.h>
19 
20 #define MAX_NEGATIVE_NUMBER ((ulonglong) LL(0x8000000000000000))
21 #define INIT_CNT 9
22 #define LFACTOR ULL(1000000000)
23 #define LFACTOR1 ULL(10000000000)
24 #define LFACTOR2 ULL(100000000000)
25 
26 static unsigned long lfactor[9]=
27 {
28  1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
29 };
30 
31 /*
32  Convert a string to an to unsigned long long integer value
33 
34  SYNOPSYS
35  my_strtoll10()
36  nptr in pointer to the string to be converted
37  endptr in/out pointer to the end of the string/
38  pointer to the stop character
39  error out returned error code
40 
41  DESCRIPTION
42  This function takes the decimal representation of integer number
43  from string nptr and converts it to an signed or unsigned
44  long long integer value.
45  Space characters and tab are ignored.
46  A sign character might precede the digit characters. The number
47  may have any number of pre-zero digits.
48 
49  The function stops reading the string nptr at the first character
50  that is not a decimal digit. If endptr is not NULL then the function
51  will not read characters after *endptr.
52 
53  RETURN VALUES
54  Value of string as a signed/unsigned longlong integer
55 
56  if no error and endptr != NULL, it will be set to point at the character
57  after the number
58 
59  The error parameter contains information how things went:
60  -1 Number was an ok negative number
61  0 ok
62  ERANGE If the the value of the converted number exceeded the
63  maximum negative/unsigned long long integer.
64  In this case the return value is ~0 if value was
65  positive and LONGLONG_MIN if value was negative.
66  EDOM If the string didn't contain any digits. In this case
67  the return value is 0.
68 
69  If endptr is not NULL the function will store the end pointer to
70  the stop character here.
71 */
72 
73 
74 longlong my_strtoll10(const char *nptr, char **endptr, int *error)
75 {
76  const char *s, *end, *start, *n_end, *true_end;
77  char *dummy;
78  uchar c;
79  unsigned long i, j, k;
80  ulonglong li;
81  int negative;
82  ulong cutoff, cutoff2, cutoff3;
83 
84  s= nptr;
85  /* If fixed length string */
86  if (endptr)
87  {
88  end= *endptr;
89  while (s != end && (*s == ' ' || *s == '\t'))
90  s++;
91  if (s == end)
92  goto no_conv;
93  }
94  else
95  {
96  endptr= &dummy; /* Easier end test */
97  while (*s == ' ' || *s == '\t')
98  s++;
99  if (!*s)
100  goto no_conv;
101  /* This number must be big to guard against a lot of pre-zeros */
102  end= s+65535; /* Can't be longer than this */
103  }
104 
105  /* Check for a sign. */
106  negative= 0;
107  if (*s == '-')
108  {
109  *error= -1; /* Mark as negative number */
110  negative= 1;
111  if (++s == end)
112  goto no_conv;
113  cutoff= MAX_NEGATIVE_NUMBER / LFACTOR2;
114  cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
115  cutoff3= MAX_NEGATIVE_NUMBER % 100;
116  }
117  else
118  {
119  *error= 0;
120  if (*s == '+')
121  {
122  if (++s == end)
123  goto no_conv;
124  }
125  cutoff= ULONGLONG_MAX / LFACTOR2;
126  cutoff2= ULONGLONG_MAX % LFACTOR2 / 100;
127  cutoff3= ULONGLONG_MAX % 100;
128  }
129 
130  /* Handle case where we have a lot of pre-zero */
131  if (*s == '0')
132  {
133  i= 0;
134  do
135  {
136  if (++s == end)
137  goto end_i; /* Return 0 */
138  }
139  while (*s == '0');
140  n_end= s+ INIT_CNT;
141  }
142  else
143  {
144  /* Read first digit to check that it's a valid number */
145  if ((c= (*s-'0')) > 9)
146  goto no_conv;
147  i= c;
148  n_end= ++s+ INIT_CNT-1;
149  }
150 
151  /* Handle first 9 digits and store them in i */
152  if (n_end > end)
153  n_end= end;
154  for (; s != n_end ; s++)
155  {
156  if ((c= (*s-'0')) > 9)
157  goto end_i;
158  i= i*10+c;
159  }
160  if (s == end)
161  goto end_i;
162 
163  /* Handle next 9 digits and store them in j */
164  j= 0;
165  start= s; /* Used to know how much to shift i */
166  n_end= true_end= s + INIT_CNT;
167  if (n_end > end)
168  n_end= end;
169  do
170  {
171  if ((c= (*s-'0')) > 9)
172  goto end_i_and_j;
173  j= j*10+c;
174  } while (++s != n_end);
175  if (s == end)
176  {
177  if (s != true_end)
178  goto end_i_and_j;
179  goto end3;
180  }
181  if ((c= (*s-'0')) > 9)
182  goto end3;
183 
184  /* Handle the next 1 or 2 digits and store them in k */
185  k=c;
186  if (++s == end || (c= (*s-'0')) > 9)
187  goto end4;
188  k= k*10+c;
189  *endptr= (char*) ++s;
190 
191  /* number string should have ended here */
192  if (s != end && (c= (*s-'0')) <= 9)
193  goto overflow;
194 
195  /* Check that we didn't get an overflow with the last digit */
196  if (i > cutoff || (i == cutoff && (j > cutoff2 || (j == cutoff2 &&
197  k > cutoff3))))
198  goto overflow;
199  li=i*LFACTOR2+ (ulonglong) j*100 + k;
200  return (longlong) li;
201 
202 overflow: /* *endptr is set here */
203  *error= MY_ERRNO_ERANGE;
204  return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX;
205 
206 end_i:
207  *endptr= (char*) s;
208  return (negative ? ((longlong) -(long) i) : (longlong) i);
209 
210 end_i_and_j:
211  li= (ulonglong) i * lfactor[(uint) (s-start)] + j;
212  *endptr= (char*) s;
213  return (negative ? -((longlong) li) : (longlong) li);
214 
215 end3:
216  li=(ulonglong) i*LFACTOR+ (ulonglong) j;
217  *endptr= (char*) s;
218  return (negative ? -((longlong) li) : (longlong) li);
219 
220 end4:
221  li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k;
222  *endptr= (char*) s;
223  if (negative)
224  {
225  if (li > MAX_NEGATIVE_NUMBER)
226  goto overflow;
227  return -((longlong) li);
228  }
229  return (longlong) li;
230 
231 no_conv:
232  /* There was no number to convert. */
233  *error= MY_ERRNO_EDOM;
234  *endptr= (char *) nptr;
235  return 0;
236 }