uu_strtoint.c revision 168404
1169691Skan/* 2169691Skan * CDDL HEADER START 3169691Skan * 4169691Skan * The contents of this file are subject to the terms of the 5169691Skan * Common Development and Distribution License, Version 1.0 only 6169691Skan * (the "License"). You may not use this file except in compliance 7169691Skan * with the License. 8169691Skan * 9169691Skan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10169691Skan * or http://www.opensolaris.org/os/licensing. 11169691Skan * See the License for the specific language governing permissions 12169691Skan * and limitations under the License. 13169691Skan * 14169691Skan * When distributing Covered Code, include this CDDL HEADER in each 15169691Skan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16169691Skan * If applicable, add the following below this CDDL HEADER, with the 17169691Skan * fields enclosed by brackets "[]" replaced with your own identifying 18169691Skan * information: Portions Copyright [yyyy] [name of copyright owner] 19169691Skan * 20169691Skan * CDDL HEADER END 21169691Skan */ 22169691Skan/* 23169691Skan * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24169691Skan * Use is subject to license terms. 25169691Skan */ 26169691Skan 27169691Skan#pragma ident "%Z%%M% %I% %E% SMI" 28169691Skan 29169691Skan#include "libuutil_common.h" 30169691Skan 31169691Skan#include <limits.h> 32169691Skan#include <ctype.h> 33169691Skan 34169691Skan#define MAX_BASE 36 35169691Skan 36169691Skan#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9') 37169691Skan 38169691Skan#define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \ 39169691Skan ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A') 40169691Skan 41169691Skanstatic int 42169691Skanstrtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign) 43169691Skan{ 44169691Skan const unsigned char *s = (const unsigned char *)s_arg; 45169691Skan 46169691Skan uint64_t val = 0; 47169691Skan uint64_t multmax; 48169691Skan 49169691Skan unsigned c, i; 50169691Skan 51169691Skan int neg = 0; 52169691Skan 53169691Skan int bad_digit = 0; 54169691Skan int bad_char = 0; 55169691Skan int overflow = 0; 56169691Skan 57169691Skan if (s == NULL || base == 1 || base > MAX_BASE) { 58169691Skan uu_set_error(UU_ERROR_INVALID_ARGUMENT); 59169691Skan return (-1); 60169691Skan } 61169691Skan 62169691Skan while ((c = *s) != 0 && isspace(c)) 63169691Skan s++; 64169691Skan 65169691Skan switch (c) { 66169691Skan case '-': 67169691Skan if (!sign) 68169691Skan overflow = 1; /* becomes underflow below */ 69169691Skan neg = 1; 70169691Skan /*FALLTHRU*/ 71169691Skan case '+': 72169691Skan c = *++s; 73169691Skan break; 74169691Skan default: 75169691Skan break; 76169691Skan } 77169691Skan 78169691Skan if (c == '\0') { 79169691Skan uu_set_error(UU_ERROR_EMPTY); 80169691Skan return (-1); 81169691Skan } 82169691Skan 83169691Skan if (base == 0) { 84169691Skan if (c != '0') 85169691Skan base = 10; 86169691Skan else if (s[1] == 'x' || s[1] == 'X') 87169691Skan base = 16; 88169691Skan else 89169691Skan base = 8; 90169691Skan } 91169691Skan 92169691Skan if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X')) 93169691Skan c = *(s += 2); 94169691Skan 95169691Skan if ((val = CTOI(c)) >= base) { 96169691Skan if (IS_DIGIT(c)) 97169691Skan bad_digit = 1; 98169691Skan else 99169691Skan bad_char = 1; 100169691Skan val = 0; 101169691Skan } 102169691Skan 103169691Skan multmax = (uint64_t)UINT64_MAX / (uint64_t)base; 104169691Skan 105169691Skan for (c = *++s; c != '\0'; c = *++s) { 106169691Skan if ((i = CTOI(c)) >= base) { 107169691Skan if (isspace(c)) 108169691Skan break; 109169691Skan if (IS_DIGIT(c)) 110169691Skan bad_digit = 1; 111169691Skan else 112169691Skan bad_char = 1; 113169691Skan i = 0; 114169691Skan } 115169691Skan 116169691Skan if (val > multmax) 117169691Skan overflow = 1; 118169691Skan 119169691Skan val *= base; 120169691Skan if ((uint64_t)UINT64_MAX - val < (uint64_t)i) 121169691Skan overflow = 1; 122169691Skan 123169691Skan val += i; 124169691Skan } 125169691Skan 126169691Skan while ((c = *s) != 0) { 127169691Skan if (!isspace(c)) 128169691Skan bad_char = 1; 129169691Skan s++; 130169691Skan } 131169691Skan 132169691Skan if (sign) { 133169691Skan if (neg) { 134169691Skan if (val > -(uint64_t)INT64_MIN) 135169691Skan overflow = 1; 136169691Skan } else { 137169691Skan if (val > INT64_MAX) 138169691Skan overflow = 1; 139169691Skan } 140169691Skan } 141169691Skan 142169691Skan if (neg) 143169691Skan val = -val; 144169691Skan 145169691Skan if (bad_char | bad_digit | overflow) { 146169691Skan if (bad_char) 147169691Skan uu_set_error(UU_ERROR_INVALID_CHAR); 148169691Skan else if (bad_digit) 149169691Skan uu_set_error(UU_ERROR_INVALID_DIGIT); 150169691Skan else if (overflow) { 151169691Skan if (neg) 152169691Skan uu_set_error(UU_ERROR_UNDERFLOW); 153169691Skan else 154169691Skan uu_set_error(UU_ERROR_OVERFLOW); 155169691Skan } 156169691Skan return (-1); 157169691Skan } 158169691Skan 159169691Skan *out = val; 160169691Skan return (0); 161169691Skan} 162169691Skan 163169691Skanint 164169691Skanuu_strtoint(const char *s, void *v, size_t sz, int base, 165169691Skan int64_t min, int64_t max) 166169691Skan{ 167169691Skan uint64_t val_u; 168169691Skan int64_t val; 169169691Skan 170169691Skan if (min > max) 171169691Skan goto bad_argument; 172169691Skan 173169691Skan switch (sz) { 174169691Skan case 1: 175169691Skan if (max > INT8_MAX || min < INT8_MIN) 176169691Skan goto bad_argument; 177169691Skan break; 178169691Skan case 2: 179169691Skan if (max > INT16_MAX || min < INT16_MIN) 180169691Skan goto bad_argument; 181169691Skan break; 182169691Skan case 4: 183169691Skan if (max > INT32_MAX || min < INT32_MIN) 184169691Skan goto bad_argument; 185169691Skan break; 186169691Skan case 8: 187169691Skan if (max > INT64_MAX || min < INT64_MIN) 188169691Skan goto bad_argument; 189169691Skan break; 190169691Skan default: 191169691Skan goto bad_argument; 192169691Skan } 193169691Skan 194169691Skan if (min == 0 && max == 0) { 195169691Skan min = -(1ULL << (8 * sz - 1)); 196169691Skan max = (1ULL << (8 * sz - 1)) - 1; 197169691Skan } 198169691Skan 199169691Skan if (strtoint(s, &val_u, base, 1) == -1) 200169691Skan return (-1); 201169691Skan 202169691Skan val = (int64_t)val_u; 203169691Skan 204169691Skan if (val < min) { 205169691Skan uu_set_error(UU_ERROR_UNDERFLOW); 206169691Skan return (-1); 207169691Skan } else if (val > max) { 208169691Skan uu_set_error(UU_ERROR_OVERFLOW); 209169691Skan return (-1); 210169691Skan } 211169691Skan 212169691Skan switch (sz) { 213169691Skan case 1: 214169691Skan *(int8_t *)v = val; 215169691Skan return (0); 216169691Skan case 2: 217169691Skan *(int16_t *)v = val; 218169691Skan return (0); 219169691Skan case 4: 220169691Skan *(int32_t *)v = val; 221169691Skan return (0); 222169691Skan case 8: 223169691Skan *(int64_t *)v = val; 224169691Skan return (0); 225169691Skan default: 226169691Skan break; /* fall through to bad_argument */ 227169691Skan } 228169691Skan 229169691Skanbad_argument: 230169691Skan uu_set_error(UU_ERROR_INVALID_ARGUMENT); 231169691Skan return (-1); 232169691Skan} 233169691Skan 234169691Skanint 235169691Skanuu_strtouint(const char *s, void *v, size_t sz, int base, 236169691Skan uint64_t min, uint64_t max) 237169691Skan{ 238169691Skan uint64_t val; 239169691Skan 240169691Skan if (min > max) 241169691Skan goto bad_argument; 242169691Skan 243169691Skan switch (sz) { 244169691Skan case 1: 245169691Skan if (max > UINT8_MAX) 246169691Skan goto bad_argument; 247169691Skan break; 248169691Skan case 2: 249169691Skan if (max > UINT16_MAX) 250169691Skan goto bad_argument; 251169691Skan break; 252169691Skan case 4: 253169691Skan if (max > UINT32_MAX) 254169691Skan goto bad_argument; 255169691Skan break; 256169691Skan case 8: 257169691Skan if (max > UINT64_MAX) 258169691Skan goto bad_argument; 259169691Skan break; 260169691Skan default: 261169691Skan goto bad_argument; 262169691Skan } 263169691Skan 264169691Skan if (min == 0 && max == 0) { 265169691Skan /* we have to be careful, since << can overflow */ 266169691Skan max = (1ULL << (8 * sz - 1)) * 2 - 1; 267169691Skan } 268169691Skan 269169691Skan if (strtoint(s, &val, base, 0) == -1) 270169691Skan return (-1); 271169691Skan 272169691Skan if (val < min) { 273169691Skan uu_set_error(UU_ERROR_UNDERFLOW); 274169691Skan return (-1); 275169691Skan } else if (val > max) { 276169691Skan uu_set_error(UU_ERROR_OVERFLOW); 277169691Skan return (-1); 278169691Skan } 279169691Skan 280169691Skan switch (sz) { 281169691Skan case 1: 282169691Skan *(uint8_t *)v = val; 283169691Skan return (0); 284169691Skan case 2: 285169691Skan *(uint16_t *)v = val; 286169691Skan return (0); 287169691Skan case 4: 288169691Skan *(uint32_t *)v = val; 289169691Skan return (0); 290169691Skan case 8: 291169691Skan *(uint64_t *)v = val; 292169691Skan return (0); 293169691Skan default: 294169691Skan break; /* shouldn't happen, fall through */ 295169691Skan } 296169691Skan 297169691Skanbad_argument: 298169691Skan uu_set_error(UU_ERROR_INVALID_ARGUMENT); 299169691Skan return (-1); 300169691Skan} 301