1bf21cd93STycho Nightingale /*-
2bf21cd93STycho Nightingale  * Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
3bf21cd93STycho Nightingale  * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4bf21cd93STycho Nightingale  * All rights reserved.
5bf21cd93STycho Nightingale  *
6bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
7bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
8bf21cd93STycho Nightingale  * are met:
9bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
10bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
11bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
12bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
13bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
14bf21cd93STycho Nightingale  *
15bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25bf21cd93STycho Nightingale  * SUCH DAMAGE.
26bf21cd93STycho Nightingale  */
27bf21cd93STycho Nightingale 
28bf21cd93STycho Nightingale #include <sys/cdefs.h>
29bf21cd93STycho Nightingale 
30bf21cd93STycho Nightingale #include <sys/types.h>
31bf21cd93STycho Nightingale #include <ctype.h>
32bf21cd93STycho Nightingale #include <errno.h>
33bf21cd93STycho Nightingale #include <inttypes.h>
34bf21cd93STycho Nightingale #include <libutil.h>
35bf21cd93STycho Nightingale #include <stdint.h>
36bf21cd93STycho Nightingale 
37bf21cd93STycho Nightingale int
expand_number(const char * buf,uint64_t * num)38bf21cd93STycho Nightingale expand_number(const char *buf, uint64_t *num)
39bf21cd93STycho Nightingale {
40bf21cd93STycho Nightingale 	char *endptr;
41bf21cd93STycho Nightingale 	uintmax_t umaxval;
42bf21cd93STycho Nightingale 	uint64_t number;
43bf21cd93STycho Nightingale 	unsigned shift;
44bf21cd93STycho Nightingale 	int serrno;
45bf21cd93STycho Nightingale 
46bf21cd93STycho Nightingale 	serrno = errno;
47bf21cd93STycho Nightingale 	errno = 0;
48bf21cd93STycho Nightingale 	umaxval = strtoumax(buf, &endptr, 0);
49*b0de25cbSAndy Fiddaman #ifdef __FreeBSD__
50bf21cd93STycho Nightingale 	if (umaxval > UINT64_MAX)
51bf21cd93STycho Nightingale 		errno = ERANGE;
52*b0de25cbSAndy Fiddaman #endif
53bf21cd93STycho Nightingale 	if (errno != 0)
54bf21cd93STycho Nightingale 		return (-1);
55bf21cd93STycho Nightingale 	errno = serrno;
56bf21cd93STycho Nightingale 	number = umaxval;
57bf21cd93STycho Nightingale 
58bf21cd93STycho Nightingale 	switch (tolower((unsigned char)*endptr)) {
59bf21cd93STycho Nightingale 	case 'e':
60bf21cd93STycho Nightingale 		shift = 60;
61bf21cd93STycho Nightingale 		break;
62bf21cd93STycho Nightingale 	case 'p':
63bf21cd93STycho Nightingale 		shift = 50;
64bf21cd93STycho Nightingale 		break;
65bf21cd93STycho Nightingale 	case 't':
66bf21cd93STycho Nightingale 		shift = 40;
67bf21cd93STycho Nightingale 		break;
68bf21cd93STycho Nightingale 	case 'g':
69bf21cd93STycho Nightingale 		shift = 30;
70bf21cd93STycho Nightingale 		break;
71bf21cd93STycho Nightingale 	case 'm':
72bf21cd93STycho Nightingale 		shift = 20;
73bf21cd93STycho Nightingale 		break;
74bf21cd93STycho Nightingale 	case 'k':
75bf21cd93STycho Nightingale 		shift = 10;
76bf21cd93STycho Nightingale 		break;
77bf21cd93STycho Nightingale 	case 'b':
78bf21cd93STycho Nightingale 	case '\0': /* No unit. */
79bf21cd93STycho Nightingale 		*num = number;
80bf21cd93STycho Nightingale 		return (0);
81bf21cd93STycho Nightingale 	default:
82bf21cd93STycho Nightingale 		/* Unrecognized unit. */
83bf21cd93STycho Nightingale 		errno = EINVAL;
84bf21cd93STycho Nightingale 		return (-1);
85bf21cd93STycho Nightingale 	}
86bf21cd93STycho Nightingale 
87bf21cd93STycho Nightingale 	if ((number << shift) >> shift != number) {
88bf21cd93STycho Nightingale 		/* Overflow */
89bf21cd93STycho Nightingale 		errno = ERANGE;
90bf21cd93STycho Nightingale 		return (-1);
91bf21cd93STycho Nightingale 	}
92bf21cd93STycho Nightingale 	*num = number << shift;
93bf21cd93STycho Nightingale 	return (0);
94bf21cd93STycho Nightingale }
95