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