main netmisc / compat / strsuftoll.c
  1/*	$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $	*/
  2/*-
  3 * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
  4 * All rights reserved.
  5 *
  6 * This code is derived from software contributed to The NetBSD Foundation
  7 * by Luke Mewburn.
  8 *
  9 * Redistribution and use in source and binary forms, with or without
 10 * modification, are permitted provided that the following conditions
 11 * are met:
 12 * 1. Redistributions of source code must retain the above copyright
 13 *    notice, this list of conditions and the following disclaimer.
 14 * 2. Redistributions in binary form must reproduce the above copyright
 15 *    notice, this list of conditions and the following disclaimer in the
 16 *    documentation and/or other materials provided with the distribution.
 17 * 3. All advertising materials mentioning features or use of this software
 18 *    must display the following acknowledgement:
 19 *        This product includes software developed by the NetBSD
 20 *        Foundation, Inc. and its contributors.
 21 * 4. Neither the name of The NetBSD Foundation nor the names of its
 22 *    contributors may be used to endorse or promote products derived
 23 *    from this software without specific prior written permission.
 24 *
 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 28 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 35 * POSSIBILITY OF SUCH DAMAGE.
 36 */
 37/*-
 38 * Copyright (c) 1991, 1993, 1994
 39 *	The Regents of the University of California.  All rights reserved.
 40 *
 41 * This code is derived from software contributed to Berkeley by
 42 * Keith Muller of the University of California, San Diego and Lance
 43 * Visser of Convex Computer Corporation.
 44 *
 45 * Redistribution and use in source and binary forms, with or without
 46 * modification, are permitted provided that the following conditions
 47 * are met:
 48 * 1. Redistributions of source code must retain the above copyright
 49 *    notice, this list of conditions and the following disclaimer.
 50 * 2. Redistributions in binary form must reproduce the above copyright
 51 *    notice, this list of conditions and the following disclaimer in the
 52 *    documentation and/or other materials provided with the distribution.
 53 * 3. Neither the name of the University nor the names of its contributors
 54 *    may be used to endorse or promote products derived from this software
 55 *    without specific prior written permission.
 56 *
 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 60 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 67 * SUCH DAMAGE.
 68 */
 69
 70#if HAVE_NBTOOL_CONFIG_H
 71#include "nbtool_config.h"
 72#endif
 73
 74#include <sys/cdefs.h>
 75
 76#if defined(LIBC_SCCS) && !defined(lint)
 77__RCSID("$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $");
 78#endif /* LIBC_SCCS and not lint */
 79
 80#ifdef _LIBC
 81#include "namespace.h"
 82#endif
 83
 84#if !HAVE_STRSUFTOLL
 85
 86#include <sys/types.h>
 87#include <sys/time.h>
 88
 89#include <assert.h>
 90#include <ctype.h>
 91#include <err.h>
 92#include <errno.h>
 93#include <limits.h>
 94#include <stdio.h>
 95#include <stdlib.h>
 96#include <string.h>
 97
 98#ifdef _LIBC
 99# ifdef __weak_alias
100__weak_alias(strsuftoll, _strsuftoll)
101__weak_alias(strsuftollx, _strsuftollx)
102# endif
103#endif /* LIBC */
104
105long long strsuftollx(const char *, const char *, long long, long long,
106    char *, size_t);
107
108/*
109 * Convert an expression of the following forms to a (u)int64_t.
110 * 	1) A positive decimal number.
111 *	2) A positive decimal number followed by a b (mult by 512).
112 *	3) A positive decimal number followed by a k (mult by 1024).
113 *	4) A positive decimal number followed by a m (mult by 1048576).
114 *	5) A positive decimal number followed by a g (mult by 1073741824).
115 *	6) A positive decimal number followed by a t (mult by 1099511627776).
116 *	7) A positive decimal number followed by a w (mult by sizeof int)
117 *	8) Two or more positive decimal numbers (with/without k,b or w).
118 *	   separated by x (also * for backwards compatibility), specifying
119 *	   the product of the indicated values.
120 * Returns the result upon successful conversion, or exits with an
121 * appropriate error.
122 * 
123 */
124/* LONGLONG */
125long long
126strsuftoll(const char *desc, const char *val,
127    long long min, long long max)
128{
129	long long result;
130	char	errbuf[100];
131
132	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
133	if (*errbuf != '\0')
134		errx(1, "%s", errbuf);
135	return (result);
136}
137
138/*
139 * As strsuftoll(), but returns the error message into the provided buffer
140 * rather than exiting with it.
141 */
142/* LONGLONG */
143long long
144strsuftollx(const char *desc, const char *val,
145    long long min, long long max, char *ebuf, size_t ebuflen)
146{
147	long long num, t;
148	char	*expr;
149
150	_DIAGASSERT(desc != NULL);
151	_DIAGASSERT(val != NULL);
152	_DIAGASSERT(ebuf != NULL);
153
154	errno = 0;
155	ebuf[0] = '\0';
156
157	while (isspace((unsigned char)*val))	/* Skip leading space */
158		val++;
159
160	num = strtoll(val, &expr, 10);
161	if (errno == ERANGE)
162		goto erange;			/* Overflow */
163
164	if (expr == val)			/* No digits */
165		goto badnum;
166
167	switch (*expr) {
168	case 'b':
169		t = num;
170		num *= 512;			/* 1 block */
171		if (t > num)
172			goto erange;
173		++expr;
174		break;
175	case 'k':
176		t = num;
177		num *= 1024;			/* 1 kilobyte */
178		if (t > num)
179			goto erange;
180		++expr;
181		break;
182	case 'm':
183		t = num;
184		num *= 1048576;			/* 1 megabyte */
185		if (t > num)
186			goto erange;
187		++expr;
188		break;
189	case 'g':
190		t = num;
191		num *= 1073741824;		/* 1 gigabyte */
192		if (t > num)
193			goto erange;
194		++expr;
195		break;
196	case 't':
197		t = num;
198		num *= 1099511627776LL;		/* 1 terabyte */
199		if (t > num)
200			goto erange;
201		++expr;
202		break;
203	case 'w':
204		t = num;
205		num *= sizeof(int);		/* 1 word */
206		if (t > num)
207			goto erange;
208		++expr;
209		break;
210	}
211
212	switch (*expr) {
213	case '\0':
214		break;
215	case '*':				/* Backward compatible */
216	case 'x':
217		t = num;
218		num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
219		if (*ebuf != '\0')
220			return (0);
221		if (t > num) {
222 erange:	 	
223			snprintf(ebuf, ebuflen,
224			    "%s: %s", desc, strerror(ERANGE));
225			return (0);
226		}
227		break;
228	default:
229 badnum:	snprintf(ebuf, ebuflen,
230		    "%s `%s': illegal number", desc, val);
231		return (0);
232	}
233	if (num < min) {
234			/* LONGLONG */
235		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
236		    desc, (long long)num, (long long)min);
237		return (0);
238	}
239	if (num > max) {
240			/* LONGLONG */
241		snprintf(ebuf, ebuflen,
242		    "%s %lld is greater than %lld.",
243		    desc, (long long)num, (long long)max);
244		return (0);
245	}
246	*ebuf = '\0';
247	return (num);
248}
249
250#endif /* !HAVE_STRSUFTOLL */