1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License, Version 1.0 only 6168404Spjd * (the "License"). You may not use this file except in compliance 7168404Spjd * with the License. 8168404Spjd * 9168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10168404Spjd * or http://www.opensolaris.org/os/licensing. 11168404Spjd * See the License for the specific language governing permissions 12168404Spjd * and limitations under the License. 13168404Spjd * 14168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 15168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16168404Spjd * If applicable, add the following below this CDDL HEADER, with the 17168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 18168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 19168404Spjd * 20168404Spjd * CDDL HEADER END 21168404Spjd */ 22168404Spjd/* 23168404Spjd * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24168404Spjd * Use is subject to license terms. 25168404Spjd */ 26168404Spjd 27168404Spjd#pragma ident "%Z%%M% %I% %E% SMI" 28168404Spjd 29168404Spjd#include "libuutil_common.h" 30168404Spjd 31168404Spjd#include <limits.h> 32168404Spjd#include <ctype.h> 33168404Spjd 34168404Spjd#define MAX_BASE 36 35168404Spjd 36168404Spjd#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9') 37168404Spjd 38168404Spjd#define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \ 39168404Spjd ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A') 40168404Spjd 41168404Spjdstatic int 42168404Spjdstrtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign) 43168404Spjd{ 44168404Spjd const unsigned char *s = (const unsigned char *)s_arg; 45168404Spjd 46168404Spjd uint64_t val = 0; 47168404Spjd uint64_t multmax; 48168404Spjd 49168404Spjd unsigned c, i; 50168404Spjd 51168404Spjd int neg = 0; 52168404Spjd 53168404Spjd int bad_digit = 0; 54168404Spjd int bad_char = 0; 55168404Spjd int overflow = 0; 56168404Spjd 57168404Spjd if (s == NULL || base == 1 || base > MAX_BASE) { 58168404Spjd uu_set_error(UU_ERROR_INVALID_ARGUMENT); 59168404Spjd return (-1); 60168404Spjd } 61168404Spjd 62168404Spjd while ((c = *s) != 0 && isspace(c)) 63168404Spjd s++; 64168404Spjd 65168404Spjd switch (c) { 66168404Spjd case '-': 67168404Spjd if (!sign) 68168404Spjd overflow = 1; /* becomes underflow below */ 69168404Spjd neg = 1; 70168404Spjd /*FALLTHRU*/ 71168404Spjd case '+': 72168404Spjd c = *++s; 73168404Spjd break; 74168404Spjd default: 75168404Spjd break; 76168404Spjd } 77168404Spjd 78168404Spjd if (c == '\0') { 79168404Spjd uu_set_error(UU_ERROR_EMPTY); 80168404Spjd return (-1); 81168404Spjd } 82168404Spjd 83168404Spjd if (base == 0) { 84168404Spjd if (c != '0') 85168404Spjd base = 10; 86168404Spjd else if (s[1] == 'x' || s[1] == 'X') 87168404Spjd base = 16; 88168404Spjd else 89168404Spjd base = 8; 90168404Spjd } 91168404Spjd 92168404Spjd if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X')) 93168404Spjd c = *(s += 2); 94168404Spjd 95168404Spjd if ((val = CTOI(c)) >= base) { 96168404Spjd if (IS_DIGIT(c)) 97168404Spjd bad_digit = 1; 98168404Spjd else 99168404Spjd bad_char = 1; 100168404Spjd val = 0; 101168404Spjd } 102168404Spjd 103168404Spjd multmax = (uint64_t)UINT64_MAX / (uint64_t)base; 104168404Spjd 105168404Spjd for (c = *++s; c != '\0'; c = *++s) { 106168404Spjd if ((i = CTOI(c)) >= base) { 107168404Spjd if (isspace(c)) 108168404Spjd break; 109168404Spjd if (IS_DIGIT(c)) 110168404Spjd bad_digit = 1; 111168404Spjd else 112168404Spjd bad_char = 1; 113168404Spjd i = 0; 114168404Spjd } 115168404Spjd 116168404Spjd if (val > multmax) 117168404Spjd overflow = 1; 118168404Spjd 119168404Spjd val *= base; 120168404Spjd if ((uint64_t)UINT64_MAX - val < (uint64_t)i) 121168404Spjd overflow = 1; 122168404Spjd 123168404Spjd val += i; 124168404Spjd } 125168404Spjd 126168404Spjd while ((c = *s) != 0) { 127168404Spjd if (!isspace(c)) 128168404Spjd bad_char = 1; 129168404Spjd s++; 130168404Spjd } 131168404Spjd 132168404Spjd if (sign) { 133168404Spjd if (neg) { 134168404Spjd if (val > -(uint64_t)INT64_MIN) 135168404Spjd overflow = 1; 136168404Spjd } else { 137168404Spjd if (val > INT64_MAX) 138168404Spjd overflow = 1; 139168404Spjd } 140168404Spjd } 141168404Spjd 142168404Spjd if (neg) 143168404Spjd val = -val; 144168404Spjd 145168404Spjd if (bad_char | bad_digit | overflow) { 146168404Spjd if (bad_char) 147168404Spjd uu_set_error(UU_ERROR_INVALID_CHAR); 148168404Spjd else if (bad_digit) 149168404Spjd uu_set_error(UU_ERROR_INVALID_DIGIT); 150168404Spjd else if (overflow) { 151168404Spjd if (neg) 152168404Spjd uu_set_error(UU_ERROR_UNDERFLOW); 153168404Spjd else 154168404Spjd uu_set_error(UU_ERROR_OVERFLOW); 155168404Spjd } 156168404Spjd return (-1); 157168404Spjd } 158168404Spjd 159168404Spjd *out = val; 160168404Spjd return (0); 161168404Spjd} 162168404Spjd 163168404Spjdint 164168404Spjduu_strtoint(const char *s, void *v, size_t sz, int base, 165168404Spjd int64_t min, int64_t max) 166168404Spjd{ 167168404Spjd uint64_t val_u; 168168404Spjd int64_t val; 169168404Spjd 170168404Spjd if (min > max) 171168404Spjd goto bad_argument; 172168404Spjd 173168404Spjd switch (sz) { 174168404Spjd case 1: 175168404Spjd if (max > INT8_MAX || min < INT8_MIN) 176168404Spjd goto bad_argument; 177168404Spjd break; 178168404Spjd case 2: 179168404Spjd if (max > INT16_MAX || min < INT16_MIN) 180168404Spjd goto bad_argument; 181168404Spjd break; 182168404Spjd case 4: 183168404Spjd if (max > INT32_MAX || min < INT32_MIN) 184168404Spjd goto bad_argument; 185168404Spjd break; 186168404Spjd case 8: 187168404Spjd if (max > INT64_MAX || min < INT64_MIN) 188168404Spjd goto bad_argument; 189168404Spjd break; 190168404Spjd default: 191168404Spjd goto bad_argument; 192168404Spjd } 193168404Spjd 194168404Spjd if (min == 0 && max == 0) { 195168404Spjd min = -(1ULL << (8 * sz - 1)); 196168404Spjd max = (1ULL << (8 * sz - 1)) - 1; 197168404Spjd } 198168404Spjd 199168404Spjd if (strtoint(s, &val_u, base, 1) == -1) 200168404Spjd return (-1); 201168404Spjd 202168404Spjd val = (int64_t)val_u; 203168404Spjd 204168404Spjd if (val < min) { 205168404Spjd uu_set_error(UU_ERROR_UNDERFLOW); 206168404Spjd return (-1); 207168404Spjd } else if (val > max) { 208168404Spjd uu_set_error(UU_ERROR_OVERFLOW); 209168404Spjd return (-1); 210168404Spjd } 211168404Spjd 212168404Spjd switch (sz) { 213168404Spjd case 1: 214168404Spjd *(int8_t *)v = val; 215168404Spjd return (0); 216168404Spjd case 2: 217168404Spjd *(int16_t *)v = val; 218168404Spjd return (0); 219168404Spjd case 4: 220168404Spjd *(int32_t *)v = val; 221168404Spjd return (0); 222168404Spjd case 8: 223168404Spjd *(int64_t *)v = val; 224168404Spjd return (0); 225168404Spjd default: 226168404Spjd break; /* fall through to bad_argument */ 227168404Spjd } 228168404Spjd 229168404Spjdbad_argument: 230168404Spjd uu_set_error(UU_ERROR_INVALID_ARGUMENT); 231168404Spjd return (-1); 232168404Spjd} 233168404Spjd 234168404Spjdint 235168404Spjduu_strtouint(const char *s, void *v, size_t sz, int base, 236168404Spjd uint64_t min, uint64_t max) 237168404Spjd{ 238168404Spjd uint64_t val; 239168404Spjd 240168404Spjd if (min > max) 241168404Spjd goto bad_argument; 242168404Spjd 243168404Spjd switch (sz) { 244168404Spjd case 1: 245168404Spjd if (max > UINT8_MAX) 246168404Spjd goto bad_argument; 247168404Spjd break; 248168404Spjd case 2: 249168404Spjd if (max > UINT16_MAX) 250168404Spjd goto bad_argument; 251168404Spjd break; 252168404Spjd case 4: 253168404Spjd if (max > UINT32_MAX) 254168404Spjd goto bad_argument; 255168404Spjd break; 256168404Spjd case 8: 257168404Spjd if (max > UINT64_MAX) 258168404Spjd goto bad_argument; 259168404Spjd break; 260168404Spjd default: 261168404Spjd goto bad_argument; 262168404Spjd } 263168404Spjd 264168404Spjd if (min == 0 && max == 0) { 265168404Spjd /* we have to be careful, since << can overflow */ 266168404Spjd max = (1ULL << (8 * sz - 1)) * 2 - 1; 267168404Spjd } 268168404Spjd 269168404Spjd if (strtoint(s, &val, base, 0) == -1) 270168404Spjd return (-1); 271168404Spjd 272168404Spjd if (val < min) { 273168404Spjd uu_set_error(UU_ERROR_UNDERFLOW); 274168404Spjd return (-1); 275168404Spjd } else if (val > max) { 276168404Spjd uu_set_error(UU_ERROR_OVERFLOW); 277168404Spjd return (-1); 278168404Spjd } 279168404Spjd 280168404Spjd switch (sz) { 281168404Spjd case 1: 282168404Spjd *(uint8_t *)v = val; 283168404Spjd return (0); 284168404Spjd case 2: 285168404Spjd *(uint16_t *)v = val; 286168404Spjd return (0); 287168404Spjd case 4: 288168404Spjd *(uint32_t *)v = val; 289168404Spjd return (0); 290168404Spjd case 8: 291168404Spjd *(uint64_t *)v = val; 292168404Spjd return (0); 293168404Spjd default: 294168404Spjd break; /* shouldn't happen, fall through */ 295168404Spjd } 296168404Spjd 297168404Spjdbad_argument: 298168404Spjd uu_set_error(UU_ERROR_INVALID_ARGUMENT); 299168404Spjd return (-1); 300168404Spjd} 301