xref: /openbsd/usr.bin/hexdump/odsyntax.c (revision 3d8817e4)
1 /*	$OpenBSD: odsyntax.c,v 1.21 2010/10/08 14:26:12 sobrado 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 deprecated;
46 
47 static void odoffset(int, char ***);
48 static void posixtypes(char *);
49 static void odadd(const char *);
50 
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
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 	deprecated = 1;
91 	argv = *argvp;
92 	while ((ch = getopt(argc, argv,
93 	    "A:aBbcDdeFfHhIij:LlN:OoPpst:wvXx")) != -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 't':
175 			posixtypes(optarg);
176 			break;
177 		case 'v':
178 			vflag = ALL;
179 			break;
180 		case 'P':
181 		case 'p':
182 		case 's':
183 		case 'w':
184 		case '?':
185 		default:
186 			warnx("od(1) has been deprecated for hexdump(1).");
187 			if (ch != '?')
188 				warnx(
189 				    "hexdump(1) compatibility doesn't"
190 				    " support the -%c option%s",
191 				    ch, ch == 's' ? "; see strings(1)." : ".");
192 			oldusage();
193 		}
194 
195 	if (fshead->nextfs->nextfs == NULL)
196 		odadd(" 8/2 \"%06o \" \"\\n\"");
197 
198 	argc -= optind;
199 	*argvp += optind;
200 
201 	if (argc)
202 		odoffset(argc, argvp);
203 }
204 
205 /*
206  * Interpret a POSIX-style -t argument.
207  */
208 static void
209 posixtypes(char *type_string)
210 {
211 	int x, y, nbytes;
212 
213 	while (*type_string) {
214 		switch (*type_string) {
215 		case 'a':
216 			type_string++;
217 			odadd("16/1 \"%3_u \" \"\\n\"");
218 			break;
219 		case 'c':
220 			type_string++;
221 			odadd("16/1 \"%3_c \" \"\\n\"");
222 			break;
223 		case 'f':
224 			type_string++;
225 			if        (*type_string == 'F' ||
226 				   *type_string == '4') {
227 				type_string++;
228 				odadd("4/4 \" %14.7e\" \"\\n\"");
229 			} else if (*type_string == 'L' ||
230 				   *type_string == '8') {
231 				type_string++;
232 				odadd("2/8 \" %16.14e\" \"\\n\"");
233 			} else if (*type_string == 'D')
234 				/* long doubles vary in size */
235 				oldusage();
236 			else
237 				odadd("2/8 \" %16.14e\" \"\\n\"");
238 			break;
239 		case 'd':
240 			x = 0;
241 			goto extensions;
242 		case 'o':
243 			x = 1;
244 			goto extensions;
245 		case 'u':
246 			x = 2;
247 			goto extensions;
248 		case 'x':
249 			x = 3;
250 		extensions:
251 			type_string++;
252 			y = 2;
253 			if (isupper(*type_string)) {
254 				switch(*type_string) {
255 				case 'C':
256 					nbytes = sizeof(char);
257 					break;
258 				case 'S':
259 					nbytes = sizeof(short);
260 					break;
261 				case 'I':
262 					nbytes = sizeof(int);
263 					break;
264 				case 'L':
265 					nbytes = sizeof(long);
266 					break;
267 				default:
268 					warnx("Bad type-size qualifier '%c'",
269 					    *type_string);
270 					oldusage();
271 				}
272 				type_string++;
273 			} else if (isdigit(*type_string))
274 				nbytes = strtol(type_string, &type_string, 10);
275 			else
276 				nbytes = 4;
277 
278 			switch (nbytes) {
279 			case 1:
280 				y = 0;
281 				break;
282 			case 2:
283 				y = 1;
284 				break;
285 			case 4:
286 				y = 2;
287 				break;
288 			case 8:
289 				y = 3;
290 				break;
291 			default:
292 				warnx("%d-byte integer formats are not "
293 				    "supported", nbytes);
294 				oldusage();
295 			}
296 			odadd(fmt[x][y]);
297 			break;
298 		default:
299 			oldusage();
300 		}
301 	}
302 }
303 
304 void
305 oldusage(void)
306 {
307 	extern char *__progname;
308 	fprintf(stderr, "usage: %s [-aBbcDdeFfHhIiLlOovXx] [-A base] "
309 	    "[-j offset] [-N length]\n"
310 	    "\t[-t type_string] [[+]offset[.][Bb]] [file ...]\n", __progname);
311 	exit(1);
312 }
313 
314 static void
315 odoffset(int argc, char ***argvp)
316 {
317 	char *num, *p;
318 	int base;
319 	char *end;
320 
321 	/*
322 	 * The offset syntax of od(1) was genuinely bizarre.  First, if
323 	 * it started with a plus it had to be an offset.  Otherwise, if
324 	 * there were at least two arguments, a number or lower-case 'x'
325 	 * followed by a number makes it an offset.  By default it was
326 	 * octal; if it started with 'x' or '0x' it was hex.  If it ended
327 	 * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
328 	 * multiplied the number by 512 or 1024 byte units.  There was
329 	 * no way to assign a block count to a hex offset.
330 	 *
331 	 * We assume it's a file if the offset is bad.
332 	 */
333 	p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
334 	if (!p)
335 		return;
336 
337 	if (*p != '+' && (argc < 2 ||
338 	    (!isdigit((unsigned char)p[0]) &&
339 	    (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
340 		return;
341 
342 	base = 0;
343 	/*
344 	 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
345 	 * set base.
346 	 */
347 	if (p[0] == '+')
348 		++p;
349 	if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
350 		++p;
351 		base = 16;
352 	} else if (p[0] == '0' && p[1] == 'x') {
353 		p += 2;
354 		base = 16;
355 	}
356 
357 	/* skip over the number */
358 	if (base == 16)
359 		for (num = p; isxdigit((unsigned char)*p); ++p);
360 	else
361 		for (num = p; isdigit((unsigned char)*p); ++p);
362 
363 	/* check for no number */
364 	if (num == p)
365 		return;
366 
367 	/* if terminates with a '.', base is decimal */
368 	if (*p == '.') {
369 		if (base)
370 			return;
371 		base = 10;
372 	}
373 
374 	skip = strtol(num, &end, base ? base : 8);
375 
376 	/* if end isn't the same as p, we got a non-octal digit */
377 	if (end != p) {
378 		skip = 0;
379 		return;
380 	}
381 
382 	if (*p) {
383 		if (*p == 'B') {
384 			skip *= 1024;
385 			++p;
386 		} else if (*p == 'b') {
387 			skip *= 512;
388 			++p;
389 		}
390 	}
391 	if (*p) {
392 		skip = 0;
393 		return;
394 	}
395 	/*
396 	 * If the offset uses a non-octal base, the base of the offset
397 	 * is changed as well.  This isn't pretty, but it's easy.
398 	 */
399 	if (base == 16) {
400 		fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
401 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
402 	} else if (base == 10) {
403 		fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
404 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
405 	}
406 
407 	/* Terminate file list. */
408 	(*argvp)[1] = NULL;
409 }
410 
411 static void
412 odadd(const char *fmt)
413 {
414 	static int needpad;
415 
416 	if (needpad)
417 		add("\""PADDING"\"");
418 	add(fmt);
419 	needpad = 1;
420 }
421