~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 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
/*
17
  str2int(src, radix, lower, upper, &val)
18
  converts the string pointed to by src to an integer and stores it in
19
  val.	It skips leading spaces and tabs (but not newlines, formfeeds,
20
  backspaces), then it accepts an optional sign and a sequence of digits
21
  in the specified radix.  The result should satisfy lower <= *val <= upper.
22
  The result is a pointer to the first character after the number;
23
  trailing spaces will NOT be skipped.
24
25
  If an error is detected, the result will be NullS, the value put
26
  in val will be 0, and errno will be set to
27
	EDOM	if there are no digits
28
	ERANGE	if the result would overflow or otherwise fail to lie
29
		within the specified bounds.
30
  Check that the bounds are right for your machine.
31
  This looks amazingly complicated for what you probably thought was an
32
  easy task.  Coping with integer overflow and the asymmetric range of
33
  twos complement machines is anything but easy.
34
35
  So that users of atoi and atol can check whether an error occured,
36
  I have taken a wholly unprecedented step: errno is CLEARED if this
37
  call has no problems.
38
*/
39
40
#include <my_global.h>
41
#include "m_string.h"
42
#include "m_ctype.h"
43
#include "my_sys.h"			/* defines errno */
44
#include <errno.h>
45
46
#define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\
47
		     X >= 'A' && X <= 'Z' ? X-'A'+10 :\
48
		     X >= 'a' && X <= 'z' ? X-'a'+10 :\
49
		     '\177')
50
51
char *str2int(register const char *src, register int radix, long int lower,
52
	      long int upper, long int *val)
53
{
54
  int sign;			/* is number negative (+1) or positive (-1) */
55
  int n;			/* number of digits yet to be converted */
56
  long limit;			/* "largest" possible valid input */
57
  long scale;			/* the amount to multiply next digit by */
58
  long sofar;			/* the running value */
59
  register int d;		/* (negative of) next digit */
60
  char *start;
61
  int digits[32];		/* Room for numbers */
62
63
  /*  Make sure *val is sensible in case of error  */
64
65
  *val = 0;
66
67
  /*  Check that the radix is in the range 2..36  */
68
69
#ifndef DBUG_OFF
70
  if (radix < 2 || radix > 36) {
71
    errno=EDOM;
72
    return NullS;
73
  }
74
#endif
75
76
  /*  The basic problem is: how do we handle the conversion of
77
      a number without resorting to machine-specific code to
78
      check for overflow?  Obviously, we have to ensure that
79
      no calculation can overflow.  We are guaranteed that the
80
      "lower" and "upper" arguments are valid machine integers.
81
      On sign-and-magnitude, twos-complement, and ones-complement
82
      machines all, if +|n| is representable, so is -|n|, but on
83
      twos complement machines the converse is not true.  So the
84
      "maximum" representable number has a negative representative.
85
      Limit is set to min(-|lower|,-|upper|); this is the "largest"
86
      number we are concerned with.	*/
87
88
  /*  Calculate Limit using Scale as a scratch variable  */
89
90
  if ((limit = lower) > 0) limit = -limit;
91
  if ((scale = upper) > 0) scale = -scale;
92
  if (scale < limit) limit = scale;
93
94
  /*  Skip leading spaces and check for a sign.
95
      Note: because on a 2s complement machine MinLong is a valid
96
      integer but |MinLong| is not, we have to keep the current
97
      converted value (and the scale!) as *negative* numbers,
98
      so the sign is the opposite of what you might expect.
99
      */
100
  while (my_isspace(&my_charset_latin1,*src)) src++;
101
  sign = -1;
102
  if (*src == '+') src++; else
103
    if (*src == '-') src++, sign = 1;
104
105
  /*  Skip leading zeros so that we never compute a power of radix
106
      in scale that we won't have a need for.  Otherwise sticking
107
      enough 0s in front of a number could cause the multiplication
108
      to overflow when it neededn't.
109
      */
110
  start=(char*) src;
111
  while (*src == '0') src++;
112
113
  /*  Move over the remaining digits.  We have to convert from left
114
      to left in order to avoid overflow.  Answer is after last digit.
115
      */
116
117
  for (n = 0; (digits[n]=char_val(*src)) < radix && n < 20; n++,src++) ;
118
119
  /*  Check that there is at least one digit  */
120
121
  if (start == src) {
122
    errno=EDOM;
123
    return NullS;
124
  }
125
126
  /*  The invariant we want to maintain is that src is just
127
      to the right of n digits, we've converted k digits to
128
      sofar, scale = -radix**k, and scale < sofar < 0.	Now
129
      if the final number is to be within the original
130
      Limit, we must have (to the left)*scale+sofar >= Limit,
131
      or (to the left)*scale >= Limit-sofar, i.e. the digits
132
      to the left of src must form an integer <= (Limit-sofar)/(scale).
133
      In particular, this is true of the next digit.  In our
134
      incremental calculation of Limit,
135
136
      IT IS VITAL that (-|N|)/(-|D|) = |N|/|D|
137
      */
138
139
  for (sofar = 0, scale = -1; --n >= 1;)
140
  {
141
    if ((long) -(d=digits[n]) < limit) {
142
      errno=ERANGE;
143
      return NullS;
144
    }
145
    limit = (limit+d)/radix, sofar += d*scale; scale *= radix;
146
  }
147
  if (n == 0)
148
  {
149
    if ((long) -(d=digits[n]) < limit)		/* get last digit */
150
    {
151
      errno=ERANGE;
152
      return NullS;
153
    }
154
    sofar+=d*scale;
155
  }
156
157
  /*  Now it might still happen that sofar = -32768 or its equivalent,
158
      so we can't just multiply by the sign and check that the result
159
      is in the range lower..upper.  All of this caution is a right
160
      pain in the neck.  If only there were a standard routine which
161
      says generate thus and such a signal on integer overflow...
162
      But not enough machines can do it *SIGH*.
163
      */
164
  if (sign < 0)
165
  {
166
    if (sofar < -LONG_MAX || (sofar= -sofar) > upper)
167
    {
168
      errno=ERANGE;
169
      return NullS;
170
    }
171
  }
172
  else if (sofar < lower)
173
  {
174
    errno=ERANGE;
175
    return NullS;
176
  }
177
  *val = sofar;
178
  errno=0;			/* indicate that all went well */
179
  return (char*) src;
180
}
181
182
	/* Theese are so slow compared with ordinary, optimized atoi */
183
184
#ifdef WANT_OUR_ATOI
185
186
int atoi(const char *src)
187
{
188
  long val;
189
  str2int(src, 10, (long) INT_MIN, (long) INT_MAX, &val);
190
  return (int) val;
191
}
192
193
194
long atol(const char *src)
195
{
196
  long val;
197
  str2int(src, 10, LONG_MIN, LONG_MAX, &val);
198
  return val;
199
}
200
201
#endif /* WANT_OUR_ATOI */