1
/* Copyright (C) 2003 MySQL AB
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include <my_global.h>
17
#include <my_sys.h> /* Needed for MY_ERRNO_ERANGE */
22
Needed under MetroWerks Compiler, since MetroWerks compiler does not
23
properly handle a constant expression containing a mod operator
25
#if defined(__NETWARE__) && defined(__MWERKS__)
26
static ulonglong ulonglong_max= ~(ulonglong) 0;
27
#define ULONGLONG_MAX ulonglong_max
29
#define ULONGLONG_MAX (~(ulonglong) 0)
30
#endif /* __NETWARE__ && __MWERKS__ */
31
#define MAX_NEGATIVE_NUMBER ((ulonglong) LL(0x8000000000000000))
33
#define LFACTOR ULL(1000000000)
34
#define LFACTOR1 ULL(10000000000)
35
#define LFACTOR2 ULL(100000000000)
37
static unsigned long lfactor[9]=
39
1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
43
Convert a string to an to unsigned long long integer value
47
nptr in pointer to the string to be converted
48
endptr in/out pointer to the end of the string/
49
pointer to the stop character
50
error out returned error code
53
This function takes the decimal representation of integer number
54
from string nptr and converts it to an signed or unsigned
55
long long integer value.
56
Space characters and tab are ignored.
57
A sign character might precede the digit characters. The number
58
may have any number of pre-zero digits.
60
The function stops reading the string nptr at the first character
61
that is not a decimal digit. If endptr is not NULL then the function
62
will not read characters after *endptr.
65
Value of string as a signed/unsigned longlong integer
67
if no error and endptr != NULL, it will be set to point at the character
70
The error parameter contains information how things went:
71
-1 Number was an ok negative number
73
ERANGE If the the value of the converted number exceeded the
74
maximum negative/unsigned long long integer.
75
In this case the return value is ~0 if value was
76
positive and LONGLONG_MIN if value was negative.
77
EDOM If the string didn't contain any digits. In this case
78
the return value is 0.
80
If endptr is not NULL the function will store the end pointer to
81
the stop character here.
85
longlong my_strtoll10(const char *nptr, char **endptr, int *error)
87
const char *s, *end, *start, *n_end, *true_end;
90
unsigned long i, j, k;
93
ulong cutoff, cutoff2, cutoff3;
96
/* If fixed length string */
100
while (s != end && (*s == ' ' || *s == '\t'))
107
endptr= &dummy; /* Easier end test */
108
while (*s == ' ' || *s == '\t')
112
/* This number must be big to guard against a lot of pre-zeros */
113
end= s+65535; /* Can't be longer than this */
116
/* Check for a sign. */
120
*error= -1; /* Mark as negative number */
124
cutoff= MAX_NEGATIVE_NUMBER / LFACTOR2;
125
cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
126
cutoff3= MAX_NEGATIVE_NUMBER % 100;
136
cutoff= ULONGLONG_MAX / LFACTOR2;
137
cutoff2= ULONGLONG_MAX % LFACTOR2 / 100;
138
cutoff3= ULONGLONG_MAX % 100;
141
/* Handle case where we have a lot of pre-zero */
148
goto end_i; /* Return 0 */
155
/* Read first digit to check that it's a valid number */
156
if ((c= (*s-'0')) > 9)
159
n_end= ++s+ INIT_CNT-1;
162
/* Handle first 9 digits and store them in i */
165
for (; s != n_end ; s++)
167
if ((c= (*s-'0')) > 9)
174
/* Handle next 9 digits and store them in j */
176
start= s; /* Used to know how much to shift i */
177
n_end= true_end= s + INIT_CNT;
182
if ((c= (*s-'0')) > 9)
185
} while (++s != n_end);
192
if ((c= (*s-'0')) > 9)
195
/* Handle the next 1 or 2 digits and store them in k */
197
if (++s == end || (c= (*s-'0')) > 9)
200
*endptr= (char*) ++s;
202
/* number string should have ended here */
203
if (s != end && (c= (*s-'0')) <= 9)
206
/* Check that we didn't get an overflow with the last digit */
207
if (i > cutoff || (i == cutoff && ((j > cutoff2 || j == cutoff2) &&
210
li=i*LFACTOR2+ (ulonglong) j*100 + k;
211
return (longlong) li;
213
overflow: /* *endptr is set here */
214
*error= MY_ERRNO_ERANGE;
215
return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX;
219
return (negative ? ((longlong) -(long) i) : (longlong) i);
222
li= (ulonglong) i * lfactor[(uint) (s-start)] + j;
224
return (negative ? -((longlong) li) : (longlong) li);
227
li=(ulonglong) i*LFACTOR+ (ulonglong) j;
229
return (negative ? -((longlong) li) : (longlong) li);
232
li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k;
236
if (li > MAX_NEGATIVE_NUMBER)
238
return -((longlong) li);
240
return (longlong) li;
243
/* There was no number to convert. */
244
*error= MY_ERRNO_EDOM;
245
*endptr= (char *) nptr;