1/*	$OpenBSD: odsyntax.c,v 1.28 2017/05/30 05:58:44 tedu Exp $	*/
2/*	$NetBSD: odsyntax.c,v 1.15 2001/12/07 15:14:29 bjh21 Exp $	*/
3
4/*-
5 * Copyright (c) 1990, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34
35#include <ctype.h>
36#include <err.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40
41#include "hexdump.h"
42
43#define PADDING	"         "
44
45int odmode;
46
47static void		 odadd(const char *);
48static void		 odoffset(int, char ***);
49static __dead void	 oldusage(void);
50static void		 posixtypes(char *);
51
52/*
53 * formats used for -t
54 */
55static const char *fmt[4][4] = {
56	{
57		"16/1 \"%3d \" \"\\n\"",
58		"8/2  \"  %05d \" \"\\n\"",
59		"4/4  \"     %010d \" \"\\n\"",
60		"2/8  \" %019d \" \"\\n\""
61	}, {
62		"16/1 \"%03o \" \"\\n\"",
63		"8/2  \" %06o \" \"\\n\"",
64		"4/4  \"    %011o\" \"\\n\"",
65		"2/8  \" %022o \" \"\\n\""
66	}, {
67		"16/1 \"%03u \" \"\\n\"",
68		"8/2  \"  %05u \" \"\\n\"",
69		"4/4  \"     %010u \" \"\\n\"",
70		"2/8  \" %020u \" \"\\n\""
71	}, {
72		"16/1 \" %02x \" \"\\n\"",
73		"8/2  \"   %04x \" \"\\n\"",
74		"4/4  \"       %08x \" \"\\n\"",
75		"2/8  \" %16x \" \"\\n\""
76	}
77};
78
79void
80oldsyntax(int argc, char ***argvp)
81{
82	static char empty[] = "", padding[] = PADDING;
83	int ch;
84	char *p, **argv;
85
86#define	TYPE_OFFSET	7
87	add("\"%07.7_Ao\n\"");
88	add("\"%07.7_ao  \"");
89
90	odmode = 1;
91	argv = *argvp;
92	while ((ch = getopt(argc, argv,
93	    "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1)
94		switch (ch) {
95		case 'A':
96			switch (*optarg) {
97			case 'd': case 'o': case 'x':
98				fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
99				fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
100				    *optarg;
101				break;
102			case 'n':
103				fshead->nextfu->fmt = empty;
104				fshead->nextfs->nextfu->fmt = padding;
105				break;
106			default:
107				errx(1, "%s: invalid address base", optarg);
108			}
109			break;
110		case 'a':
111			odadd("16/1 \"%3_u \" \"\\n\"");
112			break;
113		case 'B':
114		case 'o':
115			odadd("8/2 \" %06o \" \"\\n\"");
116			break;
117		case 'b':
118			odadd("16/1 \"%03o \" \"\\n\"");
119			break;
120		case 'c':
121			odadd("16/1 \"%3_c \" \"\\n\"");
122			break;
123		case 'd':
124			odadd("8/2 \"  %05u \" \"\\n\"");
125			break;
126		case 'D':
127			odadd("4/4 \"     %010u \" \"\\n\"");
128			break;
129		case 'e':
130		case 'F':
131			odadd("2/8 \"          %21.14e \" \"\\n\"");
132			break;
133		case 'f':
134			odadd("4/4 \" %14.7e \" \"\\n\"");
135			break;
136		case 'H':
137		case 'X':
138			odadd("4/4 \"       %08x \" \"\\n\"");
139			break;
140		case 'h':
141		case 'x':
142			odadd("8/2 \"   %04x \" \"\\n\"");
143			break;
144		case 'I':
145		case 'L':
146		case 'l':
147			odadd("4/4 \"    %11d \" \"\\n\"");
148			break;
149		case 'i':
150			odadd("8/2 \" %6d \" \"\\n\"");
151			break;
152		case 'j':
153			if ((skip = strtol(optarg, &p, 0)) < 0)
154				errx(1, "%s: bad skip value", optarg);
155			switch(*p) {
156			case 'b':
157				skip *= 512;
158				break;
159			case 'k':
160				skip *= 1024;
161				break;
162			case 'm':
163				skip *= 1048576;
164				break;
165			}
166			break;
167		case 'N':
168			if ((length = atoi(optarg)) < 0)
169				errx(1, "%s: bad length value", optarg);
170			break;
171		case 'O':
172			odadd("4/4 \"    %011o \" \"\\n\"");
173			break;
174		case 's':
175			odadd("8/2 \"  %05d \" \"\\n\"");
176			break;
177		case 't':
178			posixtypes(optarg);
179			break;
180		case 'v':
181			vflag = ALL;
182			break;
183		default:
184			oldusage();
185		}
186
187	if (fshead->nextfs->nextfs == NULL)
188		odadd(" 8/2 \"%06o \" \"\\n\"");
189
190	argc -= optind;
191	*argvp += optind;
192
193	if (argc)
194		odoffset(argc, argvp);
195}
196
197/*
198 * Interpret a POSIX-style -t argument.
199 */
200static void
201posixtypes(char *type_string)
202{
203	int x, y, nbytes;
204
205	while (*type_string) {
206		switch (*type_string) {
207		case 'a':
208			type_string++;
209			odadd("16/1 \"%3_u \" \"\\n\"");
210			break;
211		case 'c':
212			type_string++;
213			odadd("16/1 \"%3_c \" \"\\n\"");
214			break;
215		case 'f':
216			type_string++;
217			if        (*type_string == 'F' ||
218				   *type_string == '4') {
219				type_string++;
220				odadd("4/4 \" %14.7e\" \"\\n\"");
221			} else if (*type_string == 'L' ||
222				   *type_string == '8') {
223				type_string++;
224				odadd("2/8 \" %16.14e\" \"\\n\"");
225			} else if (*type_string == 'D')
226				/* long doubles vary in size */
227				oldusage();
228			else
229				odadd("2/8 \" %16.14e\" \"\\n\"");
230			break;
231		case 'd':
232			x = 0;
233			goto extensions;
234		case 'o':
235			x = 1;
236			goto extensions;
237		case 'u':
238			x = 2;
239			goto extensions;
240		case 'x':
241			x = 3;
242		extensions:
243			type_string++;
244			y = 2;
245			if (isupper((unsigned char)*type_string)) {
246				switch(*type_string) {
247				case 'C':
248					nbytes = sizeof(char);
249					break;
250				case 'S':
251					nbytes = sizeof(short);
252					break;
253				case 'I':
254					nbytes = sizeof(int);
255					break;
256				case 'L':
257					nbytes = sizeof(long);
258					break;
259				default:
260					warnx("Bad type-size qualifier '%c'",
261					    *type_string);
262					oldusage();
263				}
264				type_string++;
265			} else if (isdigit((unsigned char)*type_string))
266				nbytes = strtol(type_string, &type_string, 10);
267			else
268				nbytes = 4;
269
270			switch (nbytes) {
271			case 1:
272				y = 0;
273				break;
274			case 2:
275				y = 1;
276				break;
277			case 4:
278				y = 2;
279				break;
280			case 8:
281				y = 3;
282				break;
283			default:
284				warnx("%d-byte integer formats are not "
285				    "supported", nbytes);
286				oldusage();
287			}
288			odadd(fmt[x][y]);
289			break;
290		default:
291			oldusage();
292		}
293	}
294}
295
296static __dead void
297oldusage(void)
298{
299	extern char *__progname;
300	fprintf(stderr, "usage: %s [-aBbcDdeFfHhIiLlOosvXx] [-A base] "
301	    "[-j offset] [-N length]\n"
302	    "\t[-t type_string] [file ...]\n", __progname);
303	exit(1);
304}
305
306static void
307odoffset(int argc, char ***argvp)
308{
309	char *num, *p;
310	int base;
311	char *end;
312
313	/*
314	 * The offset syntax of od(1) was genuinely bizarre.  First, if
315	 * it started with a plus it had to be an offset.  Otherwise, if
316	 * there were at least two arguments, a number or lower-case 'x'
317	 * followed by a number makes it an offset.  By default it was
318	 * octal; if it started with 'x' or '0x' it was hex.  If it ended
319	 * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
320	 * multiplied the number by 512 or 1024 byte units.  There was
321	 * no way to assign a block count to a hex offset.
322	 *
323	 * We assume it's a file if the offset is bad.
324	 */
325	p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
326	if (!p)
327		return;
328
329	if (*p != '+' && (argc < 2 ||
330	    (!isdigit((unsigned char)p[0]) &&
331	    (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
332		return;
333
334	base = 0;
335	/*
336	 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
337	 * set base.
338	 */
339	if (p[0] == '+')
340		++p;
341	if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
342		++p;
343		base = 16;
344	} else if (p[0] == '0' && p[1] == 'x') {
345		p += 2;
346		base = 16;
347	}
348
349	/* skip over the number */
350	if (base == 16)
351		for (num = p; isxdigit((unsigned char)*p); ++p);
352	else
353		for (num = p; isdigit((unsigned char)*p); ++p);
354
355	/* check for no number */
356	if (num == p)
357		return;
358
359	/* if terminates with a '.', base is decimal */
360	if (*p == '.') {
361		if (base)
362			return;
363		base = 10;
364	}
365
366	skip = strtol(num, &end, base ? base : 8);
367
368	/* if end isn't the same as p, we got a non-octal digit */
369	if (end != p) {
370		skip = 0;
371		return;
372	}
373
374	if (*p == '.')
375		++p;
376	if (*p) {
377		if (*p == 'B') {
378			skip *= 1024;
379			++p;
380		} else if (*p == 'b') {
381			skip *= 512;
382			++p;
383		}
384	}
385	if (*p) {
386		skip = 0;
387		return;
388	}
389	/*
390	 * If the offset uses a non-octal base, the base of the offset
391	 * is changed as well.  This isn't pretty, but it's easy.
392	 */
393	if (base == 16) {
394		fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
395		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
396	} else if (base == 10) {
397		fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
398		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
399	}
400
401	/* Terminate file list. */
402	(*argvp)[argc > 1] = NULL;
403}
404
405static void
406odadd(const char *format)
407{
408	static int needpad;
409
410	if (needpad)
411		add("\""PADDING"\"");
412	add(format);
413	needpad = 1;
414}
415