Imported Upstream version 1.22.4
[platform/upstream/groff.git] / src / libs / libgroff / strtol.c
1 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
2      Written by James Clark (jjc@jclark.com)
3
4 This file is part of groff.
5
6 groff is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 groff is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <string.h>
24 #include <ctype.h>
25 #include <errno.h>
26
27 #ifdef HAVE_LIMITS_H
28 #include <limits.h>
29 #endif
30
31 #ifndef LONG_MAX
32 #define LONG_MAX  2147483647
33 #endif
34
35 #ifndef LONG_MIN
36 #define LONG_MIN (-LONG_MAX-1)
37 #endif
38
39 #ifdef isascii
40 #define ISASCII(c) isascii(c)
41 #else
42 #define ISASCII(c) (1)
43 #endif
44
45 long strtol(str, ptr, base)
46      char *str, **ptr;
47      int base;
48 {
49   char *start = str;
50   int neg = 0;
51   long val;
52   char *p;
53   static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
54
55   while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str))
56     str++;
57
58   if (*str == '-') {
59     neg = 1;
60     str++;
61   }
62   if (base == 0) {
63     if (*str == '0') {
64       if (str[1] == 'x' || str[1] == 'X') {
65         str += 2;
66         base = 16;
67       }
68       else
69         base = 8;
70     }
71     else
72       base = 10;
73   }
74   if (base < 2 || base > 36)
75     base = 10;
76   else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
77     str += 2;
78
79   p = strchr(digits, (ISASCII((unsigned char)*str)
80                       && isupper((unsigned char)*str)
81                       ? tolower((unsigned char)*str)
82                       : *str));
83   if (p == 0 || (val = (p - digits)) >= base) {
84     if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) {
85       if (ptr)
86         *ptr = str - 1;
87     }
88     else {
89       if (ptr)
90         *ptr = start;
91       errno = ERANGE;
92     }
93     return 0;
94   }
95   if (neg)
96     val = -val;
97     
98   while (*++str != '\0') {
99     int n;
100
101     p = strchr(digits, (ISASCII((unsigned char)*str)
102                         && isupper((unsigned char)*str)
103                         ? tolower((unsigned char)*str) : *str));
104     if (p == 0)
105       break;
106     n = p - digits;
107     if (n >= base)
108       break;
109     if (neg) {
110       if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) {
111         val = LONG_MIN;
112         errno = ERANGE;
113       }
114       else
115         val = val*base - n;
116     }
117     else {
118       if (val > (LONG_MAX - n)/base) {
119         val = LONG_MAX;
120         errno = ERANGE;
121       }
122       else
123         val = val*base + n;
124     }
125   }
126   
127   if (ptr)
128     *ptr = str;
129
130   return val;
131 }