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 #include "libuutil_common.h" 28 29 #include <limits.h> 30 #include <ctype.h> 31 32 #define MAX_BASE 36 33 34 #define IS_DIGIT(x) ((x) >= '0' && (x) <= '9') 35 36 #define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \ 37 ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A') 38 39 static int 40 strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign) 41 { 42 const unsigned char *s = (const unsigned char *)s_arg; 43 44 uint64_t val = 0; 45 uint64_t multmax; 46 47 unsigned c, i; 48 49 int neg = 0; 50 51 int bad_digit = 0; 52 int bad_char = 0; 53 int overflow = 0; 54 55 if (s == NULL || base == 1 || base > MAX_BASE) { 56 uu_set_error(UU_ERROR_INVALID_ARGUMENT); 57 return (-1); 58 } 59 60 while ((c = *s) != 0 && isspace(c)) 61 s++; 62 63 switch (c) { 64 case '-': 65 if (!sign) 66 overflow = 1; /* becomes underflow below */ 67 neg = 1; 68 /*FALLTHRU*/ 69 case '+': 70 c = *++s; 71 break; 72 default: 73 break; 74 } 75 76 if (c == '\0') { 77 uu_set_error(UU_ERROR_EMPTY); 78 return (-1); 79 } 80 81 if (base == 0) { 82 if (c != '0') 83 base = 10; 84 else if (s[1] == 'x' || s[1] == 'X') 85 base = 16; 86 else 87 base = 8; 88 } 89 90 if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X')) 91 c = *(s += 2); 92 93 if ((val = CTOI(c)) >= base) { 94 if (IS_DIGIT(c)) 95 bad_digit = 1; 96 else 97 bad_char = 1; 98 val = 0; 99 } 100 101 multmax = (uint64_t)UINT64_MAX / (uint64_t)base; 102 103 for (c = *++s; c != '\0'; c = *++s) { 104 if ((i = CTOI(c)) >= base) { 105 if (isspace(c)) 106 break; 107 if (IS_DIGIT(c)) 108 bad_digit = 1; 109 else 110 bad_char = 1; 111 i = 0; 112 } 113 114 if (val > multmax) 115 overflow = 1; 116 117 val *= base; 118 if ((uint64_t)UINT64_MAX - val < (uint64_t)i) 119 overflow = 1; 120 121 val += i; 122 } 123 124 while ((c = *s) != 0) { 125 if (!isspace(c)) 126 bad_char = 1; 127 s++; 128 } 129 130 if (sign) { 131 if (neg) { 132 if (val > -(uint64_t)INT64_MIN) 133 overflow = 1; 134 } else { 135 if (val > INT64_MAX) 136 overflow = 1; 137 } 138 } 139 140 if (neg) 141 val = -val; 142 143 if (bad_char | bad_digit | overflow) { 144 if (bad_char) 145 uu_set_error(UU_ERROR_INVALID_CHAR); 146 else if (bad_digit) 147 uu_set_error(UU_ERROR_INVALID_DIGIT); 148 else if (overflow) { 149 if (neg) 150 uu_set_error(UU_ERROR_UNDERFLOW); 151 else 152 uu_set_error(UU_ERROR_OVERFLOW); 153 } 154 return (-1); 155 } 156 157 *out = val; 158 return (0); 159 } 160 161 int 162 uu_strtoint(const char *s, void *v, size_t sz, int base, 163 int64_t min, int64_t max) 164 { 165 uint64_t val_u; 166 int64_t val; 167 168 if (min > max) 169 goto bad_argument; 170 171 switch (sz) { 172 case 1: 173 if (max > INT8_MAX || min < INT8_MIN) 174 goto bad_argument; 175 break; 176 case 2: 177 if (max > INT16_MAX || min < INT16_MIN) 178 goto bad_argument; 179 break; 180 case 4: 181 if (max > INT32_MAX || min < INT32_MIN) 182 goto bad_argument; 183 break; 184 case 8: 185 if (max > INT64_MAX || min < INT64_MIN) 186 goto bad_argument; 187 break; 188 default: 189 goto bad_argument; 190 } 191 192 if (min == 0 && max == 0) { 193 min = -(1ULL << (8 * sz - 1)); 194 max = (1ULL << (8 * sz - 1)) - 1; 195 } 196 197 if (strtoint(s, &val_u, base, 1) == -1) 198 return (-1); 199 200 val = (int64_t)val_u; 201 202 if (val < min) { 203 uu_set_error(UU_ERROR_UNDERFLOW); 204 return (-1); 205 } else if (val > max) { 206 uu_set_error(UU_ERROR_OVERFLOW); 207 return (-1); 208 } 209 210 switch (sz) { 211 case 1: 212 *(int8_t *)v = val; 213 return (0); 214 case 2: 215 *(int16_t *)v = val; 216 return (0); 217 case 4: 218 *(int32_t *)v = val; 219 return (0); 220 case 8: 221 *(int64_t *)v = val; 222 return (0); 223 default: 224 break; /* fall through to bad_argument */ 225 } 226 227 bad_argument: 228 uu_set_error(UU_ERROR_INVALID_ARGUMENT); 229 return (-1); 230 } 231 232 int 233 uu_strtouint(const char *s, void *v, size_t sz, int base, 234 uint64_t min, uint64_t max) 235 { 236 uint64_t val; 237 238 if (min > max) 239 goto bad_argument; 240 241 switch (sz) { 242 case 1: 243 if (max > UINT8_MAX) 244 goto bad_argument; 245 break; 246 case 2: 247 if (max > UINT16_MAX) 248 goto bad_argument; 249 break; 250 case 4: 251 if (max > UINT32_MAX) 252 goto bad_argument; 253 break; 254 case 8: 255 if (max > UINT64_MAX) 256 goto bad_argument; 257 break; 258 default: 259 goto bad_argument; 260 } 261 262 if (min == 0 && max == 0) { 263 /* we have to be careful, since << can overflow */ 264 max = (1ULL << (8 * sz - 1)) * 2 - 1; 265 } 266 267 if (strtoint(s, &val, base, 0) == -1) 268 return (-1); 269 270 if (val < min) { 271 uu_set_error(UU_ERROR_UNDERFLOW); 272 return (-1); 273 } else if (val > max) { 274 uu_set_error(UU_ERROR_OVERFLOW); 275 return (-1); 276 } 277 278 switch (sz) { 279 case 1: 280 *(uint8_t *)v = val; 281 return (0); 282 case 2: 283 *(uint16_t *)v = val; 284 return (0); 285 case 4: 286 *(uint32_t *)v = val; 287 return (0); 288 case 8: 289 *(uint64_t *)v = val; 290 return (0); 291 default: 292 break; /* shouldn't happen, fall through */ 293 } 294 295 bad_argument: 296 uu_set_error(UU_ERROR_INVALID_ARGUMENT); 297 return (-1); 298 } 299