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