~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
481.1.3 by Monty Taylor
Replaced long long with int64_t.
18
  convert string to long, unsigned long, int64_t or uint64_t.
1 by brian
clean slate
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
52
#define TYPE_MIN LONGLONG_MIN
53
#define TYPE_MAX LONGLONG_MAX
152 by Brian Aker
longlong replacement
54
#define longtype int64_t
151 by Brian Aker
Ulonglong to uint64_t
55
#define ulongtype uint64_t
1 by brian
clean slate
56
#ifdef USE_UNSIGNED
57
#define function ulongtype strtoull
58
#else
59
#define function longtype strtoll
60
#endif
61
#else
62
#define TYPE_MIN LONG_MIN
63
#define TYPE_MAX LONG_MAX
64
#define longtype long
65
#define ulongtype unsigned long
66
#ifdef USE_UNSIGNED
67
#define function ulongtype strtoul
68
#else
69
#define function longtype strtol
70
#endif
71
#endif
72
73
74
/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
75
   If BASE is 0 the base is determined by the presence of a leading
76
   zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
77
   If BASE is < 2 or > 36, it is reset to 10.
78
   If ENDPTR is not NULL, a pointer to the character after the last
79
   one converted is stored in *ENDPTR.	*/
80
81
82
function (const char *nptr,char **endptr,int base)
83
{
84
  int negative;
85
  register ulongtype cutoff;
86
  register unsigned int cutlim;
87
  register ulongtype i;
88
  register const char *s;
481 by Brian Aker
Remove all of uchar.
89
  register unsigned char c;
1 by brian
clean slate
90
  const char *save;
91
  int overflow;
92
93
  if (base < 0 || base == 1 || base > 36)
94
    base = 10;
95
96
  s = nptr;
97
98
  /* Skip white space.	*/
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
99
  while (my_isspace(&my_charset_utf8_general_ci, *s))
1 by brian
clean slate
100
    ++s;
101
  if (*s == '\0')
102
  {
103
    goto noconv;
104
  }
105
106
  /* Check for a sign.	*/
107
  negative= 0;
108
  if (*s == '-')
109
  {
110
    negative = 1;
111
    ++s;
112
  }
113
  else if (*s == '+')
114
  {
115
    ++s;
116
  }
117
    
118
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
119
  if (base == 16 && s[0] == '0' && my_toupper (&my_charset_utf8_general_ci, s[1]) == 'X')
1 by brian
clean slate
120
    s += 2;
121
122
  /* If BASE is zero, figure it out ourselves.	*/
123
  if (base == 0)
124
  {
125
    if (*s == '0')
126
    {
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
127
      if (my_toupper (&my_charset_utf8_general_ci, s[1]) == 'X')
1 by brian
clean slate
128
      {
129
	s += 2;
130
	base = 16;
131
      }
132
      else
133
	base = 8;
134
    }
135
    else
136
      base = 10;
137
  }
138
139
  /* Save the pointer so we can check later if anything happened.  */
140
  save = s;
141
365.2.9 by Monty Taylor
Got rid of all instances of ~0
142
  cutoff = UINT64_MAX / (unsigned long int) base;
143
  cutlim = (uint) (UINT64_MAX % (unsigned long int) base);
1 by brian
clean slate
144
145
  overflow = 0;
146
  i = 0;
147
  for (c = *s; c != '\0'; c = *++s)
148
  {
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
149
    if (my_isdigit (&my_charset_utf8_general_ci, c))
1 by brian
clean slate
150
      c -= '0';
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
151
    else if (my_isalpha (&my_charset_utf8_general_ci, c))
152
      c = my_toupper (&my_charset_utf8_general_ci, c) - 'A' + 10;
1 by brian
clean slate
153
    else
154
      break;
155
    if (c >= base)
156
      break;
157
    /* Check for overflow.  */
158
    if (i > cutoff || (i == cutoff && c > cutlim))
159
      overflow = 1;
160
    else
161
    {
162
      i *= (ulongtype) base;
163
      i += c;
164
    }
165
  }
166
167
  /* Check if anything actually happened.  */
168
  if (s == save)
169
    goto noconv;
170
171
  /* Store in ENDPTR the address of one character
172
     past the last character we converted.  */
173
  if (endptr != NULL)
174
    *endptr = (char *) s;
175
176
#ifndef USE_UNSIGNED
177
  /* Check for a value that is within the range of
178
     `unsigned long int', but outside the range of `long int'.	*/
179
  if (negative)
180
  {
181
    if (i  > (ulongtype) TYPE_MIN)
182
      overflow = 1;
183
  }
184
  else if (i > (ulongtype) TYPE_MAX)
185
    overflow = 1;
186
#endif
187
188
  if (overflow)
189
  {
190
    my_errno=ERANGE;
191
#ifdef USE_UNSIGNED
365.2.9 by Monty Taylor
Got rid of all instances of ~0
192
    return UINT64_MAX;
1 by brian
clean slate
193
#else
194
    return negative ? TYPE_MIN : TYPE_MAX;
195
#endif
196
  }
197
198
  /* Return the result of the appropriate sign.  */
199
  return (negative ? -((longtype) i) : (longtype) i);
200
201
noconv:
202
  /* There was no number to convert.  */
203
  my_errno=EDOM;
204
  if (endptr != NULL)
205
    *endptr = (char *) nptr;
206
  return 0L;
207
}