11556Srgrimes/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
21556Srgrimes   Free Software Foundation, Inc.
31556Srgrimes     Written by James Clark (jjc@jclark.com)
41556Srgrimes
51556SrgrimesThis file is part of groff.
61556Srgrimes
71556Srgrimesgroff is free software; you can redistribute it and/or modify it under
81556Srgrimesthe terms of the GNU General Public License as published by the Free
91556SrgrimesSoftware Foundation; either version 2, or (at your option) any later
101556Srgrimesversion.
111556Srgrimes
121556Srgrimesgroff is distributed in the hope that it will be useful, but WITHOUT ANY
131556SrgrimesWARRANTY; without even the implied warranty of MERCHANTABILITY or
141556SrgrimesFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
151556Srgrimesfor more details.
161556Srgrimes
171556SrgrimesYou should have received a copy of the GNU General Public License along
181556Srgrimeswith groff; see the file COPYING.  If not, write to the Free Software
191556SrgrimesFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
201556Srgrimes
211556Srgrimes#ifdef HAVE_CONFIG_H
221556Srgrimes#include <config.h>
231556Srgrimes#endif
241556Srgrimes
251556Srgrimes#include <string.h>
261556Srgrimes#include <ctype.h>
271556Srgrimes#include <errno.h>
281556Srgrimes
291556Srgrimes#ifdef HAVE_LIMITS_H
301556Srgrimes#include <limits.h>
311556Srgrimes#endif
321556Srgrimes
331556Srgrimes#ifndef LONG_MAX
341556Srgrimes#define LONG_MAX  2147483647
351556Srgrimes#endif
361556Srgrimes
371556Srgrimes#ifndef LONG_MIN
381556Srgrimes#define LONG_MIN (-LONG_MAX-1)
3936049Scharnier#endif
4036049Scharnier
4136049Scharnier#ifdef isascii
4236049Scharnier#define ISASCII(c) isascii(c)
4350471Speter#else
441556Srgrimes#define ISASCII(c) (1)
451556Srgrimes#endif
461556Srgrimes
471556Srgrimeslong strtol(str, ptr, base)
481556Srgrimes     char *str, **ptr;
491556Srgrimes     int base;
501556Srgrimes{
511556Srgrimes  char *start = str;
521556Srgrimes  int neg = 0;
531556Srgrimes  long val;
541556Srgrimes  char *p;
551556Srgrimes  static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
561556Srgrimes
571556Srgrimes  while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str))
581556Srgrimes    str++;
591556Srgrimes
601556Srgrimes  if (*str == '-') {
611556Srgrimes    neg = 1;
621556Srgrimes    str++;
631556Srgrimes  }
641556Srgrimes  if (base == 0) {
651556Srgrimes    if (*str == '0') {
661556Srgrimes      if (str[1] == 'x' || str[1] == 'X') {
671556Srgrimes	str += 2;
681556Srgrimes	base = 16;
691556Srgrimes      }
701556Srgrimes      else
711556Srgrimes	base = 8;
721556Srgrimes    }
7346684Skris    else
741556Srgrimes      base = 10;
751556Srgrimes  }
761556Srgrimes  if (base < 2 || base > 36)
771556Srgrimes    base = 10;
781556Srgrimes  else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
791556Srgrimes    str += 2;
801556Srgrimes
811556Srgrimes  p = strchr(digits, (ISASCII((unsigned char)*str)
821556Srgrimes		      && isupper((unsigned char)*str)
831556Srgrimes		      ? tolower((unsigned char)*str)
841556Srgrimes		      : *str));
851556Srgrimes  if (p == 0 || (val = (p - digits)) >= base) {
861556Srgrimes    if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) {
871556Srgrimes      if (ptr)
881556Srgrimes	*ptr = str - 1;
891556Srgrimes    }
901556Srgrimes    else {
911556Srgrimes      if (ptr)
921556Srgrimes	*ptr = start;
931556Srgrimes      errno = ERANGE;
9476017Skris    }
951556Srgrimes    return 0;
961556Srgrimes  }
971556Srgrimes  if (neg)
981556Srgrimes    val = -val;
991556Srgrimes
1001556Srgrimes  while (*++str != '\0') {
1011556Srgrimes    int n;
1021556Srgrimes
1031556Srgrimes    p = strchr(digits, (ISASCII((unsigned char)*str)
1041556Srgrimes			&& isupper((unsigned char)*str)
1051556Srgrimes			? tolower((unsigned char)*str) : *str));
1061556Srgrimes    if (p == 0)
1071556Srgrimes      break;
1081556Srgrimes    n = p - digits;
1091556Srgrimes    if (n >= base)
1101556Srgrimes      break;
1111556Srgrimes    if (neg) {
1121556Srgrimes      if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) {
1131556Srgrimes	val = LONG_MIN;
1141556Srgrimes	errno = ERANGE;
1151556Srgrimes      }
1161556Srgrimes      else
1171556Srgrimes	val = val*base - n;
1181556Srgrimes    }
1191556Srgrimes    else {
1201556Srgrimes      if (val > (LONG_MAX - n)/base) {
1211556Srgrimes	val = LONG_MAX;
1221556Srgrimes	errno = ERANGE;
1231556Srgrimes      }
1241556Srgrimes      else
1251556Srgrimes	val = val*base + n;
12676017Skris    }
1271556Srgrimes  }
1281556Srgrimes
1291556Srgrimes  if (ptr)
1301556Srgrimes    *ptr = str;
1311556Srgrimes
1321556Srgrimes  return val;
1331556Srgrimes}
13476017Skris