~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
  strtol,strtoul,strtoll,strtoull
18
  convert string to long, unsigned long, long long or unsigned long long.
19
  strtoxx(char *src,char **ptr,int base)
20
  converts the string pointed to by src to an long of appropriate long and
21
  returnes it. It skips leading spaces and tabs (but not newlines, formfeeds,
22
  backspaces), then it accepts an optional sign and a sequence of digits
23
  in the specified radix.
24
  If the value of ptr is not (char **)NULL, a pointer to the character
25
  terminating the scan is returned in the location pointed to by ptr.
26
  Trailing spaces will NOT be skipped.
27
28
  If an error is detected, the result will be LONG_MIN, 0 or LONG_MAX,
29
  (or LONGLONG..)  and errno will be set to
30
	EDOM	if there are no digits
31
	ERANGE	if the result would overflow.
32
  the ptr will be set to src.
33
  This file is based on the strtol from the the GNU C Library.
34
  it can be compiled with the UNSIGNED and/or LONGLONG flag set
35
*/
36
37
243.1.11 by Jay Pipes
* Added include guards in a couple places, and removed unecessary
38
#if !defined(DRIZZLE_SERVER_GLOBAL_H) || !defined(_m_string_h)
264.1.12 by Monty Taylor
Fixed ref to my_global.h in mystrings/longlong2str_asm.c.
39
#  error  Calling file must include 'drizzled/global.h' and 'mystrings/m_string.h'
1 by brian
clean slate
40
   /* see 'strtoll.c' and 'strtoull.c' for the reasons */
41
#endif
42
43
#include "m_ctype.h"
44
#include "my_sys.h"			/* defines errno */
45
#include <errno.h>
46
47
#undef strtoull
48
#undef strtoll
49
#undef strtoul
50
#undef strtol
51
#ifdef USE_LONGLONG
151 by Brian Aker
Ulonglong to uint64_t
52
#define UTYPE_MAX (~(uint64_t) 0)
1 by brian
clean slate
53
#define TYPE_MIN LONGLONG_MIN
54
#define TYPE_MAX LONGLONG_MAX
152 by Brian Aker
longlong replacement
55
#define longtype int64_t
151 by Brian Aker
Ulonglong to uint64_t
56
#define ulongtype uint64_t
1 by brian
clean slate
57
#ifdef USE_UNSIGNED
58
#define function ulongtype strtoull
59
#else
60
#define function longtype strtoll
61
#endif
62
#else
63
#define UTYPE_MAX (ulong) ~0L
64
#define TYPE_MIN LONG_MIN
65
#define TYPE_MAX LONG_MAX
66
#define longtype long
67
#define ulongtype unsigned long
68
#ifdef USE_UNSIGNED
69
#define function ulongtype strtoul
70
#else
71
#define function longtype strtol
72
#endif
73
#endif
74
75
76
/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
77
   If BASE is 0 the base is determined by the presence of a leading
78
   zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
79
   If BASE is < 2 or > 36, it is reset to 10.
80
   If ENDPTR is not NULL, a pointer to the character after the last
81
   one converted is stored in *ENDPTR.	*/
82
83
84
function (const char *nptr,char **endptr,int base)
85
{
86
  int negative;
87
  register ulongtype cutoff;
88
  register unsigned int cutlim;
89
  register ulongtype i;
90
  register const char *s;
91
  register uchar c;
92
  const char *save;
93
  int overflow;
94
95
  if (base < 0 || base == 1 || base > 36)
96
    base = 10;
97
98
  s = nptr;
99
100
  /* Skip white space.	*/
101
  while (my_isspace(&my_charset_latin1, *s))
102
    ++s;
103
  if (*s == '\0')
104
  {
105
    goto noconv;
106
  }
107
108
  /* Check for a sign.	*/
109
  negative= 0;
110
  if (*s == '-')
111
  {
112
    negative = 1;
113
    ++s;
114
  }
115
  else if (*s == '+')
116
  {
117
    ++s;
118
  }
119
    
120
121
  if (base == 16 && s[0] == '0' && my_toupper (&my_charset_latin1, s[1]) == 'X')
122
    s += 2;
123
124
  /* If BASE is zero, figure it out ourselves.	*/
125
  if (base == 0)
126
  {
127
    if (*s == '0')
128
    {
129
      if (my_toupper (&my_charset_latin1, s[1]) == 'X')
130
      {
131
	s += 2;
132
	base = 16;
133
      }
134
      else
135
	base = 8;
136
    }
137
    else
138
      base = 10;
139
  }
140
141
  /* Save the pointer so we can check later if anything happened.  */
142
  save = s;
143
144
  cutoff = UTYPE_MAX / (unsigned long int) base;
145
  cutlim = (uint) (UTYPE_MAX % (unsigned long int) base);
146
147
  overflow = 0;
148
  i = 0;
149
  for (c = *s; c != '\0'; c = *++s)
150
  {
151
    if (my_isdigit (&my_charset_latin1, c))
152
      c -= '0';
153
    else if (my_isalpha (&my_charset_latin1, c))
154
      c = my_toupper (&my_charset_latin1, c) - 'A' + 10;
155
    else
156
      break;
157
    if (c >= base)
158
      break;
159
    /* Check for overflow.  */
160
    if (i > cutoff || (i == cutoff && c > cutlim))
161
      overflow = 1;
162
    else
163
    {
164
      i *= (ulongtype) base;
165
      i += c;
166
    }
167
  }
168
169
  /* Check if anything actually happened.  */
170
  if (s == save)
171
    goto noconv;
172
173
  /* Store in ENDPTR the address of one character
174
     past the last character we converted.  */
175
  if (endptr != NULL)
176
    *endptr = (char *) s;
177
178
#ifndef USE_UNSIGNED
179
  /* Check for a value that is within the range of
180
     `unsigned long int', but outside the range of `long int'.	*/
181
  if (negative)
182
  {
183
    if (i  > (ulongtype) TYPE_MIN)
184
      overflow = 1;
185
  }
186
  else if (i > (ulongtype) TYPE_MAX)
187
    overflow = 1;
188
#endif
189
190
  if (overflow)
191
  {
192
    my_errno=ERANGE;
193
#ifdef USE_UNSIGNED
194
    return UTYPE_MAX;
195
#else
196
    return negative ? TYPE_MIN : TYPE_MAX;
197
#endif
198
  }
199
200
  /* Return the result of the appropriate sign.  */
201
  return (negative ? -((longtype) i) : (longtype) i);
202
203
noconv:
204
  /* There was no number to convert.  */
205
  my_errno=EDOM;
206
  if (endptr != NULL)
207
    *endptr = (char *) nptr;
208
  return 0L;
209
}