Drizzled Public API Documentation

my_strtoll10.cc
1 /* Copyright (C) 2003 MySQL AB
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 <config.h>
17 #include <drizzled/internal/m_string.h>
18 #include <errno.h>
19 
20 namespace drizzled
21 {
22 namespace internal
23 {
24 
25 #define MAX_NEGATIVE_NUMBER ((uint64_t) 0x8000000000000000LL)
26 #define INIT_CNT 9
27 #define LFACTOR 1000000000ULL
28 #define LFACTOR1 10000000000ULL
29 #define LFACTOR2 100000000000ULL
30 
31 static uint64_t lfactor[9]=
32 {
33  1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
34 };
35 
36 /*
37  Convert a string to an to uint64_t integer value
38 
39  SYNOPSYS
40  my_strtoll10()
41  nptr in pointer to the string to be converted
42  endptr in/out pointer to the end of the string/
43  pointer to the stop character
44  error out returned error code
45 
46  DESCRIPTION
47  This function takes the decimal representation of integer number
48  from string nptr and converts it to an signed or unsigned
49  int64_t value.
50  Space characters and tab are ignored.
51  A sign character might precede the digit characters. The number
52  may have any number of pre-zero digits.
53 
54  The function stops reading the string nptr at the first character
55  that is not a decimal digit. If endptr is not NULL then the function
56  will not read characters after *endptr.
57 
58  RETURN VALUES
59  Value of string as a signed/unsigned int64_t integer
60 
61  if no error and endptr != NULL, it will be set to point at the character
62  after the number
63 
64  The error parameter contains information how things went:
65  -1 Number was an ok negative number
66  0 ok
67  ERANGE If the the value of the converted number exceeded the
68  maximum negative/uint64_t integer.
69  In this case the return value is UINT64_MAX if value was
70  positive and UINT64_MIN if value was negative.
71  EDOM If the string didn't contain any digits. In this case
72  the return value is 0.
73 
74  If endptr is not NULL the function will store the end pointer to
75  the stop character here.
76 */
77 
78 
79 int64_t my_strtoll10(const char *nptr, char **endptr, int *error)
80 {
81  const char *s, *end, *start, *n_end, *true_end;
82  char *dummy;
83  unsigned char c;
84  unsigned long i, j, k;
85  uint64_t li;
86  int negative;
87  uint64_t cutoff, cutoff2, cutoff3;
88 
89  s= nptr;
90  /* If fixed length string */
91  if (endptr)
92  {
93  end= *endptr;
94  while (s != end && (*s == ' ' || *s == '\t'))
95  s++;
96  if (s == end)
97  goto no_conv;
98  }
99  else
100  {
101  endptr= &dummy; /* Easier end test */
102  while (*s == ' ' || *s == '\t')
103  s++;
104  if (!*s)
105  goto no_conv;
106  /* This number must be big to guard against a lot of pre-zeros */
107  end= s+65535; /* Can't be longer than this */
108  }
109 
110  /* Check for a sign. */
111  negative= 0;
112  if (*s == '-')
113  {
114  *error= -1; /* Mark as negative number */
115  negative= 1;
116  if (++s == end)
117  goto no_conv;
118  cutoff= MAX_NEGATIVE_NUMBER / LFACTOR2;
119  cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
120  cutoff3= MAX_NEGATIVE_NUMBER % 100;
121  }
122  else
123  {
124  *error= 0;
125  if (*s == '+')
126  {
127  if (++s == end)
128  goto no_conv;
129  }
130  cutoff= UINT64_MAX / LFACTOR2;
131  cutoff2= UINT64_MAX % LFACTOR2 / 100;
132  cutoff3= UINT64_MAX % 100;
133  }
134 
135  /* Handle case where we have a lot of pre-zero */
136  if (*s == '0')
137  {
138  i= 0;
139  do
140  {
141  if (++s == end)
142  goto end_i; /* Return 0 */
143  }
144  while (*s == '0');
145  n_end= s+ INIT_CNT;
146  }
147  else
148  {
149  /* Read first digit to check that it's a valid number */
150  if ((c= (*s-'0')) > 9)
151  goto no_conv;
152  i= c;
153  n_end= ++s+ INIT_CNT-1;
154  }
155 
156  /* Handle first 9 digits and store them in i */
157  if (n_end > end)
158  n_end= end;
159  for (; s != n_end ; s++)
160  {
161  if ((c= (*s-'0')) > 9)
162  goto end_i;
163  i= i*10+c;
164  }
165  if (s == end)
166  goto end_i;
167 
168  /* Handle next 9 digits and store them in j */
169  j= 0;
170  start= s; /* Used to know how much to shift i */
171  n_end= true_end= s + INIT_CNT;
172  if (n_end > end)
173  n_end= end;
174  do
175  {
176  if ((c= (*s-'0')) > 9)
177  goto end_i_and_j;
178  j= j*10+c;
179  } while (++s != n_end);
180  if (s == end)
181  {
182  if (s != true_end)
183  goto end_i_and_j;
184  goto end3;
185  }
186  if ((c= (*s-'0')) > 9)
187  goto end3;
188 
189  /* Handle the next 1 or 2 digits and store them in k */
190  k=c;
191  if (++s == end || (c= (*s-'0')) > 9)
192  goto end4;
193  k= k*10+c;
194  *endptr= (char*) ++s;
195 
196  /* number string should have ended here */
197  if (s != end && (c= (*s-'0')) <= 9)
198  goto overflow;
199 
200  /* Check that we didn't get an overflow with the last digit */
201  if (i > cutoff || (i == cutoff && ((j > cutoff2 || j == cutoff2) &&
202  k > cutoff3)))
203  goto overflow;
204  li=i*LFACTOR2+ (uint64_t) j*100 + k;
205  return (int64_t) li;
206 
207 overflow: /* *endptr is set here */
208  *error= ERANGE;
209  return negative ? INT64_MIN: INT64_MAX;
210 
211 end_i:
212  *endptr= (char*) s;
213  return (negative ? ((int64_t) -(long) i) : (int64_t) i);
214 
215 end_i_and_j:
216  li= (uint64_t) i * lfactor[(unsigned int) (s-start)] + j;
217  *endptr= (char*) s;
218  return (negative ? -((int64_t) li) : (int64_t) li);
219 
220 end3:
221  li=(uint64_t) i*LFACTOR+ (uint64_t) j;
222  *endptr= (char*) s;
223  return (negative ? -((int64_t) li) : (int64_t) li);
224 
225 end4:
226  li=(uint64_t) i*LFACTOR1+ (uint64_t) j * 10 + k;
227  *endptr= (char*) s;
228  if (negative)
229  {
230  if (li > MAX_NEGATIVE_NUMBER)
231  goto overflow;
232  return -((int64_t) li);
233  }
234  return (int64_t) li;
235 
236 no_conv:
237  /* There was no number to convert. */
238  *error= EDOM;
239  *endptr= (char *) nptr;
240  return 0;
241 }
242 
243 } /* namespace internal */
244 } /* namespace drizzled */
TODO: Rename this file - func.h is stupid.