1172029Spjd/*- 2172029Spjd * Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org> 3172029Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4172029Spjd * All rights reserved. 5172029Spjd * 6172029Spjd * Redistribution and use in source and binary forms, with or without 7172029Spjd * modification, are permitted provided that the following conditions 8172029Spjd * are met: 9172029Spjd * 1. Redistributions of source code must retain the above copyright 10172029Spjd * notice, this list of conditions and the following disclaimer. 11172029Spjd * 2. Redistributions in binary form must reproduce the above copyright 12172029Spjd * notice, this list of conditions and the following disclaimer in the 13172029Spjd * documentation and/or other materials provided with the distribution. 14172029Spjd * 15172029Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16172029Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17172029Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18172029Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19172029Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20172029Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21172029Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22172029Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23172029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24172029Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25172029Spjd * SUCH DAMAGE. 26172029Spjd */ 27172029Spjd 28172029Spjd#include <sys/cdefs.h> 29172029Spjd__FBSDID("$FreeBSD$"); 30172029Spjd 31172029Spjd#include <sys/types.h> 32172029Spjd#include <ctype.h> 33172029Spjd#include <errno.h> 34180347Skib#include <inttypes.h> 35172029Spjd#include <libutil.h> 36172029Spjd#include <stdint.h> 37172029Spjd 38172029Spjd/* 39211343Sdes * Convert an expression of the following forms to a uint64_t. 40211304Sdes * 1) A positive decimal number. 41172029Spjd * 2) A positive decimal number followed by a 'b' or 'B' (mult by 1). 42172029Spjd * 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10). 43172029Spjd * 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20). 44172029Spjd * 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30). 45172029Spjd * 6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40). 46172029Spjd * 7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50). 47172029Spjd * 8) A positive decimal number followed by a 'e' or 'E' (mult by 1 << 60). 48172029Spjd */ 49172029Spjdint 50211304Sdesexpand_number(const char *buf, uint64_t *num) 51172029Spjd{ 52211304Sdes uint64_t number; 53211343Sdes unsigned shift; 54211304Sdes char *endptr; 55172029Spjd 56211304Sdes number = strtoumax(buf, &endptr, 0); 57172029Spjd 58172029Spjd if (endptr == buf) { 59172029Spjd /* No valid digits. */ 60172029Spjd errno = EINVAL; 61172029Spjd return (-1); 62172029Spjd } 63172029Spjd 64211304Sdes switch (tolower((unsigned char)*endptr)) { 65211304Sdes case 'e': 66211343Sdes shift = 60; 67211343Sdes break; 68211304Sdes case 'p': 69211343Sdes shift = 50; 70211343Sdes break; 71211304Sdes case 't': 72211343Sdes shift = 40; 73211343Sdes break; 74211304Sdes case 'g': 75211343Sdes shift = 30; 76211343Sdes break; 77211304Sdes case 'm': 78211343Sdes shift = 20; 79211343Sdes break; 80211304Sdes case 'k': 81211343Sdes shift = 10; 82211343Sdes break; 83172049Spjd case 'b': 84211343Sdes case '\0': /* No unit. */ 85211343Sdes *num = number; 86211343Sdes return (0); 87172049Spjd default: 88172049Spjd /* Unrecognized unit. */ 89172049Spjd errno = EINVAL; 90172049Spjd return (-1); 91172049Spjd } 92172049Spjd 93211343Sdes if ((number << shift) >> shift != number) { 94211343Sdes /* Overflow */ 95211343Sdes errno = ERANGE; 96211343Sdes return (-1); 97211343Sdes } 98211343Sdes 99211343Sdes *num = number << shift; 100172029Spjd return (0); 101172029Spjd} 102