11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993, 1994
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Keith Muller of the University of California, San Diego and Lance
71556Srgrimes * Visser of Convex Computer Corporation.
81556Srgrimes *
91556Srgrimes * Redistribution and use in source and binary forms, with or without
101556Srgrimes * modification, are permitted provided that the following conditions
111556Srgrimes * are met:
121556Srgrimes * 1. Redistributions of source code must retain the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer.
141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151556Srgrimes *    notice, this list of conditions and the following disclaimer in the
161556Srgrimes *    documentation and/or other materials provided with the distribution.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
3535773Scharnier#if 0
3636007Scharnierstatic char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
3735773Scharnier#endif
381556Srgrimes#endif /* not lint */
3999109Sobrien#include <sys/cdefs.h>
4099109Sobrien__FBSDID("$FreeBSD$");
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes
441556Srgrimes#include <err.h>
451556Srgrimes#include <errno.h>
46111629Smarkm#include <inttypes.h>
471556Srgrimes#include <limits.h>
48250469Seadler#include <signal.h>
491556Srgrimes#include <stdlib.h>
501556Srgrimes#include <string.h>
511556Srgrimes
521556Srgrimes#include "dd.h"
531556Srgrimes#include "extern.h"
541556Srgrimes
5590108Simpstatic int	c_arg(const void *, const void *);
5690108Simpstatic int	c_conv(const void *, const void *);
5790108Simpstatic void	f_bs(char *);
5890108Simpstatic void	f_cbs(char *);
5990108Simpstatic void	f_conv(char *);
6090108Simpstatic void	f_count(char *);
6190108Simpstatic void	f_files(char *);
62133762Srwatsonstatic void	f_fillchar(char *);
6390108Simpstatic void	f_ibs(char *);
6490108Simpstatic void	f_if(char *);
6590108Simpstatic void	f_obs(char *);
6690108Simpstatic void	f_of(char *);
6790108Simpstatic void	f_seek(char *);
6890108Simpstatic void	f_skip(char *);
69264577Sdelphijstatic void	f_status(char *);
70111629Smarkmstatic uintmax_t get_num(const char *);
7190108Simpstatic off_t	get_off_t(const char *);
721556Srgrimes
7351208Sgreenstatic const struct arg {
7454245Sgreen	const char *name;
7590108Simp	void (*f)(char *);
761556Srgrimes	u_int set, noset;
771556Srgrimes} args[] = {
781556Srgrimes	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
791556Srgrimes	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
801556Srgrimes	{ "conv",	f_conv,		0,	 0 },
811556Srgrimes	{ "count",	f_count,	C_COUNT, C_COUNT },
821556Srgrimes	{ "files",	f_files,	C_FILES, C_FILES },
83133762Srwatson	{ "fillchar",	f_fillchar,	C_FILL,	 C_FILL },
841556Srgrimes	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
851556Srgrimes	{ "if",		f_if,		C_IF,	 C_IF },
8657523Sgreen	{ "iseek",	f_skip,		C_SKIP,	 C_SKIP },
871556Srgrimes	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
881556Srgrimes	{ "of",		f_of,		C_OF,	 C_OF },
8957523Sgreen	{ "oseek",	f_seek,		C_SEEK,	 C_SEEK },
901556Srgrimes	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
911556Srgrimes	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
92264577Sdelphij	{ "status",	f_status,	C_STATUS,C_STATUS },
931556Srgrimes};
941556Srgrimes
951556Srgrimesstatic char *oper;
961556Srgrimes
971556Srgrimes/*
981556Srgrimes * args -- parse JCL syntax of dd.
991556Srgrimes */
1001556Srgrimesvoid
10190108Simpjcl(char **argv)
1021556Srgrimes{
1031556Srgrimes	struct arg *ap, tmp;
1041556Srgrimes	char *arg;
1051556Srgrimes
1061556Srgrimes	in.dbsz = out.dbsz = 512;
1071556Srgrimes
10819720Sphk	while ((oper = *++argv) != NULL) {
10930230Seivind		if ((oper = strdup(oper)) == NULL)
11048051Sgreen			errx(1, "unable to allocate space for the argument \"%s\"", *argv);
1111556Srgrimes		if ((arg = strchr(oper, '=')) == NULL)
1121556Srgrimes			errx(1, "unknown operand %s", oper);
1131556Srgrimes		*arg++ = '\0';
1141556Srgrimes		if (!*arg)
1151556Srgrimes			errx(1, "no value specified for %s", oper);
1161556Srgrimes		tmp.name = oper;
11748051Sgreen		if (!(ap = (struct arg *)bsearch(&tmp, args,
11848051Sgreen		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
11948051Sgreen		    c_arg)))
1201556Srgrimes			errx(1, "unknown operand %s", tmp.name);
1211556Srgrimes		if (ddflags & ap->noset)
12248051Sgreen			errx(1, "%s: illegal argument combination or already set",
12348051Sgreen			    tmp.name);
1241556Srgrimes		ddflags |= ap->set;
1251556Srgrimes		ap->f(arg);
1261556Srgrimes	}
1271556Srgrimes
1281556Srgrimes	/* Final sanity checks. */
1291556Srgrimes
1301556Srgrimes	if (ddflags & C_BS) {
1311556Srgrimes		/*
1321556Srgrimes		 * Bs is turned off by any conversion -- we assume the user
1331556Srgrimes		 * just wanted to set both the input and output block sizes
1341556Srgrimes		 * and didn't want the bs semantics, so we don't warn.
1351556Srgrimes		 */
13662311Sgreen		if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
13762311Sgreen		    C_UNBLOCK))
1381556Srgrimes			ddflags &= ~C_BS;
1391556Srgrimes
1401556Srgrimes		/* Bs supersedes ibs and obs. */
14162311Sgreen		if (ddflags & C_BS && ddflags & (C_IBS | C_OBS))
1421556Srgrimes			warnx("bs supersedes ibs and obs");
1431556Srgrimes	}
1441556Srgrimes
1451556Srgrimes	/*
1461556Srgrimes	 * Ascii/ebcdic and cbs implies block/unblock.
1471556Srgrimes	 * Block/unblock requires cbs and vice-versa.
1481556Srgrimes	 */
14951249Sgreen	if (ddflags & (C_BLOCK | C_UNBLOCK)) {
1501556Srgrimes		if (!(ddflags & C_CBS))
1511556Srgrimes			errx(1, "record operations require cbs");
1521556Srgrimes		if (cbsz == 0)
1531556Srgrimes			errx(1, "cbs cannot be zero");
1541556Srgrimes		cfunc = ddflags & C_BLOCK ? block : unblock;
1551556Srgrimes	} else if (ddflags & C_CBS) {
15651249Sgreen		if (ddflags & (C_ASCII | C_EBCDIC)) {
1571556Srgrimes			if (ddflags & C_ASCII) {
1581556Srgrimes				ddflags |= C_UNBLOCK;
1591556Srgrimes				cfunc = unblock;
1601556Srgrimes			} else {
1611556Srgrimes				ddflags |= C_BLOCK;
1621556Srgrimes				cfunc = block;
1631556Srgrimes			}
1641556Srgrimes		} else
1651556Srgrimes			errx(1, "cbs meaningless if not doing record operations");
1661556Srgrimes	} else
1671556Srgrimes		cfunc = def;
16851249Sgreen
16951208Sgreen	/*
17051208Sgreen	 * Bail out if the calculation of a file offset would overflow.
17151208Sgreen	 */
172111629Smarkm	if (in.offset > OFF_MAX / (ssize_t)in.dbsz ||
173111629Smarkm	    out.offset > OFF_MAX / (ssize_t)out.dbsz)
174111629Smarkm		errx(1, "seek offsets cannot be larger than %jd",
175111629Smarkm		    (intmax_t)OFF_MAX);
1761556Srgrimes}
1771556Srgrimes
1781556Srgrimesstatic int
17990108Simpc_arg(const void *a, const void *b)
1801556Srgrimes{
1811556Srgrimes
18254278Sgreen	return (strcmp(((const struct arg *)a)->name,
18354278Sgreen	    ((const struct arg *)b)->name));
1841556Srgrimes}
1851556Srgrimes
1861556Srgrimesstatic void
18790108Simpf_bs(char *arg)
1881556Srgrimes{
189111629Smarkm	uintmax_t res;
1901556Srgrimes
19151208Sgreen	res = get_num(arg);
19251208Sgreen	if (res < 1 || res > SSIZE_MAX)
193112265Sru		errx(1, "bs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
19451208Sgreen	in.dbsz = out.dbsz = (size_t)res;
1951556Srgrimes}
1961556Srgrimes
1971556Srgrimesstatic void
19890108Simpf_cbs(char *arg)
1991556Srgrimes{
200111629Smarkm	uintmax_t res;
2011556Srgrimes
20251208Sgreen	res = get_num(arg);
20351208Sgreen	if (res < 1 || res > SSIZE_MAX)
204112265Sru		errx(1, "cbs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
20551208Sgreen	cbsz = (size_t)res;
2061556Srgrimes}
2071556Srgrimes
2081556Srgrimesstatic void
20990108Simpf_count(char *arg)
2101556Srgrimes{
211111629Smarkm	intmax_t res;
2121556Srgrimes
213111629Smarkm	res = (intmax_t)get_num(arg);
214111629Smarkm	if (res < 0)
21551326Sgreen		errx(1, "count cannot be negative");
21689788Sgreen	if (res == 0)
217111629Smarkm		cpy_cnt = (uintmax_t)-1;
21889788Sgreen	else
219111629Smarkm		cpy_cnt = (uintmax_t)res;
2201556Srgrimes}
2211556Srgrimes
2221556Srgrimesstatic void
22390108Simpf_files(char *arg)
2241556Srgrimes{
2251556Srgrimes
22651137Sgreen	files_cnt = get_num(arg);
22751249Sgreen	if (files_cnt < 1)
228111629Smarkm		errx(1, "files must be between 1 and %jd", (uintmax_t)-1);
2291556Srgrimes}
2301556Srgrimes
2311556Srgrimesstatic void
232133762Srwatsonf_fillchar(char *arg)
233133762Srwatson{
234133762Srwatson
235133762Srwatson	if (strlen(arg) != 1)
236133762Srwatson		errx(1, "need exactly one fill char");
237133762Srwatson
238133762Srwatson	fill_char = arg[0];
239133762Srwatson}
240133762Srwatson
241133762Srwatsonstatic void
24290108Simpf_ibs(char *arg)
2431556Srgrimes{
244111629Smarkm	uintmax_t res;
2451556Srgrimes
24648051Sgreen	if (!(ddflags & C_BS)) {
24751208Sgreen		res = get_num(arg);
24851208Sgreen		if (res < 1 || res > SSIZE_MAX)
249112265Sru			errx(1, "ibs must be between 1 and %jd",
250112265Sru			    (intmax_t)SSIZE_MAX);
25151249Sgreen		in.dbsz = (size_t)res;
25248051Sgreen	}
2531556Srgrimes}
2541556Srgrimes
2551556Srgrimesstatic void
25690108Simpf_if(char *arg)
2571556Srgrimes{
2581556Srgrimes
2591556Srgrimes	in.name = arg;
2601556Srgrimes}
2611556Srgrimes
2621556Srgrimesstatic void
26390108Simpf_obs(char *arg)
2641556Srgrimes{
265111629Smarkm	uintmax_t res;
2661556Srgrimes
26748051Sgreen	if (!(ddflags & C_BS)) {
26851208Sgreen		res = get_num(arg);
26951208Sgreen		if (res < 1 || res > SSIZE_MAX)
270112265Sru			errx(1, "obs must be between 1 and %jd",
271112265Sru			    (intmax_t)SSIZE_MAX);
27251208Sgreen		out.dbsz = (size_t)res;
27348051Sgreen	}
2741556Srgrimes}
2751556Srgrimes
2761556Srgrimesstatic void
27790108Simpf_of(char *arg)
2781556Srgrimes{
2791556Srgrimes
2801556Srgrimes	out.name = arg;
2811556Srgrimes}
2821556Srgrimes
2831556Srgrimesstatic void
28490108Simpf_seek(char *arg)
2851556Srgrimes{
2861556Srgrimes
28789788Sgreen	out.offset = get_off_t(arg);
2881556Srgrimes}
2891556Srgrimes
2901556Srgrimesstatic void
29190108Simpf_skip(char *arg)
2921556Srgrimes{
2931556Srgrimes
29489788Sgreen	in.offset = get_off_t(arg);
2951556Srgrimes}
2961556Srgrimes
297264577Sdelphijstatic void
298264577Sdelphijf_status(char *arg)
299264577Sdelphij{
300264577Sdelphij
301264577Sdelphij	if (strcmp(arg, "none") == 0)
302264577Sdelphij		ddflags |= C_NOINFO;
303264577Sdelphij	else if (strcmp(arg, "noxfer") == 0)
304264577Sdelphij		ddflags |= C_NOXFER;
305264577Sdelphij	else
306264577Sdelphij		errx(1, "unknown status %s", arg);
307264577Sdelphij}
308264577Sdelphij
30951208Sgreenstatic const struct conv {
31054245Sgreen	const char *name;
3111556Srgrimes	u_int set, noset;
31251208Sgreen	const u_char *ctab;
3131556Srgrimes} clist[] = {
3141556Srgrimes	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
3151556Srgrimes	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
3161556Srgrimes	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
3171556Srgrimes	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
3181556Srgrimes	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
3191556Srgrimes	{ "noerror",	C_NOERROR,	0,		NULL },
3201556Srgrimes	{ "notrunc",	C_NOTRUNC,	0,		NULL },
3211556Srgrimes	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
3221556Srgrimes	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
3231556Srgrimes	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
32431120Sjoerg	{ "osync",	C_OSYNC,	C_BS,		NULL },
325126667Sphk	{ "pareven",	C_PAREVEN,	C_PARODD|C_PARSET|C_PARNONE, NULL},
326126667Sphk	{ "parnone",	C_PARNONE,	C_PARODD|C_PARSET|C_PAREVEN, NULL},
327126667Sphk	{ "parodd",	C_PARODD,	C_PAREVEN|C_PARSET|C_PARNONE, NULL},
328126667Sphk	{ "parset",	C_PARSET,	C_PARODD|C_PAREVEN|C_PARNONE, NULL},
32930312Sjoerg	{ "sparse",	C_SPARSE,	0,		NULL },
3301556Srgrimes	{ "swab",	C_SWAB,		0,		NULL },
3311556Srgrimes	{ "sync",	C_SYNC,		0,		NULL },
3321556Srgrimes	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
3331556Srgrimes	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
3341556Srgrimes};
3351556Srgrimes
3361556Srgrimesstatic void
33790108Simpf_conv(char *arg)
3381556Srgrimes{
3391556Srgrimes	struct conv *cp, tmp;
3401556Srgrimes
3411556Srgrimes	while (arg != NULL) {
3421556Srgrimes		tmp.name = strsep(&arg, ",");
34351208Sgreen		cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv),
34451208Sgreen		    sizeof(struct conv), c_conv);
34551208Sgreen		if (cp == NULL)
3461556Srgrimes			errx(1, "unknown conversion %s", tmp.name);
3471556Srgrimes		if (ddflags & cp->noset)
3481556Srgrimes			errx(1, "%s: illegal conversion combination", tmp.name);
3491556Srgrimes		ddflags |= cp->set;
3501556Srgrimes		if (cp->ctab)
3511556Srgrimes			ctab = cp->ctab;
3521556Srgrimes	}
3531556Srgrimes}
3541556Srgrimes
3551556Srgrimesstatic int
35690108Simpc_conv(const void *a, const void *b)
3571556Srgrimes{
3581556Srgrimes
35954278Sgreen	return (strcmp(((const struct conv *)a)->name,
36054278Sgreen	    ((const struct conv *)b)->name));
3611556Srgrimes}
3621556Srgrimes
3631556Srgrimes/*
364111629Smarkm * Convert an expression of the following forms to a uintmax_t.
3651556Srgrimes * 	1) A positive decimal number.
366132933Spjd *	2) A positive decimal number followed by a 'b' or 'B' (mult by 512).
367132933Spjd *	3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
368132933Spjd *	4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
369132933Spjd *	5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
370132933Spjd *	5) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int).
371132933Spjd *	6) Two or more positive decimal numbers (with/without [BbKkMmGgWw])
372132933Spjd *	   separated by 'x' or 'X' (also '*' for backwards compatibility),
373132933Spjd *	   specifying the product of the indicated values.
3741556Srgrimes */
375111629Smarkmstatic uintmax_t
37690108Simpget_num(const char *val)
3771556Srgrimes{
378111629Smarkm	uintmax_t num, mult, prevnum;
3791556Srgrimes	char *expr;
3801556Srgrimes
38148051Sgreen	errno = 0;
38289788Sgreen	num = strtouq(val, &expr, 0);
38351208Sgreen	if (errno != 0)				/* Overflow or underflow. */
38448051Sgreen		err(1, "%s", oper);
38548051Sgreen
38651208Sgreen	if (expr == val)			/* No valid digits. */
3871556Srgrimes		errx(1, "%s: illegal numeric value", oper);
3881556Srgrimes
38989788Sgreen	mult = 0;
39051137Sgreen	switch (*expr) {
391132933Spjd	case 'B':
3921556Srgrimes	case 'b':
39389788Sgreen		mult = 512;
3941556Srgrimes		break;
395132933Spjd	case 'K':
3961556Srgrimes	case 'k':
39789788Sgreen		mult = 1 << 10;
3981556Srgrimes		break;
399132933Spjd	case 'M':
4001556Srgrimes	case 'm':
40189788Sgreen		mult = 1 << 20;
4021556Srgrimes		break;
403132933Spjd	case 'G':
40448051Sgreen	case 'g':
40589788Sgreen		mult = 1 << 30;
40648051Sgreen		break;
407132933Spjd	case 'W':
4081556Srgrimes	case 'w':
40989788Sgreen		mult = sizeof(int);
4101556Srgrimes		break;
41191079Smarkm	default:
41296383Sjedgar		;
4131556Srgrimes	}
4141556Srgrimes
41589788Sgreen	if (mult != 0) {
41689788Sgreen		prevnum = num;
41789788Sgreen		num *= mult;
41889788Sgreen		/* Check for overflow. */
41989788Sgreen		if (num / mult != prevnum)
42089788Sgreen			goto erange;
42189788Sgreen		expr++;
42289788Sgreen	}
42389788Sgreen
42451137Sgreen	switch (*expr) {
4251556Srgrimes		case '\0':
4261556Srgrimes			break;
4271556Srgrimes		case '*':			/* Backward compatible. */
428132933Spjd		case 'X':
4291556Srgrimes		case 'x':
43089788Sgreen			mult = get_num(expr + 1);
43189788Sgreen			prevnum = num;
43289788Sgreen			num *= mult;
43389788Sgreen			if (num / mult == prevnum)
43451137Sgreen				break;
43551137Sgreenerange:
43651137Sgreen			errx(1, "%s: %s", oper, strerror(ERANGE));
4371556Srgrimes		default:
4381556Srgrimes			errx(1, "%s: illegal numeric value", oper);
4391556Srgrimes	}
4401556Srgrimes	return (num);
4411556Srgrimes}
44251208Sgreen
44389788Sgreen/*
44489788Sgreen * Convert an expression of the following forms to an off_t.  This is the
44589788Sgreen * same as get_num(), but it uses signed numbers.
44689788Sgreen *
447111629Smarkm * The major problem here is that an off_t may not necessarily be a intmax_t.
44889788Sgreen */
44951208Sgreenstatic off_t
45090108Simpget_off_t(const char *val)
45151208Sgreen{
452111629Smarkm	intmax_t num, mult, prevnum;
45389788Sgreen	char *expr;
45451208Sgreen
45589788Sgreen	errno = 0;
45689788Sgreen	num = strtoq(val, &expr, 0);
45789788Sgreen	if (errno != 0)				/* Overflow or underflow. */
45889788Sgreen		err(1, "%s", oper);
45989788Sgreen
46089788Sgreen	if (expr == val)			/* No valid digits. */
46189788Sgreen		errx(1, "%s: illegal numeric value", oper);
46289788Sgreen
46389788Sgreen	mult = 0;
46489788Sgreen	switch (*expr) {
465132933Spjd	case 'B':
46689788Sgreen	case 'b':
46789788Sgreen		mult = 512;
46889788Sgreen		break;
469132933Spjd	case 'K':
47089788Sgreen	case 'k':
47189788Sgreen		mult = 1 << 10;
47289788Sgreen		break;
473132933Spjd	case 'M':
47489788Sgreen	case 'm':
47589788Sgreen		mult = 1 << 20;
47689788Sgreen		break;
477132933Spjd	case 'G':
47889788Sgreen	case 'g':
47989788Sgreen		mult = 1 << 30;
48089788Sgreen		break;
481132933Spjd	case 'W':
48289788Sgreen	case 'w':
48389788Sgreen		mult = sizeof(int);
48489788Sgreen		break;
48589788Sgreen	}
48689788Sgreen
48789788Sgreen	if (mult != 0) {
48889788Sgreen		prevnum = num;
48989788Sgreen		num *= mult;
49089788Sgreen		/* Check for overflow. */
49189788Sgreen		if ((prevnum > 0) != (num > 0) || num / mult != prevnum)
49289788Sgreen			goto erange;
49389788Sgreen		expr++;
49489788Sgreen	}
49589788Sgreen
49689788Sgreen	switch (*expr) {
49789788Sgreen		case '\0':
49889788Sgreen			break;
49989788Sgreen		case '*':			/* Backward compatible. */
500132933Spjd		case 'X':
50189788Sgreen		case 'x':
502111629Smarkm			mult = (intmax_t)get_off_t(expr + 1);
50389788Sgreen			prevnum = num;
50489788Sgreen			num *= mult;
50590331Sgreen			if ((prevnum > 0) == (num > 0) && num / mult == prevnum)
50689788Sgreen				break;
50789788Sgreenerange:
50889788Sgreen			errx(1, "%s: %s", oper, strerror(ERANGE));
50989788Sgreen		default:
51089788Sgreen			errx(1, "%s: illegal numeric value", oper);
51189788Sgreen	}
51289788Sgreen	return (num);
51351208Sgreen}
514