1 /* $NetBSD: xstrtol.c,v 1.1.1.1 2016/01/10 21:36:19 christos Exp $ */ 2 3 /* A more useful interface to strtol. 4 Copyright (C) 1995, 1996, 1998-2000 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 54 extern 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 #ifndef strtol 84 long int strtol (); 85 #endif 86 87 #ifndef strtoul 88 unsigned long int strtoul (); 89 #endif 90 91 #ifndef strtoumax 92 uintmax_t strtoumax (); 93 #endif 94 95 static int 96 bkm_scale (__strtol_t *x, int scale_factor) 97 { 98 __strtol_t product = *x * scale_factor; 99 if (*x != product / scale_factor) 100 return 1; 101 *x = product; 102 return 0; 103 } 104 105 static int 106 bkm_scale_by_power (__strtol_t *x, int base, int power) 107 { 108 while (power--) 109 if (bkm_scale (x, base)) 110 return 1; 111 112 return 0; 113 } 114 115 /* FIXME: comment. */ 116 117 strtol_error 118 __xstrtol (const char *s, char **ptr, int strtol_base, 119 __strtol_t *val, const char *valid_suffixes) 120 { 121 char *t_ptr; 122 char **p; 123 __strtol_t tmp; 124 125 assert (0 <= strtol_base && strtol_base <= 36); 126 127 p = (ptr ? ptr : &t_ptr); 128 129 if (! TYPE_SIGNED (__strtol_t)) 130 { 131 const char *q = s; 132 while (ISSPACE ((unsigned char) *q)) 133 ++q; 134 if (*q == '-') 135 return LONGINT_INVALID; 136 } 137 138 errno = 0; 139 tmp = __strtol (s, p, strtol_base); 140 if (errno != 0) 141 return LONGINT_OVERFLOW; 142 if (*p == s) 143 return LONGINT_INVALID; 144 145 /* Let valid_suffixes == NULL mean `allow any suffix'. */ 146 /* FIXME: update all callers except the ones that allow suffixes 147 after the number, changing last parameter NULL to `""'. */ 148 if (!valid_suffixes) 149 { 150 *val = tmp; 151 return LONGINT_OK; 152 } 153 154 if (**p != '\0') 155 { 156 int base = 1024; 157 int suffixes = 1; 158 int overflow; 159 160 if (!strchr (valid_suffixes, **p)) 161 { 162 *val = tmp; 163 return LONGINT_INVALID_SUFFIX_CHAR; 164 } 165 166 if (strchr (valid_suffixes, '0')) 167 { 168 /* The ``valid suffix'' '0' is a special flag meaning that 169 an optional second suffix is allowed, which can change 170 the base, e.g. "100MD" for 100 megabytes decimal. */ 171 172 switch (p[0][1]) 173 { 174 case 'B': 175 suffixes++; 176 break; 177 178 case 'D': 179 base = 1000; 180 suffixes++; 181 break; 182 } 183 } 184 185 switch (**p) 186 { 187 case 'b': 188 overflow = bkm_scale (&tmp, 512); 189 break; 190 191 case 'B': 192 overflow = bkm_scale (&tmp, 1024); 193 break; 194 195 case 'c': 196 overflow = 0; 197 break; 198 199 case 'E': /* Exa */ 200 overflow = bkm_scale_by_power (&tmp, base, 6); 201 break; 202 203 case 'G': /* Giga */ 204 overflow = bkm_scale_by_power (&tmp, base, 3); 205 break; 206 207 case 'k': /* kilo */ 208 overflow = bkm_scale_by_power (&tmp, base, 1); 209 break; 210 211 case 'M': /* Mega */ 212 case 'm': /* 'm' is undocumented; for backward compatibility only */ 213 overflow = bkm_scale_by_power (&tmp, base, 2); 214 break; 215 216 case 'P': /* Peta */ 217 overflow = bkm_scale_by_power (&tmp, base, 5); 218 break; 219 220 case 'T': /* Tera */ 221 overflow = bkm_scale_by_power (&tmp, base, 4); 222 break; 223 224 case 'w': 225 overflow = bkm_scale (&tmp, 2); 226 break; 227 228 case 'Y': /* Yotta */ 229 overflow = bkm_scale_by_power (&tmp, base, 8); 230 break; 231 232 case 'Z': /* Zetta */ 233 overflow = bkm_scale_by_power (&tmp, base, 7); 234 break; 235 236 default: 237 *val = tmp; 238 return LONGINT_INVALID_SUFFIX_CHAR; 239 break; 240 } 241 242 if (overflow) 243 return LONGINT_OVERFLOW; 244 245 (*p) += suffixes; 246 } 247 248 *val = tmp; 249 return LONGINT_OK; 250 } 251 252 #ifdef TESTING_XSTRTO 253 254 # include <stdio.h> 255 # include "error.h" 256 257 char *program_name; 258 259 int 260 main (int argc, char** argv) 261 { 262 strtol_error s_err; 263 int i; 264 265 program_name = argv[0]; 266 for (i=1; i<argc; i++) 267 { 268 char *p; 269 __strtol_t val; 270 271 s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw"); 272 if (s_err == LONGINT_OK) 273 { 274 printf ("%s->%lu (%s)\n", argv[i], val, p); 275 } 276 else 277 { 278 STRTOL_FATAL_ERROR (argv[i], "arg", s_err); 279 } 280 } 281 exit (0); 282 } 283 284 #endif /* TESTING_XSTRTO */ 285