(__strtol): Remove prototype altogether.
[gnulib.git] / lib / xstrtol.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #ifdef STDC_HEADERS
6 #include <stdlib.h>
7 #endif
8
9 #ifdef HAVE_STRING_H
10 # include <string.h>
11 #else
12 # include <strings.h>
13 # ifndef strchr
14 #  define strchr index
15 # endif
16 #endif
17
18 #define NDEBUG
19 #include <assert.h>
20
21 #include <errno.h>
22 #ifndef errno
23 extern int errno;
24 #endif
25
26 #if HAVE_LIMITS_H
27 #include <limits.h>
28 #endif
29
30 #ifndef ULONG_MAX
31 #define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
32 #endif
33
34 #ifndef LONG_MAX
35 #define LONG_MAX ((long int) (ULONG_MAX >> 1))
36 #endif
37
38 #include "xstrtol.h"
39
40 #define BKM_SCALE(x, scale_factor, error_return)                        \
41       do                                                                \
42         {                                                               \
43           if ((x) > (double) __ZLONG_MAX / (scale_factor))              \
44             return (error_return);                                      \
45           (x) *= (scale_factor);                                        \
46         }                                                               \
47       while (0)
48
49 __unsigned long int __strtol ();
50
51 /* FIXME: comment.  */
52
53 strtol_error
54 __xstrtol (s, ptr, base, val, valid_suffixes)
55      const char *s;
56      char **ptr;
57      int base;
58      __unsigned long int *val;
59      const char *valid_suffixes;
60 {
61   char *t_ptr;
62   char **p;
63   __unsigned long int tmp;
64
65   assert (0 <= base && base <= 36);
66
67   p = (ptr ? ptr : &t_ptr);
68
69   errno = 0;
70   tmp = __strtol (s, p, base);
71   if (errno != 0)
72     return LONGINT_OVERFLOW;
73   if (*p == s)
74     return LONGINT_INVALID;
75   if (!valid_suffixes)
76     {
77       if (**p == '\0')
78         {
79           *val = tmp;
80           return LONGINT_OK;
81         }
82       else
83         return LONGINT_INVALID_SUFFIX_CHAR;
84     }
85
86   if (**p != '\0' && strchr (valid_suffixes, **p))
87     {
88       switch (**p)
89         {
90         case 'b':
91           BKM_SCALE (tmp, 512, LONGINT_OVERFLOW);
92           ++(*p);
93           break;
94
95         case 'c':
96           ++(*p);
97           break;
98
99         case 'B':
100         case 'k':
101           BKM_SCALE (tmp, 1024, LONGINT_OVERFLOW);
102           ++(*p);
103           break;
104
105         case 'm':
106           BKM_SCALE (tmp, 1024 * 1024, LONGINT_OVERFLOW);
107           ++(*p);
108           break;
109
110         case 'w':
111           BKM_SCALE (tmp, 2, LONGINT_OVERFLOW);
112           ++(*p);
113           break;
114
115         default:
116           return LONGINT_INVALID_SUFFIX_CHAR;
117           break;
118         }
119     }
120
121   *val = tmp;
122   return LONGINT_OK;
123 }
124
125 #ifdef TESTING_XSTRTO
126
127 #include <stdio.h>
128 #include "error.h"
129
130 char *program_name;
131
132 int
133 main (int argc, char** argv)
134 {
135   strtol_error s_err;
136   int i;
137
138   program_name = argv[0];
139   for (i=1; i<argc; i++)
140     {
141       char *p;
142       __unsigned long int val;
143
144       s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw");
145       if (s_err == LONGINT_OK)
146         {
147           printf ("%s->%lu (%s)\n", argv[i], val, p);
148         }
149       else
150         {
151           STRTOL_FATAL_ERROR (argv[i], "arg", s_err);
152         }
153     }
154   exit (0);
155 }
156 #endif /* TESTING_XSTRTO */