1/* A more useful interface to strtol. 2 Copyright (C) 1995, 1996, 1998-2000 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17 18/* Written by Jim Meyering. */ 19 20#if HAVE_CONFIG_H 21# include <config.h> 22#endif 23 24#ifndef __strtol 25# define __strtol strtol 26# define __strtol_t long int 27# define __xstrtol xstrtol 28#endif 29 30/* Some pre-ANSI implementations (e.g. SunOS 4) 31 need stderr defined if assertion checking is enabled. */ 32#include <stdio.h> 33 34#if STDC_HEADERS 35# include <stdlib.h> 36#endif 37 38#if HAVE_STRING_H 39# include <string.h> 40#else 41# include <strings.h> 42# ifndef strchr 43# define strchr index 44# endif 45#endif 46 47#include <assert.h> 48#include <ctype.h> 49 50#include <errno.h> 51#ifndef errno 52extern int errno; 53#endif 54 55#if HAVE_LIMITS_H 56# include <limits.h> 57#endif 58 59#ifndef CHAR_BIT 60# define CHAR_BIT 8 61#endif 62 63/* The extra casts work around common compiler bugs. */ 64#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) 65/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. 66 It is necessary at least when t == time_t. */ 67#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ 68 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) 69#define TYPE_MAXIMUM(t) (~ (t) 0 - TYPE_MINIMUM (t)) 70 71#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) 72# define IN_CTYPE_DOMAIN(c) 1 73#else 74# define IN_CTYPE_DOMAIN(c) isascii(c) 75#endif 76 77#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) 78 79#include "xstrtol.h" 80 81#ifndef strtol 82long int strtol (); 83#endif 84 85#ifndef strtoul 86unsigned long int strtoul (); 87#endif 88 89#ifndef strtoumax 90uintmax_t strtoumax (); 91#endif 92 93static int 94bkm_scale (__strtol_t *x, int scale_factor) 95{ 96 __strtol_t product = *x * scale_factor; 97 if (*x != product / scale_factor) 98 return 1; 99 *x = product; 100 return 0; 101} 102 103static int 104bkm_scale_by_power (__strtol_t *x, int base, int power) 105{ 106 while (power--) 107 if (bkm_scale (x, base)) 108 return 1; 109 110 return 0; 111} 112 113/* FIXME: comment. */ 114 115strtol_error 116__xstrtol (const char *s, char **ptr, int strtol_base, 117 __strtol_t *val, const char *valid_suffixes) 118{ 119 char *t_ptr; 120 char **p; 121 __strtol_t tmp; 122 123 assert (0 <= strtol_base && strtol_base <= 36); 124 125 p = (ptr ? ptr : &t_ptr); 126 127 if (! TYPE_SIGNED (__strtol_t)) 128 { 129 const char *q = s; 130 while (ISSPACE ((unsigned char) *q)) 131 ++q; 132 if (*q == '-') 133 return LONGINT_INVALID; 134 } 135 136 errno = 0; 137 tmp = __strtol (s, p, strtol_base); 138 if (errno != 0) 139 return LONGINT_OVERFLOW; 140 if (*p == s) 141 return LONGINT_INVALID; 142 143 /* Let valid_suffixes == NULL mean `allow any suffix'. */ 144 /* FIXME: update all callers except the ones that allow suffixes 145 after the number, changing last parameter NULL to `""'. */ 146 if (!valid_suffixes) 147 { 148 *val = tmp; 149 return LONGINT_OK; 150 } 151 152 if (**p != '\0') 153 { 154 int base = 1024; 155 int suffixes = 1; 156 int overflow; 157 158 if (!strchr (valid_suffixes, **p)) 159 { 160 *val = tmp; 161 return LONGINT_INVALID_SUFFIX_CHAR; 162 } 163 164 if (strchr (valid_suffixes, '0')) 165 { 166 /* The ``valid suffix'' '0' is a special flag meaning that 167 an optional second suffix is allowed, which can change 168 the base, e.g. "100MD" for 100 megabytes decimal. */ 169 170 switch (p[0][1]) 171 { 172 case 'B': 173 suffixes++; 174 break; 175 176 case 'D': 177 base = 1000; 178 suffixes++; 179 break; 180 } 181 } 182 183 switch (**p) 184 { 185 case 'b': 186 overflow = bkm_scale (&tmp, 512); 187 break; 188 189 case 'B': 190 overflow = bkm_scale (&tmp, 1024); 191 break; 192 193 case 'c': 194 overflow = 0; 195 break; 196 197 case 'E': /* Exa */ 198 overflow = bkm_scale_by_power (&tmp, base, 6); 199 break; 200 201 case 'G': /* Giga */ 202 overflow = bkm_scale_by_power (&tmp, base, 3); 203 break; 204 205 case 'k': /* kilo */ 206 overflow = bkm_scale_by_power (&tmp, base, 1); 207 break; 208 209 case 'M': /* Mega */ 210 case 'm': /* 'm' is undocumented; for backward compatibility only */ 211 overflow = bkm_scale_by_power (&tmp, base, 2); 212 break; 213 214 case 'P': /* Peta */ 215 overflow = bkm_scale_by_power (&tmp, base, 5); 216 break; 217 218 case 'T': /* Tera */ 219 overflow = bkm_scale_by_power (&tmp, base, 4); 220 break; 221 222 case 'w': 223 overflow = bkm_scale (&tmp, 2); 224 break; 225 226 case 'Y': /* Yotta */ 227 overflow = bkm_scale_by_power (&tmp, base, 8); 228 break; 229 230 case 'Z': /* Zetta */ 231 overflow = bkm_scale_by_power (&tmp, base, 7); 232 break; 233 234 default: 235 *val = tmp; 236 return LONGINT_INVALID_SUFFIX_CHAR; 237 break; 238 } 239 240 if (overflow) 241 return LONGINT_OVERFLOW; 242 243 (*p) += suffixes; 244 } 245 246 *val = tmp; 247 return LONGINT_OK; 248} 249 250#ifdef TESTING_XSTRTO 251 252# include <stdio.h> 253# include "error.h" 254 255char *program_name; 256 257int 258main (int argc, char** argv) 259{ 260 strtol_error s_err; 261 int i; 262 263 program_name = argv[0]; 264 for (i=1; i<argc; i++) 265 { 266 char *p; 267 __strtol_t val; 268 269 s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw"); 270 if (s_err == LONGINT_OK) 271 { 272 printf ("%s->%lu (%s)\n", argv[i], val, p); 273 } 274 else 275 { 276 STRTOL_FATAL_ERROR (argv[i], "arg", s_err); 277 } 278 } 279 exit (0); 280} 281 282#endif /* TESTING_XSTRTO */ 283