groff before CVS: release 1.05
[s-roff.git] / lib / strtol.c
blob596899e861d41fa21bb682fa8b9d32d1103b17ec
1 /* Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
2 Written by James Clark (jjc@jclark.uucp)
4 This file is part of groff.
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 1, or (at your option) any later
9 version.
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.
16 You should have received a copy of the GNU General Public License along
17 with groff; see the file LICENSE. If not, write to the Free Software
18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 #include <string.h>
21 #include <ctype.h>
22 #include <errno.h>
24 /* Not everybody has limits.h. Sigh. */
26 #include "lib.h"
27 #ifndef LONG_MAX
28 #define LONG_MAX INT_MAX
29 #endif
30 #ifndef LONG_MIN
31 #define LONG_MIN INT_MIN
32 #endif
34 long strtol(str, ptr, base)
35 char *str, **ptr;
36 int base;
38 char *start = str;
39 int neg = 0;
40 long val;
41 char *p;
42 static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
44 while (isascii(*str) && isspace(*str))
45 str++;
47 if (*str == '-') {
48 neg = 1;
49 str++;
51 if (base == 0) {
52 if (*str == '0') {
53 if (str[1] == 'x' || str[1] == 'X') {
54 str += 2;
55 base = 16;
57 else
58 base = 8;
60 else
61 base = 10;
63 if (base < 2 || base > 36)
64 base = 10;
65 else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
66 str += 2;
68 p = strchr(digits, isascii(*str) && isupper(*str) ? tolower(*str) : *str);
69 if (p == 0 || (val = (p - digits)) >= base) {
70 if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) {
71 if (ptr)
72 *ptr = str - 1;
74 else {
75 if (ptr)
76 *ptr = start;
77 errno = ERANGE;
79 return 0;
81 if (neg)
82 val = -val;
84 while (*++str != '\0') {
85 int n;
87 p = strchr(digits, isascii(*str) && isupper(*str) ? tolower(*str) : *str);
88 if (p == 0)
89 break;
90 n = p - digits;
91 if (n >= base)
92 break;
93 if (neg) {
94 if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) {
95 val = LONG_MIN;
96 errno = ERANGE;
98 else
99 val = val*base - n;
101 else {
102 if (val > (LONG_MAX - n)/base) {
103 val = LONG_MAX;
104 errno = ERANGE;
106 else
107 val = val*base + n;
111 if (ptr)
112 *ptr = str;
114 return val;