strtol.c revision 75584
1/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. 2 Written by James Clark (jjc@jclark.com) 3 4This file is part of groff. 5 6groff is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 2, or (at your option) any later 9version. 10 11groff is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16You should have received a copy of the GNU General Public License along 17with groff; see the file COPYING. If not, write to the Free Software 18Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19 20#include <string.h> 21#include <ctype.h> 22#include <errno.h> 23 24#ifdef HAVE_LIMITS_H 25#include <limits.h> 26#endif 27 28#ifndef LONG_MAX 29#define LONG_MAX 2147483647 30#endif 31 32#ifndef LONG_MIN 33#define LONG_MIN (-LONG_MAX-1) 34#endif 35 36#ifdef isascii 37#define ISASCII(c) isascii(c) 38#else 39#define ISASCII(c) (1) 40#endif 41 42long strtol(str, ptr, base) 43 char *str, **ptr; 44 int base; 45{ 46 char *start = str; 47 int neg = 0; 48 long val; 49 char *p; 50 static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 51 52 while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str)) 53 str++; 54 55 if (*str == '-') { 56 neg = 1; 57 str++; 58 } 59 if (base == 0) { 60 if (*str == '0') { 61 if (str[1] == 'x' || str[1] == 'X') { 62 str += 2; 63 base = 16; 64 } 65 else 66 base = 8; 67 } 68 else 69 base = 10; 70 } 71 if (base < 2 || base > 36) 72 base = 10; 73 else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) 74 str += 2; 75 76 p = strchr(digits, (ISASCII((unsigned char)*str) 77 && isupper((unsigned char)*str) 78 ? tolower((unsigned char)*str) 79 : *str)); 80 if (p == 0 || (val = (p - digits)) >= base) { 81 if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) { 82 if (ptr) 83 *ptr = str - 1; 84 } 85 else { 86 if (ptr) 87 *ptr = start; 88 errno = ERANGE; 89 } 90 return 0; 91 } 92 if (neg) 93 val = -val; 94 95 while (*++str != '\0') { 96 int n; 97 98 p = strchr(digits, (ISASCII((unsigned char)*str) 99 && isupper((unsigned char)*str) 100 ? tolower((unsigned char)*str) : *str)); 101 if (p == 0) 102 break; 103 n = p - digits; 104 if (n >= base) 105 break; 106 if (neg) { 107 if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) { 108 val = LONG_MIN; 109 errno = ERANGE; 110 } 111 else 112 val = val*base - n; 113 } 114 else { 115 if (val > (LONG_MAX - n)/base) { 116 val = LONG_MAX; 117 errno = ERANGE; 118 } 119 else 120 val = val*base + n; 121 } 122 } 123 124 if (ptr) 125 *ptr = str; 126 127 return val; 128} 129