1131554Stjr/* A more useful interface to strtol. 2131554Stjr Copyright (C) 1995, 1996, 1998-2000 Free Software Foundation, Inc. 3131554Stjr 4131554Stjr This program is free software; you can redistribute it and/or modify 5131554Stjr it under the terms of the GNU General Public License as published by 6131554Stjr the Free Software Foundation; either version 2, or (at your option) 7131554Stjr any later version. 8131554Stjr 9131554Stjr This program is distributed in the hope that it will be useful, 10131554Stjr but WITHOUT ANY WARRANTY; without even the implied warranty of 11131554Stjr MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12131554Stjr GNU General Public License for more details. 13131554Stjr 14131554Stjr You should have received a copy of the GNU General Public License 15131554Stjr along with this program; if not, write to the Free Software Foundation, 16131554Stjr Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17131554Stjr 18131554Stjr/* Written by Jim Meyering. */ 19131554Stjr 20131554Stjr#if HAVE_CONFIG_H 21131554Stjr# include <config.h> 22131554Stjr#endif 23131554Stjr 24131554Stjr#ifndef __strtol 25131554Stjr# define __strtol strtol 26131554Stjr# define __strtol_t long int 27131554Stjr# define __xstrtol xstrtol 28131554Stjr#endif 29131554Stjr 30131554Stjr/* Some pre-ANSI implementations (e.g. SunOS 4) 31131554Stjr need stderr defined if assertion checking is enabled. */ 32131554Stjr#include <stdio.h> 33131554Stjr 34131554Stjr#if STDC_HEADERS 35131554Stjr# include <stdlib.h> 36131554Stjr#endif 37131554Stjr 38131554Stjr#if HAVE_STRING_H 39131554Stjr# include <string.h> 40131554Stjr#else 41131554Stjr# include <strings.h> 42131554Stjr# ifndef strchr 43131554Stjr# define strchr index 44131554Stjr# endif 45131554Stjr#endif 46131554Stjr 47131554Stjr#include <assert.h> 48131554Stjr#include <ctype.h> 49131554Stjr 50131554Stjr#include <errno.h> 51131554Stjr#ifndef errno 52131554Stjrextern int errno; 53131554Stjr#endif 54131554Stjr 55131554Stjr#if HAVE_LIMITS_H 56131554Stjr# include <limits.h> 57131554Stjr#endif 58131554Stjr 59131554Stjr#ifndef CHAR_BIT 60131554Stjr# define CHAR_BIT 8 61131554Stjr#endif 62131554Stjr 63131554Stjr/* The extra casts work around common compiler bugs. */ 64131554Stjr#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) 65131554Stjr/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. 66131554Stjr It is necessary at least when t == time_t. */ 67131554Stjr#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ 68131554Stjr ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) 69131554Stjr#define TYPE_MAXIMUM(t) (~ (t) 0 - TYPE_MINIMUM (t)) 70131554Stjr 71131554Stjr#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) 72131554Stjr# define IN_CTYPE_DOMAIN(c) 1 73131554Stjr#else 74131554Stjr# define IN_CTYPE_DOMAIN(c) isascii(c) 75131554Stjr#endif 76131554Stjr 77131554Stjr#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) 78131554Stjr 79131554Stjr#include "xstrtol.h" 80131554Stjr 81131554Stjr#ifndef strtol 82131554Stjrlong int strtol (); 83131554Stjr#endif 84131554Stjr 85131554Stjr#ifndef strtoul 86131554Stjrunsigned long int strtoul (); 87131554Stjr#endif 88131554Stjr 89131554Stjr#ifndef strtoumax 90131554Stjruintmax_t strtoumax (); 91131554Stjr#endif 92131554Stjr 93131554Stjrstatic int 94131554Stjrbkm_scale (__strtol_t *x, int scale_factor) 95131554Stjr{ 96131554Stjr __strtol_t product = *x * scale_factor; 97131554Stjr if (*x != product / scale_factor) 98131554Stjr return 1; 99131554Stjr *x = product; 100131554Stjr return 0; 101131554Stjr} 102131554Stjr 103131554Stjrstatic int 104131554Stjrbkm_scale_by_power (__strtol_t *x, int base, int power) 105131554Stjr{ 106131554Stjr while (power--) 107131554Stjr if (bkm_scale (x, base)) 108131554Stjr return 1; 109131554Stjr 110131554Stjr return 0; 111131554Stjr} 112131554Stjr 113131554Stjr/* FIXME: comment. */ 114131554Stjr 115131554Stjrstrtol_error 116131554Stjr__xstrtol (const char *s, char **ptr, int strtol_base, 117131554Stjr __strtol_t *val, const char *valid_suffixes) 118131554Stjr{ 119131554Stjr char *t_ptr; 120131554Stjr char **p; 121131554Stjr __strtol_t tmp; 122131554Stjr 123131554Stjr assert (0 <= strtol_base && strtol_base <= 36); 124131554Stjr 125131554Stjr p = (ptr ? ptr : &t_ptr); 126131554Stjr 127131554Stjr if (! TYPE_SIGNED (__strtol_t)) 128131554Stjr { 129131554Stjr const char *q = s; 130131554Stjr while (ISSPACE ((unsigned char) *q)) 131131554Stjr ++q; 132131554Stjr if (*q == '-') 133131554Stjr return LONGINT_INVALID; 134131554Stjr } 135131554Stjr 136131554Stjr errno = 0; 137131554Stjr tmp = __strtol (s, p, strtol_base); 138131554Stjr if (errno != 0) 139131554Stjr return LONGINT_OVERFLOW; 140131554Stjr if (*p == s) 141131554Stjr return LONGINT_INVALID; 142131554Stjr 143131554Stjr /* Let valid_suffixes == NULL mean `allow any suffix'. */ 144131554Stjr /* FIXME: update all callers except the ones that allow suffixes 145131554Stjr after the number, changing last parameter NULL to `""'. */ 146131554Stjr if (!valid_suffixes) 147131554Stjr { 148131554Stjr *val = tmp; 149131554Stjr return LONGINT_OK; 150131554Stjr } 151131554Stjr 152131554Stjr if (**p != '\0') 153131554Stjr { 154131554Stjr int base = 1024; 155131554Stjr int suffixes = 1; 156131554Stjr int overflow; 157131554Stjr 158131554Stjr if (!strchr (valid_suffixes, **p)) 159131554Stjr { 160131554Stjr *val = tmp; 161131554Stjr return LONGINT_INVALID_SUFFIX_CHAR; 162131554Stjr } 163131554Stjr 164131554Stjr if (strchr (valid_suffixes, '0')) 165131554Stjr { 166131554Stjr /* The ``valid suffix'' '0' is a special flag meaning that 167131554Stjr an optional second suffix is allowed, which can change 168131554Stjr the base, e.g. "100MD" for 100 megabytes decimal. */ 169131554Stjr 170131554Stjr switch (p[0][1]) 171131554Stjr { 172131554Stjr case 'B': 173131554Stjr suffixes++; 174131554Stjr break; 175131554Stjr 176131554Stjr case 'D': 177131554Stjr base = 1000; 178131554Stjr suffixes++; 179131554Stjr break; 180131554Stjr } 181131554Stjr } 182131554Stjr 183131554Stjr switch (**p) 184131554Stjr { 185131554Stjr case 'b': 186131554Stjr overflow = bkm_scale (&tmp, 512); 187131554Stjr break; 188131554Stjr 189131554Stjr case 'B': 190131554Stjr overflow = bkm_scale (&tmp, 1024); 191131554Stjr break; 192131554Stjr 193131554Stjr case 'c': 194131554Stjr overflow = 0; 195131554Stjr break; 196131554Stjr 197131554Stjr case 'E': /* Exa */ 198131554Stjr overflow = bkm_scale_by_power (&tmp, base, 6); 199131554Stjr break; 200131554Stjr 201131554Stjr case 'G': /* Giga */ 202131554Stjr overflow = bkm_scale_by_power (&tmp, base, 3); 203131554Stjr break; 204131554Stjr 205131554Stjr case 'k': /* kilo */ 206131554Stjr overflow = bkm_scale_by_power (&tmp, base, 1); 207131554Stjr break; 208131554Stjr 209131554Stjr case 'M': /* Mega */ 210131554Stjr case 'm': /* 'm' is undocumented; for backward compatibility only */ 211131554Stjr overflow = bkm_scale_by_power (&tmp, base, 2); 212131554Stjr break; 213131554Stjr 214131554Stjr case 'P': /* Peta */ 215131554Stjr overflow = bkm_scale_by_power (&tmp, base, 5); 216131554Stjr break; 217131554Stjr 218131554Stjr case 'T': /* Tera */ 219131554Stjr overflow = bkm_scale_by_power (&tmp, base, 4); 220131554Stjr break; 221131554Stjr 222131554Stjr case 'w': 223131554Stjr overflow = bkm_scale (&tmp, 2); 224131554Stjr break; 225131554Stjr 226131554Stjr case 'Y': /* Yotta */ 227131554Stjr overflow = bkm_scale_by_power (&tmp, base, 8); 228131554Stjr break; 229131554Stjr 230131554Stjr case 'Z': /* Zetta */ 231131554Stjr overflow = bkm_scale_by_power (&tmp, base, 7); 232131554Stjr break; 233131554Stjr 234131554Stjr default: 235131554Stjr *val = tmp; 236131554Stjr return LONGINT_INVALID_SUFFIX_CHAR; 237131554Stjr break; 238131554Stjr } 239131554Stjr 240131554Stjr if (overflow) 241131554Stjr return LONGINT_OVERFLOW; 242131554Stjr 243131554Stjr (*p) += suffixes; 244131554Stjr } 245131554Stjr 246131554Stjr *val = tmp; 247131554Stjr return LONGINT_OK; 248131554Stjr} 249131554Stjr 250131554Stjr#ifdef TESTING_XSTRTO 251131554Stjr 252131554Stjr# include <stdio.h> 253131554Stjr# include "error.h" 254131554Stjr 255131554Stjrchar *program_name; 256131554Stjr 257131554Stjrint 258131554Stjrmain (int argc, char** argv) 259131554Stjr{ 260131554Stjr strtol_error s_err; 261131554Stjr int i; 262131554Stjr 263131554Stjr program_name = argv[0]; 264131554Stjr for (i=1; i<argc; i++) 265131554Stjr { 266131554Stjr char *p; 267131554Stjr __strtol_t val; 268131554Stjr 269131554Stjr s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw"); 270131554Stjr if (s_err == LONGINT_OK) 271131554Stjr { 272131554Stjr printf ("%s->%lu (%s)\n", argv[i], val, p); 273131554Stjr } 274131554Stjr else 275131554Stjr { 276131554Stjr STRTOL_FATAL_ERROR (argv[i], "arg", s_err); 277131554Stjr } 278131554Stjr } 279131554Stjr exit (0); 280131554Stjr} 281131554Stjr 282131554Stjr#endif /* TESTING_XSTRTO */ 283