xref: /netbsd-src/usr.bin/hexdump/odsyntax.c (revision e45d81596048059cf412e70f3b6cfdf4cc643513)
1*e45d8159Schristos /*	$NetBSD: odsyntax.c,v 1.28 2010/11/27 20:46:38 christos Exp $	*/
29d225a17Stls 
361f28255Scgd /*-
473973984Smrg  * Copyright (c) 1990, 1993
573973984Smrg  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
32171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
33171d6532Slukem #include "nbtool_config.h"
34171d6532Slukem #endif
35171d6532Slukem 
36c6810a02Slukem #include <sys/cdefs.h>
37171d6532Slukem #if !defined(lint)
38769693f9Smikel #if 0
3973973984Smrg static char sccsid[] = "@(#)odsyntax.c	8.2 (Berkeley) 5/4/95";
40769693f9Smikel #else
41*e45d8159Schristos __RCSID("$NetBSD: odsyntax.c,v 1.28 2010/11/27 20:46:38 christos Exp $");
42769693f9Smikel #endif
4361f28255Scgd #endif /* not lint */
4461f28255Scgd 
4561f28255Scgd #include <sys/types.h>
4673973984Smrg 
47769693f9Smikel #include <ctype.h>
48c6810a02Slukem #include <err.h>
4961f28255Scgd #include <stdio.h>
50769693f9Smikel #include <stdlib.h>
5173973984Smrg #include <unistd.h>
52cdab3a7aSchristos #include <util.h>
5373973984Smrg 
5461f28255Scgd #include "hexdump.h"
5561f28255Scgd 
56316dc7a8Sdrochner #define PADDING "         "
57316dc7a8Sdrochner 
5889e07ef7Sbjh21 struct odformat {
5989e07ef7Sbjh21 	char type;
6089e07ef7Sbjh21 	int nbytes;
6189e07ef7Sbjh21 	char const *format;
6289e07ef7Sbjh21 	int minwidth;
6389e07ef7Sbjh21 };
6489e07ef7Sbjh21 
6589e07ef7Sbjh21 struct odaddrformat {
6689e07ef7Sbjh21 	char type;
6789e07ef7Sbjh21 	char const *format1;
6889e07ef7Sbjh21 	char const *format2;
6989e07ef7Sbjh21 };
7089e07ef7Sbjh21 
71ec10ab01Sdrochner int odmode;
7261f28255Scgd 
73d310ebb1Sperry static void odoffset(int, char ***);
74d310ebb1Sperry static void posixtypes(char const *);
7574f15d98Schristos 
76769693f9Smikel void
odsyntax(int argc,char *** argvp)77ec10ab01Sdrochner odsyntax(int argc, char ***argvp)
7861f28255Scgd {
79316dc7a8Sdrochner 	static char empty[] = "", padding[] = PADDING;
8061f28255Scgd 	int ch;
81a4b50871Sbjh21 	char *p, **argv;
8261f28255Scgd 
83316dc7a8Sdrochner #define TYPE_OFFSET 7
84316dc7a8Sdrochner 	add("\"%07.7_Ao\n\"");
85316dc7a8Sdrochner 	add("\"%07.7_ao  \"");
86316dc7a8Sdrochner 
87ec10ab01Sdrochner 	odmode = 1;
8861f28255Scgd 	argv = *argvp;
8994f69635Sbjh21 	while ((ch = getopt(argc, argv,
90ec10ab01Sdrochner 	    "A:aBbcDdeFfHhIij:LlN:Oot:vXx")) != -1)
9161f28255Scgd 		switch (ch) {
92316dc7a8Sdrochner 		case 'A':
93316dc7a8Sdrochner 			switch (*optarg) {
94316dc7a8Sdrochner 			case 'd': case 'o': case 'x':
95316dc7a8Sdrochner 				fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
96316dc7a8Sdrochner 				fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
97316dc7a8Sdrochner 					*optarg;
98316dc7a8Sdrochner 				break;
99316dc7a8Sdrochner 			case 'n':
100316dc7a8Sdrochner 				fshead->nextfu->fmt = empty;
101316dc7a8Sdrochner 				fshead->nextfs->nextfu->fmt = padding;
102316dc7a8Sdrochner 				break;
103316dc7a8Sdrochner 			default:
104316dc7a8Sdrochner 				errx(1, "%s: invalid address base", optarg);
105316dc7a8Sdrochner 			}
106316dc7a8Sdrochner 			break;
10761f28255Scgd 		case 'a':
10889e07ef7Sbjh21 			posixtypes("a");
10961f28255Scgd 			break;
11061f28255Scgd 		case 'B':
11161f28255Scgd 		case 'o':
11289e07ef7Sbjh21 			posixtypes("o2");
11361f28255Scgd 			break;
11461f28255Scgd 		case 'b':
11589e07ef7Sbjh21 			posixtypes("o1");
11661f28255Scgd 			break;
11761f28255Scgd 		case 'c':
11889e07ef7Sbjh21 			posixtypes("c");
11961f28255Scgd 			break;
12061f28255Scgd 		case 'd':
12189e07ef7Sbjh21 			posixtypes("u2");
12261f28255Scgd 			break;
12361f28255Scgd 		case 'D':
12489e07ef7Sbjh21 			posixtypes("u4");
12561f28255Scgd 			break;
12661f28255Scgd 		case 'e':		/* undocumented in od */
12761f28255Scgd 		case 'F':
12889e07ef7Sbjh21 			posixtypes("f8");
12961f28255Scgd 			break;
13061f28255Scgd 		case 'f':
13189e07ef7Sbjh21 			posixtypes("f4");
13261f28255Scgd 			break;
13361f28255Scgd 		case 'H':
13461f28255Scgd 		case 'X':
13589e07ef7Sbjh21 			posixtypes("x4");
13661f28255Scgd 			break;
13761f28255Scgd 		case 'h':
13861f28255Scgd 		case 'x':
13989e07ef7Sbjh21 			posixtypes("x2");
14061f28255Scgd 			break;
14161f28255Scgd 		case 'I':
14261f28255Scgd 		case 'L':
14361f28255Scgd 		case 'l':
14489e07ef7Sbjh21 			posixtypes("d4");
14561f28255Scgd 			break;
14661f28255Scgd 		case 'i':
14789e07ef7Sbjh21 			posixtypes("d2");
14861f28255Scgd 			break;
149a4b50871Sbjh21 		case 'j':
150a4b50871Sbjh21 			if ((skip = strtol(optarg, &p, 0)) < 0)
151a4b50871Sbjh21 				errx(1, "%s: bad skip value", optarg);
152a4b50871Sbjh21 			switch(*p) {
153a4b50871Sbjh21 			case 'b':
154a4b50871Sbjh21 				skip *= 512;
155a4b50871Sbjh21 				break;
156a4b50871Sbjh21 			case 'k':
157a4b50871Sbjh21 				skip *= 1024;
158a4b50871Sbjh21 				break;
159a4b50871Sbjh21 			case 'm':
160a4b50871Sbjh21 				skip *= 1048576;
161a4b50871Sbjh21 				break;
162a4b50871Sbjh21 			}
163a4b50871Sbjh21 			break;
16494f69635Sbjh21 		case 'N':
16594f69635Sbjh21 			if ((length = atoi(optarg)) < 0)
16694f69635Sbjh21 				errx(1, "%s: bad length value", optarg);
16794f69635Sbjh21 			break;
16861f28255Scgd 		case 'O':
16989e07ef7Sbjh21 			posixtypes("o4");
17061f28255Scgd 			break;
17174f15d98Schristos 		case 't':
1720a1ce99fSbjh21 			posixtypes(optarg);
17374f15d98Schristos 			break;
17461f28255Scgd 		case 'v':
17561f28255Scgd 			vflag = ALL;
17661f28255Scgd 			break;
17761f28255Scgd 		case '?':
17861f28255Scgd 		default:
179*e45d8159Schristos 			usage();
18061f28255Scgd 		}
18161f28255Scgd 
182316dc7a8Sdrochner 	if (fshead->nextfs->nextfs == NULL)
183316dc7a8Sdrochner 		posixtypes("oS");
18461f28255Scgd 
18561f28255Scgd 	argc -= optind;
18661f28255Scgd 	*argvp += optind;
18761f28255Scgd 
18873973984Smrg 	if (argc)
18961f28255Scgd 		odoffset(argc, argvp);
19061f28255Scgd }
19161f28255Scgd 
19289e07ef7Sbjh21 /* formats used for -t */
19389e07ef7Sbjh21 
19489e07ef7Sbjh21 static const struct odformat odftab[] = {
19589e07ef7Sbjh21 	{ 'a', 1, "%3_u",  4 },
19689e07ef7Sbjh21 	{ 'c', 1, "%3_c",  4 },
19789e07ef7Sbjh21 	{ 'd', 1, "%4d",   5 },
19889e07ef7Sbjh21 	{ 'd', 2, "%6d",   6 },
19989e07ef7Sbjh21 	{ 'd', 4, "%11d", 11 },
20089e07ef7Sbjh21 	{ 'd', 8, "%20d", 20 },
20189e07ef7Sbjh21 	{ 'o', 1, "%03o",  4 },
20289e07ef7Sbjh21 	{ 'o', 2, "%06o",  7 },
20389e07ef7Sbjh21 	{ 'o', 4, "%011o", 12 },
20489e07ef7Sbjh21 	{ 'o', 8, "%022o", 23 },
20589e07ef7Sbjh21 	{ 'u', 1, "%03u" , 4 },
20689e07ef7Sbjh21 	{ 'u', 2, "%05u" , 6 },
20789e07ef7Sbjh21 	{ 'u', 4, "%010u", 11 },
20889e07ef7Sbjh21 	{ 'u', 8, "%020u", 21 },
20989e07ef7Sbjh21 	{ 'x', 1, "%02x",  3 },
21089e07ef7Sbjh21 	{ 'x', 2, "%04x",  5 },
21189e07ef7Sbjh21 	{ 'x', 4, "%08x",  9 },
21289e07ef7Sbjh21 	{ 'x', 8, "%016x", 17 },
21389e07ef7Sbjh21 	{ 'f', 4, "%14.7e",  15 },
21489e07ef7Sbjh21 	{ 'f', 8, "%21.14e", 22 },
21589e07ef7Sbjh21 	{ 0, 0, NULL, 0 }
21689e07ef7Sbjh21 };
21789e07ef7Sbjh21 
2180a1ce99fSbjh21 /*
2190a1ce99fSbjh21  * Interpret a POSIX-style -t argument.
2200a1ce99fSbjh21  */
2210a1ce99fSbjh21 static void
posixtypes(char const * type_string)222d310ebb1Sperry posixtypes(char const *type_string)
2230a1ce99fSbjh21 {
224a3b235bbSlukem 	int nbytes = 0;
22589e07ef7Sbjh21 	char *fmt, type, *tmp;
22689e07ef7Sbjh21 	struct odformat const *odf;
2270a1ce99fSbjh21 
2280a1ce99fSbjh21 	while (*type_string) {
22989e07ef7Sbjh21 		switch ((type = *type_string++)) {
2300a1ce99fSbjh21 		case 'a':
2310a1ce99fSbjh21 		case 'c':
23289e07ef7Sbjh21 			nbytes = 1;
2330a1ce99fSbjh21 			break;
2340a1ce99fSbjh21 		case 'f':
235b23af931Sdsl 			if (isupper((unsigned char)*type_string)) {
23689e07ef7Sbjh21 				switch(*type_string) {
23789e07ef7Sbjh21 				case 'F':
23889e07ef7Sbjh21 					nbytes = sizeof(float);
23989e07ef7Sbjh21 					break;
24089e07ef7Sbjh21 				case 'D':
24189e07ef7Sbjh21 					nbytes = sizeof(double);
24289e07ef7Sbjh21 					break;
24389e07ef7Sbjh21 				case 'L':
24489e07ef7Sbjh21 					nbytes = sizeof(long double);
24589e07ef7Sbjh21 					break;
24689e07ef7Sbjh21 				default:
24789e07ef7Sbjh21 					warnx("Bad type-size qualifier '%c'",
24889e07ef7Sbjh21 					    *type_string);
249*e45d8159Schristos 					usage();
25089e07ef7Sbjh21 				}
25189e07ef7Sbjh21 				type_string++;
252b23af931Sdsl 			} else if (isdigit((unsigned char)*type_string)) {
25389e07ef7Sbjh21 				nbytes = strtol(type_string, &tmp, 10);
25489e07ef7Sbjh21 				type_string = tmp;
25589e07ef7Sbjh21 			} else
25689e07ef7Sbjh21 				nbytes = 8;
2570a1ce99fSbjh21 			break;
2580a1ce99fSbjh21 		case 'd':
2590a1ce99fSbjh21 		case 'o':
2600a1ce99fSbjh21 		case 'u':
2610a1ce99fSbjh21 		case 'x':
262b23af931Sdsl 			if (isupper((unsigned char)*type_string)) {
2630a1ce99fSbjh21 				switch(*type_string) {
2640a1ce99fSbjh21 				case 'C':
26541a2a8aaSbjh21 					nbytes = sizeof(char);
2660a1ce99fSbjh21 					break;
2670a1ce99fSbjh21 				case 'S':
26841a2a8aaSbjh21 					nbytes = sizeof(short);
2690a1ce99fSbjh21 					break;
2700a1ce99fSbjh21 				case 'I':
27141a2a8aaSbjh21 					nbytes = sizeof(int);
2720a1ce99fSbjh21 					break;
2730a1ce99fSbjh21 				case 'L':
27441a2a8aaSbjh21 					nbytes = sizeof(long);
2750a1ce99fSbjh21 					break;
2760a1ce99fSbjh21 				default:
2770a1ce99fSbjh21 					warnx("Bad type-size qualifier '%c'",
2780a1ce99fSbjh21 					    *type_string);
279*e45d8159Schristos 					usage();
2800a1ce99fSbjh21 				}
2810a1ce99fSbjh21 				type_string++;
282b23af931Sdsl 			} else if (isdigit((unsigned char)*type_string)) {
28389e07ef7Sbjh21 				nbytes = strtol(type_string, &tmp, 10);
28489e07ef7Sbjh21 				type_string = tmp;
28589e07ef7Sbjh21 			} else
28689e07ef7Sbjh21 				nbytes = 4;
2870a1ce99fSbjh21 			break;
2880a1ce99fSbjh21 		default:
289*e45d8159Schristos 			usage();
2900a1ce99fSbjh21 		}
29189e07ef7Sbjh21 		for (odf = odftab; odf->type != 0; odf++)
29289e07ef7Sbjh21 			if (odf->type == type && odf->nbytes == nbytes)
29389e07ef7Sbjh21 				break;
29489e07ef7Sbjh21 		if (odf->type == 0)
29589e07ef7Sbjh21 			errx(1, "%c%d: format not supported", type, nbytes);
296cdab3a7aSchristos 		(void)easprintf(&fmt, "%d/%d  \"%*s%s \" \"\\n\"",
29789e07ef7Sbjh21 		    16 / nbytes, nbytes,
29889e07ef7Sbjh21 		    4 * nbytes - odf->minwidth, "", odf->format);
29989e07ef7Sbjh21 		add(fmt);
3000a1ce99fSbjh21 	}
3010a1ce99fSbjh21 }
3020a1ce99fSbjh21 
30373973984Smrg static void
odoffset(int argc,char *** argvp)304d310ebb1Sperry odoffset(int argc, char ***argvp)
30561f28255Scgd {
306c6810a02Slukem 	char *num, *p;
30761f28255Scgd 	int base;
30861f28255Scgd 	char *end;
30961f28255Scgd 
31061f28255Scgd 	/*
31161f28255Scgd 	 * The offset syntax of od(1) was genuinely bizarre.  First, if
31261f28255Scgd 	 * it started with a plus it had to be an offset.  Otherwise, if
31361f28255Scgd 	 * there were at least two arguments, a number or lower-case 'x'
31461f28255Scgd 	 * followed by a number makes it an offset.  By default it was
31561f28255Scgd 	 * octal; if it started with 'x' or '0x' it was hex.  If it ended
31661f28255Scgd 	 * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
31761f28255Scgd 	 * multiplied the number by 512 or 1024 byte units.  There was
31861f28255Scgd 	 * no way to assign a block count to a hex offset.
31961f28255Scgd 	 *
320769693f9Smikel 	 * We assume it's a file if the offset is bad.
32161f28255Scgd 	 */
32273973984Smrg 	p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
32321f39729Smycroft 	if (!p)
32421f39729Smycroft 		return;
32573973984Smrg 
32661f28255Scgd 	if (*p != '+' && (argc < 2 ||
3279794a7e0Schristos 	    (!isdigit((unsigned char)p[0]) &&
3289794a7e0Schristos 	    (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
32961f28255Scgd 		return;
33061f28255Scgd 
33161f28255Scgd 	base = 0;
33261f28255Scgd 	/*
33361f28255Scgd 	 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
33461f28255Scgd 	 * set base.
33561f28255Scgd 	 */
33661f28255Scgd 	if (p[0] == '+')
33761f28255Scgd 		++p;
3389794a7e0Schristos 	if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
33961f28255Scgd 		++p;
34061f28255Scgd 		base = 16;
34161f28255Scgd 	} else if (p[0] == '0' && p[1] == 'x') {
34261f28255Scgd 		p += 2;
34361f28255Scgd 		base = 16;
34461f28255Scgd 	}
34561f28255Scgd 
34661f28255Scgd 	/* skip over the number */
34761f28255Scgd 	if (base == 16)
3489794a7e0Schristos 		for (num = p; isxdigit((unsigned char)*p); ++p);
34961f28255Scgd 	else
3509794a7e0Schristos 		for (num = p; isdigit((unsigned char)*p); ++p);
35161f28255Scgd 
35261f28255Scgd 	/* check for no number */
35361f28255Scgd 	if (num == p)
35461f28255Scgd 		return;
35561f28255Scgd 
35661f28255Scgd 	/* if terminates with a '.', base is decimal */
35761f28255Scgd 	if (*p == '.') {
35861f28255Scgd 		if (base)
35961f28255Scgd 			return;
36061f28255Scgd 		base = 10;
36161f28255Scgd 	}
36261f28255Scgd 
36361f28255Scgd 	skip = strtol(num, &end, base ? base : 8);
36461f28255Scgd 
36561f28255Scgd 	/* if end isn't the same as p, we got a non-octal digit */
36673973984Smrg 	if (end != p) {
36761f28255Scgd 		skip = 0;
36873973984Smrg 		return;
36973973984Smrg 	}
37073973984Smrg 
371f670fa10Sross 	if (*p) {
37273973984Smrg 		if (*p == 'B') {
37361f28255Scgd 			skip *= 1024;
37461f28255Scgd 			++p;
37573973984Smrg 		} else if (*p == 'b') {
37673973984Smrg 			skip *= 512;
37773973984Smrg 			++p;
37861f28255Scgd 		}
379f670fa10Sross 	}
38073973984Smrg 	if (*p) {
38161f28255Scgd 		skip = 0;
38273973984Smrg 		return;
38373973984Smrg 	}
38461f28255Scgd 	/*
38573973984Smrg 	 * If the offset uses a non-octal base, the base of the offset
38673973984Smrg 	 * is changed as well.  This isn't pretty, but it's easy.
38761f28255Scgd 	 */
38861f28255Scgd 	if (base == 16) {
38961f28255Scgd 		fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
39061f28255Scgd 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
39161f28255Scgd 	} else if (base == 10) {
39261f28255Scgd 		fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
39361f28255Scgd 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
39461f28255Scgd 	}
39573973984Smrg 
39673973984Smrg 	/* Terminate file list. */
39773973984Smrg 	(*argvp)[1] = NULL;
39861f28255Scgd }
399