155714Skris/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
255714Skris   Free Software Foundation, Inc.
355714Skris     Written by James Clark (jjc@jclark.com)
455714Skris
555714SkrisThis file is part of groff.
655714Skris
755714Skrisgroff is free software; you can redistribute it and/or modify it under
855714Skristhe terms of the GNU General Public License as published by the Free
955714SkrisSoftware Foundation; either version 2, or (at your option) any later
1055714Skrisversion.
1155714Skris
1255714Skrisgroff is distributed in the hope that it will be useful, but WITHOUT ANY
1355714SkrisWARRANTY; without even the implied warranty of MERCHANTABILITY or
1455714SkrisFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1555714Skrisfor more details.
1655714Skris
1755714SkrisYou should have received a copy of the GNU General Public License along
1855714Skriswith groff; see the file COPYING.  If not, write to the Free Software
1955714SkrisFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
2055714Skris
2155714Skris#ifdef HAVE_CONFIG_H
2255714Skris#include <config.h>
2355714Skris#endif
2455714Skris
2555714Skris#include <string.h>
2655714Skris#include <ctype.h>
2755714Skris#include <errno.h>
2855714Skris
2955714Skris#ifdef HAVE_LIMITS_H
3055714Skris#include <limits.h>
3155714Skris#endif
3255714Skris
3355714Skris#ifndef LONG_MAX
3455714Skris#define LONG_MAX  2147483647
3555714Skris#endif
3655714Skris
3755714Skris#ifndef LONG_MIN
3855714Skris#define LONG_MIN (-LONG_MAX-1)
3955714Skris#endif
4055714Skris
4155714Skris#ifdef isascii
4255714Skris#define ISASCII(c) isascii(c)
4355714Skris#else
4455714Skris#define ISASCII(c) (1)
4555714Skris#endif
4655714Skris
4755714Skrislong strtol(str, ptr, base)
4855714Skris     char *str, **ptr;
4955714Skris     int base;
5055714Skris{
5155714Skris  char *start = str;
5255714Skris  int neg = 0;
5355714Skris  long val;
5455714Skris  char *p;
5555714Skris  static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
5655714Skris
5755714Skris  while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str))
5855714Skris    str++;
5955714Skris
6055714Skris  if (*str == '-') {
61109998Smarkm    neg = 1;
6255714Skris    str++;
63194206Ssimon  }
64194206Ssimon  if (base == 0) {
65194206Ssimon    if (*str == '0') {
66194206Ssimon      if (str[1] == 'x' || str[1] == 'X') {
67194206Ssimon	str += 2;
68194206Ssimon	base = 16;
69111147Snectar      }
70109998Smarkm      else
71111147Snectar	base = 8;
7255714Skris    }
73194206Ssimon    else
74194206Ssimon      base = 10;
75194206Ssimon  }
76194206Ssimon  if (base < 2 || base > 36)
77194206Ssimon    base = 10;
78194206Ssimon  else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
79194206Ssimon    str += 2;
80194206Ssimon
81194206Ssimon  p = strchr(digits, (ISASCII((unsigned char)*str)
82194206Ssimon		      && isupper((unsigned char)*str)
83194206Ssimon		      ? tolower((unsigned char)*str)
84194206Ssimon		      : *str));
85194206Ssimon  if (p == 0 || (val = (p - digits)) >= base) {
86194206Ssimon    if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) {
87194206Ssimon      if (ptr)
88194206Ssimon	*ptr = str - 1;
89194206Ssimon    }
90194206Ssimon    else {
91194206Ssimon      if (ptr)
92194206Ssimon	*ptr = start;
93194206Ssimon      errno = ERANGE;
94194206Ssimon    }
95194206Ssimon    return 0;
96194206Ssimon  }
97194206Ssimon  if (neg)
98194206Ssimon    val = -val;
99194206Ssimon
100194206Ssimon  while (*++str != '\0') {
101194206Ssimon    int n;
102194206Ssimon
103194206Ssimon    p = strchr(digits, (ISASCII((unsigned char)*str)
104194206Ssimon			&& isupper((unsigned char)*str)
105194206Ssimon			? tolower((unsigned char)*str) : *str));
106194206Ssimon    if (p == 0)
107194206Ssimon      break;
108194206Ssimon    n = p - digits;
109194206Ssimon    if (n >= base)
110194206Ssimon      break;
111111147Snectar    if (neg) {
112194206Ssimon      if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) {
113194206Ssimon	val = LONG_MIN;
114194206Ssimon	errno = ERANGE;
115194206Ssimon      }
116194206Ssimon      else
117194206Ssimon	val = val*base - n;
118194206Ssimon    }
119194206Ssimon    else {
120194206Ssimon      if (val > (LONG_MAX - n)/base) {
121194206Ssimon	val = LONG_MAX;
122194206Ssimon	errno = ERANGE;
123194206Ssimon      }
124194206Ssimon      else
125194206Ssimon	val = val*base + n;
126194206Ssimon    }
127194206Ssimon  }
128194206Ssimon
129194206Ssimon  if (ptr)
130194206Ssimon    *ptr = str;
131194206Ssimon
132194206Ssimon  return val;
133194206Ssimon}
134194206Ssimon