1*e45d8159Schristos /* $NetBSD: odsyntax.c,v 1.28 2010/11/27 20:46:38 christos Exp $ */
29d225a17Stls
361f28255Scgd /*-
473973984Smrg * Copyright (c) 1990, 1993
573973984Smrg * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
32171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
33171d6532Slukem #include "nbtool_config.h"
34171d6532Slukem #endif
35171d6532Slukem
36c6810a02Slukem #include <sys/cdefs.h>
37171d6532Slukem #if !defined(lint)
38769693f9Smikel #if 0
3973973984Smrg static char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95";
40769693f9Smikel #else
41*e45d8159Schristos __RCSID("$NetBSD: odsyntax.c,v 1.28 2010/11/27 20:46:38 christos Exp $");
42769693f9Smikel #endif
4361f28255Scgd #endif /* not lint */
4461f28255Scgd
4561f28255Scgd #include <sys/types.h>
4673973984Smrg
47769693f9Smikel #include <ctype.h>
48c6810a02Slukem #include <err.h>
4961f28255Scgd #include <stdio.h>
50769693f9Smikel #include <stdlib.h>
5173973984Smrg #include <unistd.h>
52cdab3a7aSchristos #include <util.h>
5373973984Smrg
5461f28255Scgd #include "hexdump.h"
5561f28255Scgd
56316dc7a8Sdrochner #define PADDING " "
57316dc7a8Sdrochner
5889e07ef7Sbjh21 struct odformat {
5989e07ef7Sbjh21 char type;
6089e07ef7Sbjh21 int nbytes;
6189e07ef7Sbjh21 char const *format;
6289e07ef7Sbjh21 int minwidth;
6389e07ef7Sbjh21 };
6489e07ef7Sbjh21
6589e07ef7Sbjh21 struct odaddrformat {
6689e07ef7Sbjh21 char type;
6789e07ef7Sbjh21 char const *format1;
6889e07ef7Sbjh21 char const *format2;
6989e07ef7Sbjh21 };
7089e07ef7Sbjh21
71ec10ab01Sdrochner int odmode;
7261f28255Scgd
73d310ebb1Sperry static void odoffset(int, char ***);
74d310ebb1Sperry static void posixtypes(char const *);
7574f15d98Schristos
76769693f9Smikel void
odsyntax(int argc,char *** argvp)77ec10ab01Sdrochner odsyntax(int argc, char ***argvp)
7861f28255Scgd {
79316dc7a8Sdrochner static char empty[] = "", padding[] = PADDING;
8061f28255Scgd int ch;
81a4b50871Sbjh21 char *p, **argv;
8261f28255Scgd
83316dc7a8Sdrochner #define TYPE_OFFSET 7
84316dc7a8Sdrochner add("\"%07.7_Ao\n\"");
85316dc7a8Sdrochner add("\"%07.7_ao \"");
86316dc7a8Sdrochner
87ec10ab01Sdrochner odmode = 1;
8861f28255Scgd argv = *argvp;
8994f69635Sbjh21 while ((ch = getopt(argc, argv,
90ec10ab01Sdrochner "A:aBbcDdeFfHhIij:LlN:Oot:vXx")) != -1)
9161f28255Scgd switch (ch) {
92316dc7a8Sdrochner case 'A':
93316dc7a8Sdrochner switch (*optarg) {
94316dc7a8Sdrochner case 'd': case 'o': case 'x':
95316dc7a8Sdrochner fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
96316dc7a8Sdrochner fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
97316dc7a8Sdrochner *optarg;
98316dc7a8Sdrochner break;
99316dc7a8Sdrochner case 'n':
100316dc7a8Sdrochner fshead->nextfu->fmt = empty;
101316dc7a8Sdrochner fshead->nextfs->nextfu->fmt = padding;
102316dc7a8Sdrochner break;
103316dc7a8Sdrochner default:
104316dc7a8Sdrochner errx(1, "%s: invalid address base", optarg);
105316dc7a8Sdrochner }
106316dc7a8Sdrochner break;
10761f28255Scgd case 'a':
10889e07ef7Sbjh21 posixtypes("a");
10961f28255Scgd break;
11061f28255Scgd case 'B':
11161f28255Scgd case 'o':
11289e07ef7Sbjh21 posixtypes("o2");
11361f28255Scgd break;
11461f28255Scgd case 'b':
11589e07ef7Sbjh21 posixtypes("o1");
11661f28255Scgd break;
11761f28255Scgd case 'c':
11889e07ef7Sbjh21 posixtypes("c");
11961f28255Scgd break;
12061f28255Scgd case 'd':
12189e07ef7Sbjh21 posixtypes("u2");
12261f28255Scgd break;
12361f28255Scgd case 'D':
12489e07ef7Sbjh21 posixtypes("u4");
12561f28255Scgd break;
12661f28255Scgd case 'e': /* undocumented in od */
12761f28255Scgd case 'F':
12889e07ef7Sbjh21 posixtypes("f8");
12961f28255Scgd break;
13061f28255Scgd case 'f':
13189e07ef7Sbjh21 posixtypes("f4");
13261f28255Scgd break;
13361f28255Scgd case 'H':
13461f28255Scgd case 'X':
13589e07ef7Sbjh21 posixtypes("x4");
13661f28255Scgd break;
13761f28255Scgd case 'h':
13861f28255Scgd case 'x':
13989e07ef7Sbjh21 posixtypes("x2");
14061f28255Scgd break;
14161f28255Scgd case 'I':
14261f28255Scgd case 'L':
14361f28255Scgd case 'l':
14489e07ef7Sbjh21 posixtypes("d4");
14561f28255Scgd break;
14661f28255Scgd case 'i':
14789e07ef7Sbjh21 posixtypes("d2");
14861f28255Scgd break;
149a4b50871Sbjh21 case 'j':
150a4b50871Sbjh21 if ((skip = strtol(optarg, &p, 0)) < 0)
151a4b50871Sbjh21 errx(1, "%s: bad skip value", optarg);
152a4b50871Sbjh21 switch(*p) {
153a4b50871Sbjh21 case 'b':
154a4b50871Sbjh21 skip *= 512;
155a4b50871Sbjh21 break;
156a4b50871Sbjh21 case 'k':
157a4b50871Sbjh21 skip *= 1024;
158a4b50871Sbjh21 break;
159a4b50871Sbjh21 case 'm':
160a4b50871Sbjh21 skip *= 1048576;
161a4b50871Sbjh21 break;
162a4b50871Sbjh21 }
163a4b50871Sbjh21 break;
16494f69635Sbjh21 case 'N':
16594f69635Sbjh21 if ((length = atoi(optarg)) < 0)
16694f69635Sbjh21 errx(1, "%s: bad length value", optarg);
16794f69635Sbjh21 break;
16861f28255Scgd case 'O':
16989e07ef7Sbjh21 posixtypes("o4");
17061f28255Scgd break;
17174f15d98Schristos case 't':
1720a1ce99fSbjh21 posixtypes(optarg);
17374f15d98Schristos break;
17461f28255Scgd case 'v':
17561f28255Scgd vflag = ALL;
17661f28255Scgd break;
17761f28255Scgd case '?':
17861f28255Scgd default:
179*e45d8159Schristos usage();
18061f28255Scgd }
18161f28255Scgd
182316dc7a8Sdrochner if (fshead->nextfs->nextfs == NULL)
183316dc7a8Sdrochner posixtypes("oS");
18461f28255Scgd
18561f28255Scgd argc -= optind;
18661f28255Scgd *argvp += optind;
18761f28255Scgd
18873973984Smrg if (argc)
18961f28255Scgd odoffset(argc, argvp);
19061f28255Scgd }
19161f28255Scgd
19289e07ef7Sbjh21 /* formats used for -t */
19389e07ef7Sbjh21
19489e07ef7Sbjh21 static const struct odformat odftab[] = {
19589e07ef7Sbjh21 { 'a', 1, "%3_u", 4 },
19689e07ef7Sbjh21 { 'c', 1, "%3_c", 4 },
19789e07ef7Sbjh21 { 'd', 1, "%4d", 5 },
19889e07ef7Sbjh21 { 'd', 2, "%6d", 6 },
19989e07ef7Sbjh21 { 'd', 4, "%11d", 11 },
20089e07ef7Sbjh21 { 'd', 8, "%20d", 20 },
20189e07ef7Sbjh21 { 'o', 1, "%03o", 4 },
20289e07ef7Sbjh21 { 'o', 2, "%06o", 7 },
20389e07ef7Sbjh21 { 'o', 4, "%011o", 12 },
20489e07ef7Sbjh21 { 'o', 8, "%022o", 23 },
20589e07ef7Sbjh21 { 'u', 1, "%03u" , 4 },
20689e07ef7Sbjh21 { 'u', 2, "%05u" , 6 },
20789e07ef7Sbjh21 { 'u', 4, "%010u", 11 },
20889e07ef7Sbjh21 { 'u', 8, "%020u", 21 },
20989e07ef7Sbjh21 { 'x', 1, "%02x", 3 },
21089e07ef7Sbjh21 { 'x', 2, "%04x", 5 },
21189e07ef7Sbjh21 { 'x', 4, "%08x", 9 },
21289e07ef7Sbjh21 { 'x', 8, "%016x", 17 },
21389e07ef7Sbjh21 { 'f', 4, "%14.7e", 15 },
21489e07ef7Sbjh21 { 'f', 8, "%21.14e", 22 },
21589e07ef7Sbjh21 { 0, 0, NULL, 0 }
21689e07ef7Sbjh21 };
21789e07ef7Sbjh21
2180a1ce99fSbjh21 /*
2190a1ce99fSbjh21 * Interpret a POSIX-style -t argument.
2200a1ce99fSbjh21 */
2210a1ce99fSbjh21 static void
posixtypes(char const * type_string)222d310ebb1Sperry posixtypes(char const *type_string)
2230a1ce99fSbjh21 {
224a3b235bbSlukem int nbytes = 0;
22589e07ef7Sbjh21 char *fmt, type, *tmp;
22689e07ef7Sbjh21 struct odformat const *odf;
2270a1ce99fSbjh21
2280a1ce99fSbjh21 while (*type_string) {
22989e07ef7Sbjh21 switch ((type = *type_string++)) {
2300a1ce99fSbjh21 case 'a':
2310a1ce99fSbjh21 case 'c':
23289e07ef7Sbjh21 nbytes = 1;
2330a1ce99fSbjh21 break;
2340a1ce99fSbjh21 case 'f':
235b23af931Sdsl if (isupper((unsigned char)*type_string)) {
23689e07ef7Sbjh21 switch(*type_string) {
23789e07ef7Sbjh21 case 'F':
23889e07ef7Sbjh21 nbytes = sizeof(float);
23989e07ef7Sbjh21 break;
24089e07ef7Sbjh21 case 'D':
24189e07ef7Sbjh21 nbytes = sizeof(double);
24289e07ef7Sbjh21 break;
24389e07ef7Sbjh21 case 'L':
24489e07ef7Sbjh21 nbytes = sizeof(long double);
24589e07ef7Sbjh21 break;
24689e07ef7Sbjh21 default:
24789e07ef7Sbjh21 warnx("Bad type-size qualifier '%c'",
24889e07ef7Sbjh21 *type_string);
249*e45d8159Schristos usage();
25089e07ef7Sbjh21 }
25189e07ef7Sbjh21 type_string++;
252b23af931Sdsl } else if (isdigit((unsigned char)*type_string)) {
25389e07ef7Sbjh21 nbytes = strtol(type_string, &tmp, 10);
25489e07ef7Sbjh21 type_string = tmp;
25589e07ef7Sbjh21 } else
25689e07ef7Sbjh21 nbytes = 8;
2570a1ce99fSbjh21 break;
2580a1ce99fSbjh21 case 'd':
2590a1ce99fSbjh21 case 'o':
2600a1ce99fSbjh21 case 'u':
2610a1ce99fSbjh21 case 'x':
262b23af931Sdsl if (isupper((unsigned char)*type_string)) {
2630a1ce99fSbjh21 switch(*type_string) {
2640a1ce99fSbjh21 case 'C':
26541a2a8aaSbjh21 nbytes = sizeof(char);
2660a1ce99fSbjh21 break;
2670a1ce99fSbjh21 case 'S':
26841a2a8aaSbjh21 nbytes = sizeof(short);
2690a1ce99fSbjh21 break;
2700a1ce99fSbjh21 case 'I':
27141a2a8aaSbjh21 nbytes = sizeof(int);
2720a1ce99fSbjh21 break;
2730a1ce99fSbjh21 case 'L':
27441a2a8aaSbjh21 nbytes = sizeof(long);
2750a1ce99fSbjh21 break;
2760a1ce99fSbjh21 default:
2770a1ce99fSbjh21 warnx("Bad type-size qualifier '%c'",
2780a1ce99fSbjh21 *type_string);
279*e45d8159Schristos usage();
2800a1ce99fSbjh21 }
2810a1ce99fSbjh21 type_string++;
282b23af931Sdsl } else if (isdigit((unsigned char)*type_string)) {
28389e07ef7Sbjh21 nbytes = strtol(type_string, &tmp, 10);
28489e07ef7Sbjh21 type_string = tmp;
28589e07ef7Sbjh21 } else
28689e07ef7Sbjh21 nbytes = 4;
2870a1ce99fSbjh21 break;
2880a1ce99fSbjh21 default:
289*e45d8159Schristos usage();
2900a1ce99fSbjh21 }
29189e07ef7Sbjh21 for (odf = odftab; odf->type != 0; odf++)
29289e07ef7Sbjh21 if (odf->type == type && odf->nbytes == nbytes)
29389e07ef7Sbjh21 break;
29489e07ef7Sbjh21 if (odf->type == 0)
29589e07ef7Sbjh21 errx(1, "%c%d: format not supported", type, nbytes);
296cdab3a7aSchristos (void)easprintf(&fmt, "%d/%d \"%*s%s \" \"\\n\"",
29789e07ef7Sbjh21 16 / nbytes, nbytes,
29889e07ef7Sbjh21 4 * nbytes - odf->minwidth, "", odf->format);
29989e07ef7Sbjh21 add(fmt);
3000a1ce99fSbjh21 }
3010a1ce99fSbjh21 }
3020a1ce99fSbjh21
30373973984Smrg static void
odoffset(int argc,char *** argvp)304d310ebb1Sperry odoffset(int argc, char ***argvp)
30561f28255Scgd {
306c6810a02Slukem char *num, *p;
30761f28255Scgd int base;
30861f28255Scgd char *end;
30961f28255Scgd
31061f28255Scgd /*
31161f28255Scgd * The offset syntax of od(1) was genuinely bizarre. First, if
31261f28255Scgd * it started with a plus it had to be an offset. Otherwise, if
31361f28255Scgd * there were at least two arguments, a number or lower-case 'x'
31461f28255Scgd * followed by a number makes it an offset. By default it was
31561f28255Scgd * octal; if it started with 'x' or '0x' it was hex. If it ended
31661f28255Scgd * in a '.', it was decimal. If a 'b' or 'B' was appended, it
31761f28255Scgd * multiplied the number by 512 or 1024 byte units. There was
31861f28255Scgd * no way to assign a block count to a hex offset.
31961f28255Scgd *
320769693f9Smikel * We assume it's a file if the offset is bad.
32161f28255Scgd */
32273973984Smrg p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
32321f39729Smycroft if (!p)
32421f39729Smycroft return;
32573973984Smrg
32661f28255Scgd if (*p != '+' && (argc < 2 ||
3279794a7e0Schristos (!isdigit((unsigned char)p[0]) &&
3289794a7e0Schristos (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
32961f28255Scgd return;
33061f28255Scgd
33161f28255Scgd base = 0;
33261f28255Scgd /*
33361f28255Scgd * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
33461f28255Scgd * set base.
33561f28255Scgd */
33661f28255Scgd if (p[0] == '+')
33761f28255Scgd ++p;
3389794a7e0Schristos if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
33961f28255Scgd ++p;
34061f28255Scgd base = 16;
34161f28255Scgd } else if (p[0] == '0' && p[1] == 'x') {
34261f28255Scgd p += 2;
34361f28255Scgd base = 16;
34461f28255Scgd }
34561f28255Scgd
34661f28255Scgd /* skip over the number */
34761f28255Scgd if (base == 16)
3489794a7e0Schristos for (num = p; isxdigit((unsigned char)*p); ++p);
34961f28255Scgd else
3509794a7e0Schristos for (num = p; isdigit((unsigned char)*p); ++p);
35161f28255Scgd
35261f28255Scgd /* check for no number */
35361f28255Scgd if (num == p)
35461f28255Scgd return;
35561f28255Scgd
35661f28255Scgd /* if terminates with a '.', base is decimal */
35761f28255Scgd if (*p == '.') {
35861f28255Scgd if (base)
35961f28255Scgd return;
36061f28255Scgd base = 10;
36161f28255Scgd }
36261f28255Scgd
36361f28255Scgd skip = strtol(num, &end, base ? base : 8);
36461f28255Scgd
36561f28255Scgd /* if end isn't the same as p, we got a non-octal digit */
36673973984Smrg if (end != p) {
36761f28255Scgd skip = 0;
36873973984Smrg return;
36973973984Smrg }
37073973984Smrg
371f670fa10Sross if (*p) {
37273973984Smrg if (*p == 'B') {
37361f28255Scgd skip *= 1024;
37461f28255Scgd ++p;
37573973984Smrg } else if (*p == 'b') {
37673973984Smrg skip *= 512;
37773973984Smrg ++p;
37861f28255Scgd }
379f670fa10Sross }
38073973984Smrg if (*p) {
38161f28255Scgd skip = 0;
38273973984Smrg return;
38373973984Smrg }
38461f28255Scgd /*
38573973984Smrg * If the offset uses a non-octal base, the base of the offset
38673973984Smrg * is changed as well. This isn't pretty, but it's easy.
38761f28255Scgd */
38861f28255Scgd if (base == 16) {
38961f28255Scgd fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
39061f28255Scgd fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
39161f28255Scgd } else if (base == 10) {
39261f28255Scgd fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
39361f28255Scgd fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
39461f28255Scgd }
39573973984Smrg
39673973984Smrg /* Terminate file list. */
39773973984Smrg (*argvp)[1] = NULL;
39861f28255Scgd }
399