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