xref: /openbsd/usr.bin/hexdump/odsyntax.c (revision db3296cf)
1 /*	$OpenBSD: odsyntax.c,v 1.13 2003/06/12 20:58:09 deraadt 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 #ifndef lint
34 /*static char sccsid[] = "from: @(#)odsyntax.c	5.4 (Berkeley) 3/8/91";*/
35 static char rcsid[] = "$OpenBSD: odsyntax.c,v 1.13 2003/06/12 20:58:09 deraadt Exp $";
36 #endif /* not lint */
37 
38 #include <sys/types.h>
39 
40 #include <ctype.h>
41 #include <err.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 
46 #include "hexdump.h"
47 
48 int deprecated;
49 
50 static void odoffset(int, char ***);
51 static void posixtypes(char *);
52 static void odprecede(void);
53 
54 
55 /*
56  * formats used for -t
57  */
58 static const char *fmt[4][4] = {
59 	{
60 		"16/1 \"%3d \" \"\\n\"",
61 		"8/2  \"  %05d \" \"\\n\"",
62 		"4/4  \"     %010d \" \"\\n\"",
63 		"2/8  \" %019d \" \"\\n\""
64 	}, {
65 		"16/1 \"%03o \" \"\\n\"",
66 		"8/2  \" %06o \" \"\\n\"",
67 		"4/4  \"    %011o\" \"\\n\"",
68 		"2/8  \" %022o \" \"\\n\""
69 	}, {
70 		"16/1 \"%03u \" \"\\n\"",
71 		"8/2  \"  %05u \" \"\\n\"",
72 		"4/4  \"     %010u \" \"\\n\"",
73 		"2/8  \" %020u \" \"\\n\""
74 	}, {
75 		"16/1 \" %02x \" \"\\n\"",
76 		"8/2  \"   %04x \" \"\\n\"",
77 		"4/4  \"       %08x \" \"\\n\"",
78 		"2/8  \" %16x \" \"\\n\""
79 	}
80 };
81 
82 void
83 oldsyntax(int argc, char ***argvp)
84 {
85 	int ch;
86 	char *p, **argv;
87 
88 	deprecated = 1;
89 	argv = *argvp;
90 	while ((ch = getopt(argc, argv,
91 	    "aBbcDdeFfHhIij:LlN:OoPpst:wvXx")) != -1)
92 		switch (ch) {
93 		case 'a':
94 			odprecede();
95 			add("16/1 \"%3_u \" \"\\n\"");
96 			break;
97 		case 'B':
98 		case 'o':
99 			odprecede();
100 			add("8/2 \" %06o \" \"\\n\"");
101 			break;
102 		case 'b':
103 			odprecede();
104 			add("16/1 \"%03o \" \"\\n\"");
105 			break;
106 		case 'c':
107 			odprecede();
108 			add("16/1 \"%3_c \" \"\\n\"");
109 			break;
110 		case 'd':
111 			odprecede();
112 			add("8/2 \"  %05u \" \"\\n\"");
113 			break;
114 		case 'D':
115 			odprecede();
116 			add("4/4 \"     %010u \" \"\\n\"");
117 			break;
118 		case 'e':		/* undocumented in od */
119 		case 'F':
120 			odprecede();
121 			add("2/8 \"          %21.14e \" \"\\n\"");
122 			break;
123 
124 		case 'f':
125 			odprecede();
126 			add("4/4 \" %14.7e \" \"\\n\"");
127 			break;
128 		case 'H':
129 		case 'X':
130 			odprecede();
131 			add("4/4 \"       %08x \" \"\\n\"");
132 			break;
133 		case 'h':
134 		case 'x':
135 			odprecede();
136 			add("8/2 \"   %04x \" \"\\n\"");
137 			break;
138 		case 'I':
139 		case 'L':
140 		case 'l':
141 			odprecede();
142 			add("4/4 \"    %11d \" \"\\n\"");
143 			break;
144 		case 'i':
145 			odprecede();
146 			add("8/2 \" %6d \" \"\\n\"");
147 			break;
148 		case 'j':
149 			if ((skip = strtol(optarg, &p, 0)) < 0)
150 				errx(1, "%s: bad skip value", optarg);
151 			switch(*p) {
152 			case 'b':
153 				skip *= 512;
154 				break;
155 			case 'k':
156 				skip *= 1024;
157 				break;
158 			case 'm':
159 				skip *= 1048576;
160 				break;
161 			}
162 			break;
163 		case 'N':
164 			if ((length = atoi(optarg)) < 0)
165 				errx(1, "%s: bad length value", optarg);
166 			break;
167 		case 'O':
168 			odprecede();
169 			add("4/4 \"    %011o \" \"\\n\"");
170 			break;
171 		case 't':
172 			posixtypes(optarg);
173 			break;
174 		case 'v':
175 			vflag = ALL;
176 			break;
177 		case 'P':
178 		case 'p':
179 		case 's':
180 		case 'w':
181 		case '?':
182 		default:
183 			warnx("od(1) has been deprecated for hexdump(1).");
184 			if (ch != '?')
185 				warnx(
186 "hexdump(1) compatibility doesn't support the -%c option%s\n",
187 				    ch, ch == 's' ? "; see strings(1)." : ".");
188 			oldusage();
189 		}
190 
191 	if (!fshead) {
192 		add("\"%07.7_Ao\n\"");
193 		add("\"%07.7_ao  \" 8/2 \"%06o \" \"\\n\"");
194 	}
195 
196 	argc -= optind;
197 	*argvp += optind;
198 
199 	if (argc)
200 		odoffset(argc, argvp);
201 }
202 
203 /*
204  * Interpret a POSIX-style -t argument.
205  */
206 static void
207 posixtypes(char *type_string)
208 {
209 	int x, y, nbytes;
210 
211 	while (*type_string) {
212 		odprecede();
213 		switch (*type_string) {
214 		case 'a':
215 			type_string++;
216 			add("16/1 \"%3_u \" \"\\n\"");
217 			break;
218 		case 'c':
219 			type_string++;
220 			add("16/1 \"%3_c \" \"\\n\"");
221 			break;
222 		case 'f':
223 			type_string++;
224 			if        (*type_string == 'F' ||
225 				   *type_string == '4') {
226 				type_string++;
227 				add("4/4 \" %14.7e\" \"\\n\"");
228 			} else if (*type_string == 'L' ||
229 				   *type_string == '8') {
230 				type_string++;
231 				add("2/8 \" %16.14e\" \"\\n\"");
232 			} else if (*type_string == 'D')
233 				/* long doubles vary in size */
234 				oldusage();
235 			else
236 				add("2/8 \" %16.14e\" \"\\n\"");
237 			break;
238 		case 'd':
239 			x = 0;
240 			goto extensions;
241 		case 'o':
242 			x = 1;
243 			goto extensions;
244 		case 'u':
245 			x = 2;
246 			goto extensions;
247 		case 'x':
248 			x = 3;
249 		extensions:
250 			type_string++;
251 			y = 2;
252 			if (isupper(*type_string)) {
253 				switch(*type_string) {
254 				case 'C':
255 					nbytes = sizeof(char);
256 					break;
257 				case 'S':
258 					nbytes = sizeof(short);
259 					break;
260 				case 'I':
261 					nbytes = sizeof(int);
262 					break;
263 				case 'L':
264 					nbytes = sizeof(long);
265 					break;
266 				default:
267 					warnx("Bad type-size qualifier '%c'",
268 					    *type_string);
269 					oldusage();
270 				}
271 				type_string++;
272 			} else if (isdigit(*type_string))
273 				nbytes = strtol(type_string, &type_string, 10);
274 
275 			switch (nbytes) {
276 			case 1:
277 				y = 0;
278 				break;
279 			case 2:
280 				y = 1;
281 				break;
282 			case 4:
283 				y = 2;
284 				break;
285 			case 8:
286 				y = 3;
287 				break;
288 			default:
289 				warnx("%d-byte integer formats are not "
290 				    "supported", nbytes);
291 				oldusage();
292 			}
293 			add(fmt[x][y]);
294 			break;
295 		default:
296 			oldusage();
297 		}
298 	}
299 }
300 
301 void
302 oldusage(void)
303 {
304 	extern char *__progname;
305 	fprintf(stderr, "usage: %s [-aBbcDdeFfHhIiLlOovXx] [-j skip] "
306 			"[-N length] [-t type_string] "
307 			"[[+]offset[.][Bb]] [file ...]\n", __progname);
308 	exit(1);
309 }
310 
311 static void
312 odoffset(int argc, char ***argvp)
313 {
314 	char *num, *p;
315 	int base;
316 	char *end;
317 
318 	/*
319 	 * The offset syntax of od(1) was genuinely bizarre.  First, if
320 	 * it started with a plus it had to be an offset.  Otherwise, if
321 	 * there were at least two arguments, a number or lower-case 'x'
322 	 * followed by a number makes it an offset.  By default it was
323 	 * octal; if it started with 'x' or '0x' it was hex.  If it ended
324 	 * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
325 	 * multiplied the number by 512 or 1024 byte units.  There was
326 	 * no way to assign a block count to a hex offset.
327 	 *
328 	 * We assume it's a file if the offset is bad.
329 	 */
330 	p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
331 	if (!p)
332 		return;
333 
334 	if (*p != '+' && (argc < 2 ||
335 	    (!isdigit((unsigned char)p[0]) &&
336 	    (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
337 		return;
338 
339 	base = 0;
340 	/*
341 	 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
342 	 * set base.
343 	 */
344 	if (p[0] == '+')
345 		++p;
346 	if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
347 		++p;
348 		base = 16;
349 	} else if (p[0] == '0' && p[1] == 'x') {
350 		p += 2;
351 		base = 16;
352 	}
353 
354 	/* skip over the number */
355 	if (base == 16)
356 		for (num = p; isxdigit((unsigned char)*p); ++p);
357 	else
358 		for (num = p; isdigit((unsigned char)*p); ++p);
359 
360 	/* check for no number */
361 	if (num == p)
362 		return;
363 
364 	/* if terminates with a '.', base is decimal */
365 	if (*p == '.') {
366 		if (base)
367 			return;
368 		base = 10;
369 	}
370 
371 	skip = strtol(num, &end, base ? base : 8);
372 
373 	/* if end isn't the same as p, we got a non-octal digit */
374 	if (end != p) {
375 		skip = 0;
376 		return;
377 	}
378 
379 	if (*p) {
380 		if (*p == 'B') {
381 			skip *= 1024;
382 			++p;
383 		} else if (*p == 'b') {
384 			skip *= 512;
385 			++p;
386 		}
387 	}
388 	if (*p) {
389 		skip = 0;
390 		return;
391 	}
392 	/*
393 	 * If the offset uses a non-octal base, the base of the offset
394 	 * is changed as well.  This isn't pretty, but it's easy.
395 	 */
396 #define	TYPE_OFFSET	7
397 	if (base == 16) {
398 		fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
399 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
400 	} else if (base == 10) {
401 		fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
402 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
403 	}
404 
405 	/* Terminate file list. */
406 	(*argvp)[1] = NULL;
407 }
408 
409 static void
410 odprecede(void)
411 {
412 	static int first = 1;
413 
414 	if (first) {
415 		first = 0;
416 		add("\"%07.7_Ao\n\"");
417 		add("\"%07.7_ao  \"");
418 	} else
419 		add("\"         \"");
420 }
421