Home | History | Annotate | Line # | Download | only in common
      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