(__xstrtol) [STRING_TO_UNSIGNED]: Return
[gnulib.git] / lib / xstrtol.c
1 /* A more useful interface to strtol.
2    Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by Jim Meyering. */
19
20 #if HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 /* Some pre-ANSI implementations (e.g. SunOS 4)
25    need stderr defined if assertion checking is enabled.  */
26 #include <stdio.h>
27
28 #if STDC_HEADERS
29 # include <stdlib.h>
30 #endif
31
32 #if HAVE_STRING_H
33 # include <string.h>
34 #else
35 # include <strings.h>
36 # ifndef strchr
37 #  define strchr index
38 # endif
39 #endif
40
41 #include <assert.h>
42
43 #include <errno.h>
44 #ifndef errno
45 extern int errno;
46 #endif
47
48 #if HAVE_LIMITS_H
49 # include <limits.h>
50 #endif
51
52 #ifndef CHAR_BIT
53 # define CHAR_BIT 8
54 #endif
55
56 /* The extra casts work around common compiler bugs.  */
57 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
58 /* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
59    It is necessary at least when t == time_t.  */
60 #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
61                               ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
62 #define TYPE_MAXIMUM(t) (~ (t) 0 - TYPE_MINIMUM (t))
63
64 #ifndef ULONG_MAX
65 # define ULONG_MAX TYPE_MAXIMUM (unsigned long int)
66 #endif
67
68 #ifndef LONG_MAX
69 # define LONG_MAX TYPE_MAXIMUM (long int)
70 #endif
71
72 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
73 # define IN_CTYPE_DOMAIN(c) 1
74 #else
75 # define IN_CTYPE_DOMAIN(c) isascii(c)
76 #endif
77
78 #ifdef isblank
79 # define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c))
80 #else
81 # define ISBLANK(c) ((c) == ' ' || (c) == '\t')
82 #endif
83
84 #include "xstrtol.h"
85
86 __unsigned long int __strtol ();
87
88 static int
89 bkm_scale (__unsigned long int *x, int scale_factor)
90 {
91   __unsigned long int product = *x * scale_factor;
92   if (*x != product / scale_factor)
93     return 1;
94   *x = product;
95   return 0;
96 }
97
98 static int
99 bkm_scale_by_power (__unsigned long int *x, int base, int power)
100 {
101   while (power--)
102     if (bkm_scale (x, base))
103       return 1;
104
105   return 0;
106 }
107
108 /* FIXME: comment.  */
109
110 strtol_error
111 __xstrtol (const char *s, char **ptr, int strtol_base,
112            __unsigned long int *val, const char *valid_suffixes)
113 {
114   char *t_ptr;
115   char **p;
116   __unsigned long int tmp;
117
118   assert (0 <= strtol_base && strtol_base <= 36);
119
120   p = (ptr ? ptr : &t_ptr);
121
122 #if STRING_TO_UNSIGNED
123   {
124     const char *q = s;
125     while (ISBLANK (*q))
126       {
127         ++q;
128       }
129     if (*q == '-')
130       return LONGINT_INVALID;
131   }
132 #endif
133
134   errno = 0;
135   tmp = __strtol (s, p, strtol_base);
136   if (errno != 0)
137     return LONGINT_OVERFLOW;
138   if (*p == s)
139     return LONGINT_INVALID;
140
141   /* Let valid_suffixes == NULL mean `allow any suffix'.  */
142   /* FIXME: update all callers except the one in tail.c changing
143      last parameter NULL to `""'.  */
144   if (!valid_suffixes)
145     {
146       *val = tmp;
147       return LONGINT_OK;
148     }
149
150   if (**p != '\0')
151     {
152       int base = 1024;
153       int suffixes = 1;
154       int overflow;
155
156       if (!strchr (valid_suffixes, **p))
157         return LONGINT_INVALID_SUFFIX_CHAR;
158
159       if (strchr (valid_suffixes, '0'))
160         {
161           /* The ``valid suffix'' '0' is a special flag meaning that
162              an optional second suffix is allowed, which can change
163              the base, e.g. "100MD" for 100 megabytes decimal.  */
164
165           switch (p[0][1])
166             {
167             case 'B':
168               suffixes++;
169               break;
170
171             case 'D':
172               base = 1000;
173               suffixes++;
174               break;
175             }
176         }
177
178       switch (**p)
179         {
180         case 'b':
181           overflow = bkm_scale (&tmp, 512);
182           break;
183
184         case 'B':
185           overflow = bkm_scale (&tmp, 1024);
186           break;
187
188         case 'c':
189           overflow = 0;
190           break;
191
192         case 'E': /* Exa */
193           overflow = bkm_scale_by_power (&tmp, base, 6);
194           break;
195
196         case 'G': /* Giga */
197           overflow = bkm_scale_by_power (&tmp, base, 3);
198           break;
199
200         case 'k': /* kilo */
201           overflow = bkm_scale_by_power (&tmp, base, 1);
202           break;
203
204         case 'M': /* Mega */
205         case 'm': /* 'm' is undocumented; for backward compatibility only */
206           overflow = bkm_scale_by_power (&tmp, base, 2);
207           break;
208
209         case 'P': /* Peta */
210           overflow = bkm_scale_by_power (&tmp, base, 5);
211           break;
212
213         case 'T': /* Tera */
214           overflow = bkm_scale_by_power (&tmp, base, 4);
215           break;
216
217         case 'w':
218           overflow = bkm_scale (&tmp, 2);
219           break;
220
221         case 'Y': /* Yotta */
222           overflow = bkm_scale_by_power (&tmp, base, 8);
223           break;
224
225         case 'Z': /* Zetta */
226           overflow = bkm_scale_by_power (&tmp, base, 7);
227           break;
228
229         default:
230           return LONGINT_INVALID_SUFFIX_CHAR;
231           break;
232         }
233
234       if (overflow)
235         return LONGINT_OVERFLOW;
236
237       (*p) += suffixes;
238     }
239
240   *val = tmp;
241   return LONGINT_OK;
242 }
243
244 #ifdef TESTING_XSTRTO
245
246 # include <stdio.h>
247 # include "error.h"
248
249 char *program_name;
250
251 int
252 main (int argc, char** argv)
253 {
254   strtol_error s_err;
255   int i;
256
257   program_name = argv[0];
258   for (i=1; i<argc; i++)
259     {
260       char *p;
261       __unsigned long int val;
262
263       s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw");
264       if (s_err == LONGINT_OK)
265         {
266           printf ("%s->%lu (%s)\n", argv[i], val, p);
267         }
268       else
269         {
270           STRTOL_FATAL_ERROR (argv[i], "arg", s_err);
271         }
272     }
273   exit (0);
274 }
275
276 #endif /* TESTING_XSTRTO */