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