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