1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "libuutil_common.h" 30 31 #include <limits.h> 32 #include <ctype.h> 33 34 #define MAX_BASE 36 35 36 #define IS_DIGIT(x) ((x) >= '0' && (x) <= '9') 37 38 #define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \ 39 ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A') 40 41 static int 42 strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign) 43 { 44 const unsigned char *s = (const unsigned char *)s_arg; 45 46 uint64_t val = 0; 47 uint64_t multmax; 48 49 unsigned c, i; 50 51 int neg = 0; 52 53 int bad_digit = 0; 54 int bad_char = 0; 55 int overflow = 0; 56 57 if (s == NULL || base == 1 || base > MAX_BASE) { 58 uu_set_error(UU_ERROR_INVALID_ARGUMENT); 59 return (-1); 60 } 61 62 while ((c = *s) != 0 && isspace(c)) 63 s++; 64 65 switch (c) { 66 case '-': 67 if (!sign) 68 overflow = 1; /* becomes underflow below */ 69 neg = 1; 70 /*FALLTHRU*/ 71 case '+': 72 c = *++s; 73 break; 74 default: 75 break; 76 } 77 78 if (c == '\0') { 79 uu_set_error(UU_ERROR_EMPTY); 80 return (-1); 81 } 82 83 if (base == 0) { 84 if (c != '0') 85 base = 10; 86 else if (s[1] == 'x' || s[1] == 'X') 87 base = 16; 88 else 89 base = 8; 90 } 91 92 if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X')) 93 c = *(s += 2); 94 95 if ((val = CTOI(c)) >= base) { 96 if (IS_DIGIT(c)) 97 bad_digit = 1; 98 else 99 bad_char = 1; 100 val = 0; 101 } 102 103 multmax = (uint64_t)UINT64_MAX / (uint64_t)base; 104 105 for (c = *++s; c != '\0'; c = *++s) { 106 if ((i = CTOI(c)) >= base) { 107 if (isspace(c)) 108 break; 109 if (IS_DIGIT(c)) 110 bad_digit = 1; 111 else 112 bad_char = 1; 113 i = 0; 114 } 115 116 if (val > multmax) 117 overflow = 1; 118 119 val *= base; 120 if ((uint64_t)UINT64_MAX - val < (uint64_t)i) 121 overflow = 1; 122 123 val += i; 124 } 125 126 while ((c = *s) != 0) { 127 if (!isspace(c)) 128 bad_char = 1; 129 s++; 130 } 131 132 if (sign) { 133 if (neg) { 134 if (val > -(uint64_t)INT64_MIN) 135 overflow = 1; 136 } else { 137 if (val > INT64_MAX) 138 overflow = 1; 139 } 140 } 141 142 if (neg) 143 val = -val; 144 145 if (bad_char | bad_digit | overflow) { 146 if (bad_char) 147 uu_set_error(UU_ERROR_INVALID_CHAR); 148 else if (bad_digit) 149 uu_set_error(UU_ERROR_INVALID_DIGIT); 150 else if (overflow) { 151 if (neg) 152 uu_set_error(UU_ERROR_UNDERFLOW); 153 else 154 uu_set_error(UU_ERROR_OVERFLOW); 155 } 156 return (-1); 157 } 158 159 *out = val; 160 return (0); 161 } 162 163 int 164 uu_strtoint(const char *s, void *v, size_t sz, int base, 165 int64_t min, int64_t max) 166 { 167 uint64_t val_u; 168 int64_t val; 169 170 if (min > max) 171 goto bad_argument; 172 173 switch (sz) { 174 case 1: 175 if (max > INT8_MAX || min < INT8_MIN) 176 goto bad_argument; 177 break; 178 case 2: 179 if (max > INT16_MAX || min < INT16_MIN) 180 goto bad_argument; 181 break; 182 case 4: 183 if (max > INT32_MAX || min < INT32_MIN) 184 goto bad_argument; 185 break; 186 case 8: 187 if (max > INT64_MAX || min < INT64_MIN) 188 goto bad_argument; 189 break; 190 default: 191 goto bad_argument; 192 } 193 194 if (min == 0 && max == 0) { 195 min = -(1ULL << (8 * sz - 1)); 196 max = (1ULL << (8 * sz - 1)) - 1; 197 } 198 199 if (strtoint(s, &val_u, base, 1) == -1) 200 return (-1); 201 202 val = (int64_t)val_u; 203 204 if (val < min) { 205 uu_set_error(UU_ERROR_UNDERFLOW); 206 return (-1); 207 } else if (val > max) { 208 uu_set_error(UU_ERROR_OVERFLOW); 209 return (-1); 210 } 211 212 switch (sz) { 213 case 1: 214 *(int8_t *)v = val; 215 return (0); 216 case 2: 217 *(int16_t *)v = val; 218 return (0); 219 case 4: 220 *(int32_t *)v = val; 221 return (0); 222 case 8: 223 *(int64_t *)v = val; 224 return (0); 225 default: 226 break; /* fall through to bad_argument */ 227 } 228 229 bad_argument: 230 uu_set_error(UU_ERROR_INVALID_ARGUMENT); 231 return (-1); 232 } 233 234 int 235 uu_strtouint(const char *s, void *v, size_t sz, int base, 236 uint64_t min, uint64_t max) 237 { 238 uint64_t val; 239 240 if (min > max) 241 goto bad_argument; 242 243 switch (sz) { 244 case 1: 245 if (max > UINT8_MAX) 246 goto bad_argument; 247 break; 248 case 2: 249 if (max > UINT16_MAX) 250 goto bad_argument; 251 break; 252 case 4: 253 if (max > UINT32_MAX) 254 goto bad_argument; 255 break; 256 case 8: 257 if (max > UINT64_MAX) 258 goto bad_argument; 259 break; 260 default: 261 goto bad_argument; 262 } 263 264 if (min == 0 && max == 0) { 265 /* we have to be careful, since << can overflow */ 266 max = (1ULL << (8 * sz - 1)) * 2 - 1; 267 } 268 269 if (strtoint(s, &val, base, 0) == -1) 270 return (-1); 271 272 if (val < min) { 273 uu_set_error(UU_ERROR_UNDERFLOW); 274 return (-1); 275 } else if (val > max) { 276 uu_set_error(UU_ERROR_OVERFLOW); 277 return (-1); 278 } 279 280 switch (sz) { 281 case 1: 282 *(uint8_t *)v = val; 283 return (0); 284 case 2: 285 *(uint16_t *)v = val; 286 return (0); 287 case 4: 288 *(uint32_t *)v = val; 289 return (0); 290 case 8: 291 *(uint64_t *)v = val; 292 return (0); 293 default: 294 break; /* shouldn't happen, fall through */ 295 } 296 297 bad_argument: 298 uu_set_error(UU_ERROR_INVALID_ARGUMENT); 299 return (-1); 300 } 301