xref: /openbsd-src/usr.bin/hexdump/odsyntax.c (revision 48a8138eaf620866eea17ae3a74c409afae0a361)
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 
45 int odmode;
46 
47 static void		 odadd(const char *);
48 static void		 odoffset(int, char ***);
49 static __dead void	 oldusage(void);
50 static void		 posixtypes(char *);
51 
52 /*
53  * formats used for -t
54  */
55 static 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 
79 void
oldsyntax(int argc,char *** argvp)80 oldsyntax(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  */
200 static void
posixtypes(char * type_string)201 posixtypes(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 
296 static __dead void
oldusage(void)297 oldusage(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 
306 static void
odoffset(int argc,char *** argvp)307 odoffset(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 
405 static void
odadd(const char * format)406 odadd(const char *format)
407 {
408 	static int needpad;
409 
410 	if (needpad)
411 		add("\""PADDING"\"");
412 	add(format);
413 	needpad = 1;
414 }
415