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