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