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