odsyntax.c revision 102944
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1990, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3527315Scharnier#if 0
3623693Speterstatic char sccsid[] = "@(#)odsyntax.c	8.2 (Berkeley) 5/4/95";
3727315Scharnier#endif
381590Srgrimes#endif /* not lint */
3999112Sobrien#include <sys/cdefs.h>
4099112Sobrien__FBSDID("$FreeBSD: head/usr.bin/hexdump/odsyntax.c 102944 2002-09-04 23:29:10Z dwmalone $");
411590Srgrimes
421590Srgrimes#include <sys/types.h>
431590Srgrimes
4423693Speter#include <ctype.h>
4527315Scharnier#include <err.h>
4696795Stjr#include <errno.h>
4796795Stjr#include <float.h>
4823693Speter#include <stdio.h>
491590Srgrimes#include <stdlib.h>
5096795Stjr#include <string.h>
5123693Speter#include <unistd.h>
5223693Speter
531590Srgrimes#include "hexdump.h"
541590Srgrimes
5596795Stjr#define PADDING	"         "
5696795Stjr
5796787Stjrint odmode;
581590Srgrimes
5996795Stjrstatic void odadd(const char *);
6096795Stjrstatic void odformat(const char *);
6196795Stjrstatic const char *odformatfp(char, const char *);
6296795Stjrstatic const char *odformatint(char, const char *);
6392920Simpstatic void odoffset(int, char ***);
6496795Stjrstatic void odusage(void);
651590Srgrimes
661590Srgrimesvoid
67102944Sdwmaloneoldsyntax(int argc, char ***argvp)
681590Srgrimes{
6996795Stjr	static char empty[] = "", padding[] = PADDING;
701590Srgrimes	int ch;
7196795Stjr	char **argv, *end;
721590Srgrimes
7396795Stjr	/* Add initial (default) address format. -A may change it later. */
7496795Stjr#define	TYPE_OFFSET	7
7596795Stjr	add("\"%07.7_Ao\n\"");
7696795Stjr	add("\"%07.7_ao  \"");
7796795Stjr
7896787Stjr	odmode = 1;
791590Srgrimes	argv = *argvp;
8096795Stjr	while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1)
811590Srgrimes		switch (ch) {
8296795Stjr		case 'A':
8396795Stjr			switch (*optarg) {
8496795Stjr			case 'd': case 'o': case 'x':
8596795Stjr				fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
8696795Stjr				fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
8796795Stjr				    *optarg;
8896795Stjr				break;
8996795Stjr			case 'n':
9096795Stjr				fshead->nextfu->fmt = empty;
9196795Stjr				fshead->nextfs->nextfu->fmt = padding;
9296795Stjr				break;
9396795Stjr			default:
9496795Stjr				errx(1, "%s: invalid address base", optarg);
9596795Stjr			}
9696795Stjr			break;
971590Srgrimes		case 'a':
9896795Stjr			odformat("a");
991590Srgrimes			break;
1001590Srgrimes		case 'B':
1011590Srgrimes		case 'o':
10296795Stjr			odformat("o2");
1031590Srgrimes			break;
1041590Srgrimes		case 'b':
10596795Stjr			odformat("o1");
1061590Srgrimes			break;
1071590Srgrimes		case 'c':
10896795Stjr			odformat("c");
1091590Srgrimes			break;
1101590Srgrimes		case 'd':
11196795Stjr			odformat("u2");
1121590Srgrimes			break;
1131590Srgrimes		case 'D':
11496795Stjr			odformat("u4");
1151590Srgrimes			break;
1161590Srgrimes		case 'e':		/* undocumented in od */
1171590Srgrimes		case 'F':
11896795Stjr			odformat("fD");
1191590Srgrimes			break;
1201590Srgrimes		case 'f':
12196795Stjr			odformat("fF");
1221590Srgrimes			break;
1231590Srgrimes		case 'H':
1241590Srgrimes		case 'X':
12596795Stjr			odformat("x4");
1261590Srgrimes			break;
1271590Srgrimes		case 'h':
1281590Srgrimes		case 'x':
12996795Stjr			odformat("x2");
1301590Srgrimes			break;
1311590Srgrimes		case 'I':
1321590Srgrimes		case 'L':
1331590Srgrimes		case 'l':
13496795Stjr			odformat("dL");
1351590Srgrimes			break;
1361590Srgrimes		case 'i':
13796795Stjr			odformat("dI");
1381590Srgrimes			break;
13996795Stjr		case 'j':
14096795Stjr			errno = 0;
14196795Stjr			skip = strtoll(optarg, &end, 0);
14296795Stjr			if (*end == 'b')
14396795Stjr				skip *= 512;
14496795Stjr			else if (*end == 'k')
14596795Stjr				skip *= 1024;
14696795Stjr			else if (*end == 'm')
14796795Stjr				skip *= 1048576L;
14896795Stjr			if (errno != 0 || skip < 0 || strlen(end) > 1)
14996795Stjr				errx(1, "%s: invalid skip amount", optarg);
15096795Stjr			break;
15196795Stjr		case 'N':
15296795Stjr			if ((length = atoi(optarg)) <= 0)
15396795Stjr				errx(1, "%s: invalid length", optarg);
15496795Stjr			break;
1551590Srgrimes		case 'O':
15696795Stjr			odformat("o4");
1571590Srgrimes			break;
15896795Stjr		case 's':
15996795Stjr			odformat("d2");
16096795Stjr			break;
16196795Stjr		case 't':
16296795Stjr			odformat(optarg);
16396795Stjr			break;
1641590Srgrimes		case 'v':
1651590Srgrimes			vflag = ALL;
1661590Srgrimes			break;
1671590Srgrimes		case '?':
1681590Srgrimes		default:
16996795Stjr			odusage();
1701590Srgrimes		}
1711590Srgrimes
17296795Stjr	if (fshead->nextfs->nextfs == NULL)
17396795Stjr		odformat("oS");
1741590Srgrimes
1751590Srgrimes	argc -= optind;
1761590Srgrimes	*argvp += optind;
1771590Srgrimes
1781590Srgrimes	if (argc)
1791590Srgrimes		odoffset(argc, argvp);
1801590Srgrimes}
1811590Srgrimes
1821590Srgrimesstatic void
18396795Stjrodusage(void)
18496795Stjr{
18596795Stjr
18696795Stjr	fprintf(stderr,
18796795Stjr"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n");
18896795Stjr	fprintf(stderr,
18996795Stjr"          [[+]offset[.][Bb]] [file ...]\n");
19096795Stjr	exit(1);
19196795Stjr}
19296795Stjr
19396795Stjrstatic void
194102944Sdwmaloneodoffset(int argc, char ***argvp)
1951590Srgrimes{
19630921Sache	unsigned char *p, *num, *end;
1971590Srgrimes	int base;
1981590Srgrimes
1991590Srgrimes	/*
2001590Srgrimes	 * The offset syntax of od(1) was genuinely bizarre.  First, if
2011590Srgrimes	 * it started with a plus it had to be an offset.  Otherwise, if
2021590Srgrimes	 * there were at least two arguments, a number or lower-case 'x'
2031590Srgrimes	 * followed by a number makes it an offset.  By default it was
2041590Srgrimes	 * octal; if it started with 'x' or '0x' it was hex.  If it ended
2051590Srgrimes	 * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
2061590Srgrimes	 * multiplied the number by 512 or 1024 byte units.  There was
2071590Srgrimes	 * no way to assign a block count to a hex offset.
2081590Srgrimes	 *
2091590Srgrimes	 * We assume it's a file if the offset is bad.
2101590Srgrimes	 */
2111590Srgrimes	p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
2121590Srgrimes
2131590Srgrimes	if (*p != '+' && (argc < 2 ||
2141590Srgrimes	    (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1])))))
2151590Srgrimes		return;
2161590Srgrimes
2171590Srgrimes	base = 0;
2181590Srgrimes	/*
2191590Srgrimes	 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
2201590Srgrimes	 * set base.
2211590Srgrimes	 */
2221590Srgrimes	if (p[0] == '+')
2231590Srgrimes		++p;
2241590Srgrimes	if (p[0] == 'x' && isxdigit(p[1])) {
2251590Srgrimes		++p;
2261590Srgrimes		base = 16;
2271590Srgrimes	} else if (p[0] == '0' && p[1] == 'x') {
2281590Srgrimes		p += 2;
2291590Srgrimes		base = 16;
2301590Srgrimes	}
2311590Srgrimes
2321590Srgrimes	/* skip over the number */
2331590Srgrimes	if (base == 16)
2341590Srgrimes		for (num = p; isxdigit(*p); ++p);
2351590Srgrimes	else
2361590Srgrimes		for (num = p; isdigit(*p); ++p);
2371590Srgrimes
2381590Srgrimes	/* check for no number */
2391590Srgrimes	if (num == p)
2401590Srgrimes		return;
2411590Srgrimes
2421590Srgrimes	/* if terminates with a '.', base is decimal */
2431590Srgrimes	if (*p == '.') {
2441590Srgrimes		if (base)
2451590Srgrimes			return;
2461590Srgrimes		base = 10;
2471590Srgrimes	}
2481590Srgrimes
24982766Sache	skip = strtoll(num, (char **)&end, base ? base : 8);
2501590Srgrimes
2511590Srgrimes	/* if end isn't the same as p, we got a non-octal digit */
2521590Srgrimes	if (end != p) {
2531590Srgrimes		skip = 0;
2541590Srgrimes		return;
2551590Srgrimes	}
2561590Srgrimes
25748566Sbillf	if (*p) {
2581590Srgrimes		if (*p == 'B') {
2591590Srgrimes			skip *= 1024;
2601590Srgrimes			++p;
2611590Srgrimes		} else if (*p == 'b') {
2621590Srgrimes			skip *= 512;
2631590Srgrimes			++p;
2641590Srgrimes		}
26548566Sbillf	}
2661590Srgrimes
2671590Srgrimes	if (*p) {
2681590Srgrimes		skip = 0;
2691590Srgrimes		return;
2701590Srgrimes	}
2711590Srgrimes
2721590Srgrimes	/*
2731590Srgrimes	 * If the offset uses a non-octal base, the base of the offset
2741590Srgrimes	 * is changed as well.  This isn't pretty, but it's easy.
2751590Srgrimes	 */
2761590Srgrimes	if (base == 16) {
2771590Srgrimes		fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
2781590Srgrimes		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
2791590Srgrimes	} else if (base == 10) {
2801590Srgrimes		fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
2811590Srgrimes		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
2821590Srgrimes	}
2831590Srgrimes
2841590Srgrimes	/* Terminate file list. */
2851590Srgrimes	(*argvp)[1] = NULL;
2861590Srgrimes}
2871590Srgrimes
2881590Srgrimesstatic void
28996795Stjrodformat(const char *fmt)
2901590Srgrimes{
29196795Stjr	char fchar;
2921590Srgrimes
29396795Stjr	while (*fmt != '\0') {
29496795Stjr		switch ((fchar = *fmt++)) {
29596795Stjr		case 'a':
29696795Stjr			odadd("16/1 \"%3_u \" \"\\n\"");
29796795Stjr			break;
29896795Stjr		case 'c':
29996795Stjr			odadd("16/1 \"%3_c \" \"\\n\"");
30096795Stjr			break;
30196795Stjr		case 'o': case 'u': case 'd': case 'x':
30296795Stjr			fmt = odformatint(fchar, fmt);
30396795Stjr			break;
30496795Stjr		case 'f':
30596795Stjr			fmt = odformatfp(fchar, fmt);
30696795Stjr			break;
30796795Stjr		default:
30896795Stjr			errx(1, "%c: unrecognised format character", fchar);
30996795Stjr		}
31096795Stjr	}
3111590Srgrimes}
31296795Stjr
31396795Stjrstatic const char *
31496795Stjrodformatfp(char fchar __unused, const char *fmt)
31596795Stjr{
31696795Stjr	size_t isize;
31796795Stjr	int digits;
31896795Stjr	char *end, *hdfmt;
31996795Stjr
32096795Stjr	isize = sizeof(double);
32196795Stjr	switch (*fmt) {
32296795Stjr	case 'F':
32396795Stjr		isize = sizeof(float);
32496795Stjr		fmt++;
32596795Stjr		break;
32696795Stjr	case 'D':
32796795Stjr		isize = sizeof(double);
32896795Stjr		fmt++;
32996795Stjr		break;
33096795Stjr	case 'L':
33196795Stjr		isize = sizeof(long double);
33296795Stjr		fmt++;
33396795Stjr		break;
33496795Stjr	default:
33596795Stjr		if (isdigit((unsigned char)*fmt)) {
33696795Stjr			errno = 0;
33796795Stjr			isize = (size_t)strtoul(fmt, &end, 10);
33896795Stjr			if (errno != 0 || isize == 0)
33996795Stjr				errx(1, "%s: invalid size", fmt);
34096795Stjr			fmt = (const char *)end;
34196795Stjr		}
34296795Stjr	}
34396795Stjr	switch (isize) {
34496795Stjr	case sizeof(float):
34596795Stjr		digits = FLT_DIG;
34696795Stjr		break;
34796795Stjr	case sizeof(double):
34896795Stjr		digits = DBL_DIG;
34996795Stjr		break;
35096795Stjr	default:
35196795Stjr		if (isize == sizeof(long double))
35296795Stjr			digits = LDBL_DIG;
35396795Stjr		else
35496795Stjr			errx(1, "unsupported floating point size %lu",
35596795Stjr			    (u_long)isize);
35696795Stjr	}
35796795Stjr
35896795Stjr	asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"",
35996795Stjr	    16UL / (u_long)isize, (u_long)isize, digits + 8, digits);
36096795Stjr	if (hdfmt == NULL)
36196795Stjr		err(1, NULL);
36296795Stjr	odadd(hdfmt);
36396795Stjr	free(hdfmt);
36496795Stjr
36596795Stjr	return (fmt);
36696795Stjr}
36796795Stjr
36896795Stjrstatic const char *
36996795Stjrodformatint(char fchar, const char *fmt)
37096795Stjr{
37196795Stjr	unsigned long long n;
37296795Stjr	size_t isize;
37396795Stjr	int digits;
37496795Stjr	char *end, *hdfmt;
37596795Stjr
37696795Stjr	isize = sizeof(int);
37796795Stjr	switch (*fmt) {
37896795Stjr	case 'C':
37996795Stjr		isize = sizeof(char);
38096795Stjr		fmt++;
38196795Stjr		break;
38296795Stjr	case 'I':
38396795Stjr		isize = sizeof(int);
38496795Stjr		fmt++;
38596795Stjr		break;
38696795Stjr	case 'L':
38796795Stjr		isize = sizeof(long);
38896795Stjr		fmt++;
38996795Stjr		break;
39096795Stjr	case 'S':
39196795Stjr		isize = sizeof(short);
39296795Stjr		fmt++;
39396795Stjr		break;
39496795Stjr	default:
39596795Stjr		if (isdigit((unsigned char)*fmt)) {
39696795Stjr			errno = 0;
39796795Stjr			isize = (size_t)strtoul(fmt, &end, 10);
39896795Stjr			if (errno != 0 || isize == 0)
39996795Stjr				errx(1, "%s: invalid size", fmt);
40096795Stjr			if (isize != sizeof(char) && isize != sizeof(short) &&
40196795Stjr			    isize != sizeof(int) && isize != sizeof(long))
40296795Stjr				errx(1, "unsupported int size %lu",
40396795Stjr				    (u_long)isize);
40496795Stjr			fmt = (const char *)end;
40596795Stjr		}
40696795Stjr	}
40796795Stjr
40896795Stjr	/*
40996795Stjr	 * Calculate the maximum number of digits we need to
41096795Stjr	 * fit the number. Overestimate for decimal with log
41196795Stjr	 * base 8. We need one extra space for signed numbers
41296795Stjr	 * to store the sign.
41396795Stjr	 */
41496795Stjr	n = (1ULL << (8 * isize)) - 1;
41596795Stjr	digits = 0;
41696795Stjr	while (n != 0) {
41796795Stjr		digits++;
41896795Stjr		n >>= (fchar == 'x') ? 4 : 3;
41996795Stjr	}
42096795Stjr	if (fchar == 'd')
42196795Stjr		digits++;
42296798Stjr	asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"",
42396798Stjr	    16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits),
42496798Stjr	    "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar);
42596795Stjr	if (hdfmt == NULL)
42696795Stjr		err(1, NULL);
42796795Stjr	odadd(hdfmt);
42896795Stjr	free(hdfmt);
42996795Stjr
43096795Stjr	return (fmt);
43196795Stjr}
43296795Stjr
43396795Stjrstatic void
43496795Stjrodadd(const char *fmt)
43596795Stjr{
43696795Stjr	static int needpad;
43796795Stjr
43896795Stjr	if (needpad)
43996795Stjr		add("\""PADDING"\"");
44096795Stjr	add(fmt);
44196795Stjr	needpad = 1;
44296795Stjr}
443