~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to strings/str2int.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 */