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