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