xref: /openbsd-src/usr.bin/hexdump/odsyntax.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*	$OpenBSD: odsyntax.c,v 1.16 2007/02/06 20:55:13 jmc 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.16 2007/02/06 20:55:13 jmc 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':
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"
187 				    " support the -%c option%s",
188 				    ch, ch == 's' ? "; see strings(1)." : ".");
189 			oldusage();
190 		}
191 
192 	if (!fshead) {
193 		add("\"%07.7_Ao\n\"");
194 		add("\"%07.7_ao  \" 8/2 \"%06o \" \"\\n\"");
195 	}
196 
197 	argc -= optind;
198 	*argvp += optind;
199 
200 	if (argc)
201 		odoffset(argc, argvp);
202 }
203 
204 /*
205  * Interpret a POSIX-style -t argument.
206  */
207 static void
208 posixtypes(char *type_string)
209 {
210 	int x, y, nbytes;
211 
212 	while (*type_string) {
213 		odprecede();
214 		switch (*type_string) {
215 		case 'a':
216 			type_string++;
217 			add("16/1 \"%3_u \" \"\\n\"");
218 			break;
219 		case 'c':
220 			type_string++;
221 			add("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 				add("4/4 \" %14.7e\" \"\\n\"");
229 			} else if (*type_string == 'L' ||
230 				   *type_string == '8') {
231 				type_string++;
232 				add("2/8 \" %16.14e\" \"\\n\"");
233 			} else if (*type_string == 'D')
234 				/* long doubles vary in size */
235 				oldusage();
236 			else
237 				add("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 
276 			switch (nbytes) {
277 			case 1:
278 				y = 0;
279 				break;
280 			case 2:
281 				y = 1;
282 				break;
283 			case 4:
284 				y = 2;
285 				break;
286 			case 8:
287 				y = 3;
288 				break;
289 			default:
290 				warnx("%d-byte integer formats are not "
291 				    "supported", nbytes);
292 				oldusage();
293 			}
294 			add(fmt[x][y]);
295 			break;
296 		default:
297 			oldusage();
298 		}
299 	}
300 }
301 
302 void
303 oldusage(void)
304 {
305 	extern char *__progname;
306 	fprintf(stderr, "usage: %s [-aBbcDdeFfHhIiLlOovXx] [-j offset] "
307 	    "[-N length] [-t type_string]\n"
308 	    "\t[[+]offset[.][Bb]] [file ...]\n", __progname);
309 	exit(1);
310 }
311 
312 static void
313 odoffset(int argc, char ***argvp)
314 {
315 	char *num, *p;
316 	int base;
317 	char *end;
318 
319 	/*
320 	 * The offset syntax of od(1) was genuinely bizarre.  First, if
321 	 * it started with a plus it had to be an offset.  Otherwise, if
322 	 * there were at least two arguments, a number or lower-case 'x'
323 	 * followed by a number makes it an offset.  By default it was
324 	 * octal; if it started with 'x' or '0x' it was hex.  If it ended
325 	 * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
326 	 * multiplied the number by 512 or 1024 byte units.  There was
327 	 * no way to assign a block count to a hex offset.
328 	 *
329 	 * We assume it's a file if the offset is bad.
330 	 */
331 	p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
332 	if (!p)
333 		return;
334 
335 	if (*p != '+' && (argc < 2 ||
336 	    (!isdigit((unsigned char)p[0]) &&
337 	    (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
338 		return;
339 
340 	base = 0;
341 	/*
342 	 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
343 	 * set base.
344 	 */
345 	if (p[0] == '+')
346 		++p;
347 	if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
348 		++p;
349 		base = 16;
350 	} else if (p[0] == '0' && p[1] == 'x') {
351 		p += 2;
352 		base = 16;
353 	}
354 
355 	/* skip over the number */
356 	if (base == 16)
357 		for (num = p; isxdigit((unsigned char)*p); ++p);
358 	else
359 		for (num = p; isdigit((unsigned char)*p); ++p);
360 
361 	/* check for no number */
362 	if (num == p)
363 		return;
364 
365 	/* if terminates with a '.', base is decimal */
366 	if (*p == '.') {
367 		if (base)
368 			return;
369 		base = 10;
370 	}
371 
372 	skip = strtol(num, &end, base ? base : 8);
373 
374 	/* if end isn't the same as p, we got a non-octal digit */
375 	if (end != p) {
376 		skip = 0;
377 		return;
378 	}
379 
380 	if (*p) {
381 		if (*p == 'B') {
382 			skip *= 1024;
383 			++p;
384 		} else if (*p == 'b') {
385 			skip *= 512;
386 			++p;
387 		}
388 	}
389 	if (*p) {
390 		skip = 0;
391 		return;
392 	}
393 	/*
394 	 * If the offset uses a non-octal base, the base of the offset
395 	 * is changed as well.  This isn't pretty, but it's easy.
396 	 */
397 #define	TYPE_OFFSET	7
398 	if (base == 16) {
399 		fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
400 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
401 	} else if (base == 10) {
402 		fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
403 		fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
404 	}
405 
406 	/* Terminate file list. */
407 	(*argvp)[1] = NULL;
408 }
409 
410 static void
411 odprecede(void)
412 {
413 	static int first = 1;
414 
415 	if (first) {
416 		first = 0;
417 		add("\"%07.7_Ao\n\"");
418 		add("\"%07.7_ao  \"");
419 	} else
420 		add("\"         \"");
421 }
422