~drizzle-trunk/drizzle/development

1 by brian
clean slate
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
#include <my_global.h>
17
#include <my_sys.h>            /* Needed for MY_ERRNO_ERANGE */
18
#include <m_string.h>
19
20
#undef  ULONGLONG_MAX
21
/*
22
  Needed under MetroWerks Compiler, since MetroWerks compiler does not
23
  properly handle a constant expression containing a mod operator
24
*/
25
#if defined(__NETWARE__) && defined(__MWERKS__) 
26
static ulonglong ulonglong_max= ~(ulonglong) 0;
27
#define ULONGLONG_MAX ulonglong_max
28
#else
29
#define ULONGLONG_MAX		(~(ulonglong) 0)
30
#endif /* __NETWARE__ && __MWERKS__ */
80.1.1 by Brian Aker
LL() cleanup
31
#define MAX_NEGATIVE_NUMBER	((ulonglong) 0x8000000000000000LL)
1 by brian
clean slate
32
#define INIT_CNT  9
80.1.1 by Brian Aker
LL() cleanup
33
#define LFACTOR   1000000000ULL
34
#define LFACTOR1  10000000000ULL
35
#define LFACTOR2  100000000000ULL
1 by brian
clean slate
36
37
static unsigned long lfactor[9]=
38
{
39
  1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
40
};
41
42
/*
43
  Convert a string to an to unsigned long long integer value
44
  
45
  SYNOPSYS
46
    my_strtoll10()
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
51
 
52
  DESCRIPTION
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.
59
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.
63
 
64
  RETURN VALUES
65
    Value of string as a signed/unsigned longlong integer
66
67
    if no error and endptr != NULL, it will be set to point at the character
68
    after the number
69
70
    The error parameter contains information how things went:
71
    -1		Number was an ok negative number
72
    0	 	ok
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.
79
80
    If endptr is not NULL the function will store the end pointer to
81
    the stop character here.
82
*/
83
84
85
longlong my_strtoll10(const char *nptr, char **endptr, int *error)
86
{
87
  const char *s, *end, *start, *n_end, *true_end;
88
  char *dummy;
89
  uchar c;
90
  unsigned long i, j, k;
91
  ulonglong li;
92
  int negative;
93
  ulong cutoff, cutoff2, cutoff3;
94
95
  s= nptr;
96
  /* If fixed length string */
97
  if (endptr)
98
  {
99
    end= *endptr;
100
    while (s != end && (*s == ' ' || *s == '\t'))
101
      s++;
102
    if (s == end)
103
      goto no_conv;
104
  }
105
  else
106
  {
107
    endptr= &dummy;				/* Easier end test */
108
    while (*s == ' ' || *s == '\t')
109
      s++;
110
    if (!*s)
111
      goto no_conv;
112
    /* This number must be big to guard against a lot of pre-zeros */
113
    end= s+65535;				/* Can't be longer than this */
114
  }
115
116
  /* Check for a sign.	*/
117
  negative= 0;
118
  if (*s == '-')
119
  {
120
    *error= -1;					/* Mark as negative number */
121
    negative= 1;
122
    if (++s == end)
123
      goto no_conv;
124
    cutoff=  MAX_NEGATIVE_NUMBER / LFACTOR2;
125
    cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
126
    cutoff3=  MAX_NEGATIVE_NUMBER % 100;
127
  }
128
  else
129
  {
130
    *error= 0;
131
    if (*s == '+')
132
    {
133
      if (++s == end)
134
	goto no_conv;
135
    }
136
    cutoff=  ULONGLONG_MAX / LFACTOR2;
137
    cutoff2= ULONGLONG_MAX % LFACTOR2 / 100;
138
    cutoff3=  ULONGLONG_MAX % 100;
139
  }
140
141
  /* Handle case where we have a lot of pre-zero */
142
  if (*s == '0')
143
  {
144
    i= 0;
145
    do
146
    {
147
      if (++s == end)
148
	goto end_i;				/* Return 0 */
149
    }
150
    while (*s == '0');
151
    n_end= s+ INIT_CNT;
152
  }
153
  else
154
  {
155
    /* Read first digit to check that it's a valid number */
156
    if ((c= (*s-'0')) > 9)
157
      goto no_conv;
158
    i= c;
159
    n_end= ++s+ INIT_CNT-1;
160
  }
161
162
  /* Handle first 9 digits and store them in i */
163
  if (n_end > end)
164
    n_end= end;
165
  for (; s != n_end ; s++)
166
  {
167
    if ((c= (*s-'0')) > 9)
168
      goto end_i;
169
    i= i*10+c;
170
  }
171
  if (s == end)
172
    goto end_i;
173
174
  /* Handle next 9 digits and store them in j */
175
  j= 0;
176
  start= s;				/* Used to know how much to shift i */
177
  n_end= true_end= s + INIT_CNT;
178
  if (n_end > end)
179
    n_end= end;
180
  do
181
  {
182
    if ((c= (*s-'0')) > 9)
183
      goto end_i_and_j;
184
    j= j*10+c;
185
  } while (++s != n_end);
186
  if (s == end)
187
  {
188
    if (s != true_end)
189
      goto end_i_and_j;
190
    goto end3;
191
  }
192
  if ((c= (*s-'0')) > 9)
193
    goto end3;
194
195
  /* Handle the next 1 or 2 digits and store them in k */
196
  k=c;
197
  if (++s == end || (c= (*s-'0')) > 9)
198
    goto end4;
199
  k= k*10+c;
200
  *endptr= (char*) ++s;
201
202
  /* number string should have ended here */
203
  if (s != end && (c= (*s-'0')) <= 9)
204
    goto overflow;
205
206
  /* Check that we didn't get an overflow with the last digit */
207
  if (i > cutoff || (i == cutoff && ((j > cutoff2 || j == cutoff2) &&
208
                                     k > cutoff3)))
209
    goto overflow;
210
  li=i*LFACTOR2+ (ulonglong) j*100 + k;
211
  return (longlong) li;
212
213
overflow:					/* *endptr is set here */
214
  *error= MY_ERRNO_ERANGE;
215
  return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX;
216
217
end_i:
218
  *endptr= (char*) s;
219
  return (negative ? ((longlong) -(long) i) : (longlong) i);
220
221
end_i_and_j:
222
  li= (ulonglong) i * lfactor[(uint) (s-start)] + j;
223
  *endptr= (char*) s;
224
  return (negative ? -((longlong) li) : (longlong) li);
225
226
end3:
227
  li=(ulonglong) i*LFACTOR+ (ulonglong) j;
228
  *endptr= (char*) s;
229
  return (negative ? -((longlong) li) : (longlong) li);
230
231
end4:
232
  li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k;
233
  *endptr= (char*) s;
234
  if (negative)
235
  {
236
   if (li > MAX_NEGATIVE_NUMBER)
237
     goto overflow;
238
   return -((longlong) li);
239
  }
240
  return (longlong) li;
241
242
no_conv:
243
  /* There was no number to convert.  */
244
  *error= MY_ERRNO_EDOM;
245
  *endptr= (char *) nptr;
246
  return 0;
247
}