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