1104862Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
2104862Sru   Free Software Foundation, Inc.
375584Sru     Written by James Clark (jjc@jclark.com)
475584Sru
575584SruThis file is part of groff.
675584Sru
775584Srugroff is free software; you can redistribute it and/or modify it under
875584Sruthe terms of the GNU General Public License as published by the Free
975584SruSoftware Foundation; either version 2, or (at your option) any later
1075584Sruversion.
1175584Sru
1275584Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
1375584SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
1475584SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1575584Srufor more details.
1675584Sru
1775584SruYou should have received a copy of the GNU General Public License along
1875584Sruwith groff; see the file COPYING.  If not, write to the Free Software
19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
2075584Sru
21104862Sru#ifdef HAVE_CONFIG_H
22104862Sru#include <config.h>
23104862Sru#endif
24104862Sru
2575584Sru#include <string.h>
2675584Sru#include <ctype.h>
2775584Sru#include <errno.h>
2875584Sru
2975584Sru#ifdef HAVE_LIMITS_H
3075584Sru#include <limits.h>
3175584Sru#endif
3275584Sru
3375584Sru#ifndef LONG_MAX
3475584Sru#define LONG_MAX  2147483647
3575584Sru#endif
3675584Sru
3775584Sru#ifndef LONG_MIN
3875584Sru#define LONG_MIN (-LONG_MAX-1)
3975584Sru#endif
4075584Sru
4175584Sru#ifdef isascii
4275584Sru#define ISASCII(c) isascii(c)
4375584Sru#else
4475584Sru#define ISASCII(c) (1)
4575584Sru#endif
4675584Sru
4775584Srulong strtol(str, ptr, base)
4875584Sru     char *str, **ptr;
4975584Sru     int base;
5075584Sru{
5175584Sru  char *start = str;
5275584Sru  int neg = 0;
5375584Sru  long val;
5475584Sru  char *p;
5575584Sru  static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
5675584Sru
5775584Sru  while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str))
5875584Sru    str++;
5975584Sru
6075584Sru  if (*str == '-') {
6175584Sru    neg = 1;
6275584Sru    str++;
6375584Sru  }
6475584Sru  if (base == 0) {
6575584Sru    if (*str == '0') {
6675584Sru      if (str[1] == 'x' || str[1] == 'X') {
6775584Sru	str += 2;
6875584Sru	base = 16;
6975584Sru      }
7075584Sru      else
7175584Sru	base = 8;
7275584Sru    }
7375584Sru    else
7475584Sru      base = 10;
7575584Sru  }
7675584Sru  if (base < 2 || base > 36)
7775584Sru    base = 10;
7875584Sru  else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
7975584Sru    str += 2;
8075584Sru
8175584Sru  p = strchr(digits, (ISASCII((unsigned char)*str)
8275584Sru		      && isupper((unsigned char)*str)
8375584Sru		      ? tolower((unsigned char)*str)
8475584Sru		      : *str));
8575584Sru  if (p == 0 || (val = (p - digits)) >= base) {
8675584Sru    if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) {
8775584Sru      if (ptr)
8875584Sru	*ptr = str - 1;
8975584Sru    }
9075584Sru    else {
9175584Sru      if (ptr)
9275584Sru	*ptr = start;
9375584Sru      errno = ERANGE;
9475584Sru    }
9575584Sru    return 0;
9675584Sru  }
9775584Sru  if (neg)
9875584Sru    val = -val;
9975584Sru
10075584Sru  while (*++str != '\0') {
10175584Sru    int n;
10275584Sru
10375584Sru    p = strchr(digits, (ISASCII((unsigned char)*str)
10475584Sru			&& isupper((unsigned char)*str)
10575584Sru			? tolower((unsigned char)*str) : *str));
10675584Sru    if (p == 0)
10775584Sru      break;
10875584Sru    n = p - digits;
10975584Sru    if (n >= base)
11075584Sru      break;
11175584Sru    if (neg) {
11275584Sru      if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) {
11375584Sru	val = LONG_MIN;
11475584Sru	errno = ERANGE;
11575584Sru      }
11675584Sru      else
11775584Sru	val = val*base - n;
11875584Sru    }
11975584Sru    else {
12075584Sru      if (val > (LONG_MAX - n)/base) {
12175584Sru	val = LONG_MAX;
12275584Sru	errno = ERANGE;
12375584Sru      }
12475584Sru      else
12575584Sru	val = val*base + n;
12675584Sru    }
12775584Sru  }
12875584Sru
12975584Sru  if (ptr)
13075584Sru    *ptr = str;
13175584Sru
13275584Sru  return val;
13375584Sru}
134