~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to strings/my_strtoll10.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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__ */
 
31
#define MAX_NEGATIVE_NUMBER     ((ulonglong) LL(0x8000000000000000))
 
32
#define INIT_CNT  9
 
33
#define LFACTOR   ULL(1000000000)
 
34
#define LFACTOR1  ULL(10000000000)
 
35
#define LFACTOR2  ULL(100000000000)
 
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
}