138859Sbostic /*
2*62031Sbostic * Copyright (c) 1989, 1993
3*62031Sbostic * The Regents of the University of California. All rights reserved.
438859Sbostic *
542734Sbostic * %sccs.include.redist.c%
638859Sbostic */
738859Sbostic
838859Sbostic #ifndef lint
9*62031Sbostic static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 06/06/93";
1038859Sbostic #endif /* not lint */
1138859Sbostic
1238859Sbostic #include <sys/types.h>
1355201Sbostic
1455201Sbostic #include <errno.h>
1555201Sbostic #include <fcntl.h>
1638859Sbostic #include <stdio.h>
1747173Sbostic #include <stdlib.h>
1838859Sbostic #include <ctype.h>
1942056Sbostic #include <string.h>
2038859Sbostic #include "hexdump.h"
2138859Sbostic
2238859Sbostic FU *endfu; /* format at end-of-data */
2338859Sbostic
2455201Sbostic void
addfile(name)2538859Sbostic addfile(name)
2638859Sbostic char *name;
2738859Sbostic {
2838859Sbostic register char *p;
2938859Sbostic FILE *fp;
3038859Sbostic int ch;
3138859Sbostic char buf[2048 + 1];
3238859Sbostic
3355201Sbostic if ((fp = fopen(name, "r")) == NULL)
3455201Sbostic err("%s: %s\n", name, strerror(errno));
3538859Sbostic while (fgets(buf, sizeof(buf), fp)) {
3638859Sbostic if (!(p = index(buf, '\n'))) {
3738859Sbostic (void)fprintf(stderr, "hexdump: line too long.\n");
3838859Sbostic while ((ch = getchar()) != '\n' && ch != EOF);
3938859Sbostic continue;
4038859Sbostic }
4138859Sbostic *p = '\0';
4238859Sbostic for (p = buf; *p && isspace(*p); ++p);
4338859Sbostic if (!*p || *p == '#')
4438859Sbostic continue;
4538859Sbostic add(p);
4638859Sbostic }
4738859Sbostic (void)fclose(fp);
4838859Sbostic }
4938859Sbostic
5055201Sbostic void
add(fmt)5147173Sbostic add(fmt)
5247173Sbostic char *fmt;
5338859Sbostic {
5438859Sbostic register char *p;
5538859Sbostic static FS **nextfs;
5638859Sbostic FS *tfs;
5738859Sbostic FU *tfu, **nextfu;
5855201Sbostic char *savep;
5938859Sbostic
6038859Sbostic /* start new linked list of format units */
6155201Sbostic tfs = emalloc(sizeof(FS));
6238859Sbostic if (!fshead)
6338859Sbostic fshead = tfs;
6438859Sbostic else
6538859Sbostic *nextfs = tfs;
6638859Sbostic nextfs = &tfs->nextfs;
6738859Sbostic nextfu = &tfs->nextfu;
6838859Sbostic
6938859Sbostic /* take the format string and break it up into format units */
7038859Sbostic for (p = fmt;;) {
7138859Sbostic /* skip leading white space */
7238859Sbostic for (; isspace(*p); ++p);
7338859Sbostic if (!*p)
7438859Sbostic break;
7538859Sbostic
7638859Sbostic /* allocate a new format unit and link it in */
7755201Sbostic tfu = emalloc(sizeof(FU));
7838859Sbostic *nextfu = tfu;
7938859Sbostic nextfu = &tfu->nextfu;
8038859Sbostic tfu->reps = 1;
8138859Sbostic
8238859Sbostic /* if leading digit, repetition count */
8338859Sbostic if (isdigit(*p)) {
8438859Sbostic for (savep = p; isdigit(*p); ++p);
8538859Sbostic if (!isspace(*p) && *p != '/')
8638859Sbostic badfmt(fmt);
8738859Sbostic /* may overwrite either white space or slash */
8838859Sbostic tfu->reps = atoi(savep);
8938859Sbostic tfu->flags = F_SETREP;
9038859Sbostic /* skip trailing white space */
9138859Sbostic for (++p; isspace(*p); ++p);
9238859Sbostic }
9338859Sbostic
9438859Sbostic /* skip slash and trailing white space */
9538859Sbostic if (*p == '/')
9638859Sbostic while (isspace(*++p));
9738859Sbostic
9838859Sbostic /* byte count */
9938859Sbostic if (isdigit(*p)) {
10038859Sbostic for (savep = p; isdigit(*p); ++p);
10138859Sbostic if (!isspace(*p))
10238859Sbostic badfmt(fmt);
10338859Sbostic tfu->bcnt = atoi(savep);
10438859Sbostic /* skip trailing white space */
10538859Sbostic for (++p; isspace(*p); ++p);
10638859Sbostic }
10738859Sbostic
10838859Sbostic /* format */
10938859Sbostic if (*p != '"')
11038859Sbostic badfmt(fmt);
11147173Sbostic for (savep = ++p; *p != '"';)
11247173Sbostic if (*p++ == 0)
11347173Sbostic badfmt(fmt);
11447173Sbostic if (!(tfu->fmt = malloc(p - savep + 1)))
11538859Sbostic nomem();
11647173Sbostic (void) strncpy(tfu->fmt, savep, p - savep);
11747173Sbostic tfu->fmt[p - savep] = '\0';
11838859Sbostic escape(tfu->fmt);
11947173Sbostic p++;
12038859Sbostic }
12138859Sbostic }
12238859Sbostic
12338859Sbostic static char *spec = ".#-+ 0123456789";
12455201Sbostic
12555201Sbostic int
size(fs)12638859Sbostic size(fs)
12738859Sbostic FS *fs;
12838859Sbostic {
12938859Sbostic register FU *fu;
13038859Sbostic register int bcnt, cursize;
13138859Sbostic register char *fmt;
13238859Sbostic int prec;
13338859Sbostic
13438859Sbostic /* figure out the data block size needed for each format unit */
13538859Sbostic for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
13638859Sbostic if (fu->bcnt) {
13738859Sbostic cursize += fu->bcnt * fu->reps;
13838859Sbostic continue;
13938859Sbostic }
14038859Sbostic for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
14138859Sbostic if (*fmt != '%')
14238859Sbostic continue;
14338859Sbostic /*
14438859Sbostic * skip any special chars -- save precision in
14538859Sbostic * case it's a %s format.
14638859Sbostic */
14738859Sbostic while (index(spec + 1, *++fmt));
14838859Sbostic if (*fmt == '.' && isdigit(*++fmt)) {
14938859Sbostic prec = atoi(fmt);
15038859Sbostic while (isdigit(*++fmt));
15138859Sbostic }
15238859Sbostic switch(*fmt) {
15338859Sbostic case 'c':
15438859Sbostic bcnt += 1;
15538859Sbostic break;
15638859Sbostic case 'd': case 'i': case 'o': case 'u':
15738859Sbostic case 'x': case 'X':
15838859Sbostic bcnt += 4;
15938859Sbostic break;
16038859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G':
16138859Sbostic bcnt += 8;
16238859Sbostic break;
16338859Sbostic case 's':
16438859Sbostic bcnt += prec;
16538859Sbostic break;
16638859Sbostic case '_':
16738859Sbostic switch(*++fmt) {
16838859Sbostic case 'c': case 'p': case 'u':
16938859Sbostic bcnt += 1;
17038859Sbostic break;
17138859Sbostic }
17238859Sbostic }
17338859Sbostic }
17438859Sbostic cursize += bcnt * fu->reps;
17538859Sbostic }
17655201Sbostic return (cursize);
17738859Sbostic }
17838859Sbostic
17955201Sbostic void
rewrite(fs)18038859Sbostic rewrite(fs)
18138859Sbostic FS *fs;
18238859Sbostic {
18338859Sbostic enum { NOTOKAY, USEBCNT, USEPREC } sokay;
18438859Sbostic register PR *pr, **nextpr;
18538859Sbostic register FU *fu;
18638859Sbostic register char *p1, *p2;
18755201Sbostic char savech, *fmtp, cs[3];
18838859Sbostic int nconv, prec;
18938859Sbostic
19038859Sbostic for (fu = fs->nextfu; fu; fu = fu->nextfu) {
19138859Sbostic /*
19255201Sbostic * Break each format unit into print units; each conversion
19355201Sbostic * character gets its own.
19438859Sbostic */
19538859Sbostic for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
19655201Sbostic pr = emalloc(sizeof(PR));
19738859Sbostic if (!fu->nextpr)
19838859Sbostic fu->nextpr = pr;
19938859Sbostic else
20038859Sbostic *nextpr = pr;
20138859Sbostic
20255201Sbostic /* Skip preceding text and up to the next % sign. */
20338859Sbostic for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
20438859Sbostic
20555201Sbostic /* Only text in the string. */
20638859Sbostic if (!*p1) {
20738859Sbostic pr->fmt = fmtp;
20838859Sbostic pr->flags = F_TEXT;
20938859Sbostic break;
21038859Sbostic }
21138859Sbostic
21238859Sbostic /*
21355201Sbostic * Get precision for %s -- if have a byte count, don't
21438859Sbostic * need it.
21538859Sbostic */
21638859Sbostic if (fu->bcnt) {
21738859Sbostic sokay = USEBCNT;
21855201Sbostic /* Skip to conversion character. */
21938859Sbostic for (++p1; index(spec, *p1); ++p1);
22038859Sbostic } else {
22155201Sbostic /* Skip any special chars, field width. */
22238859Sbostic while (index(spec + 1, *++p1));
22338859Sbostic if (*p1 == '.' && isdigit(*++p1)) {
22438859Sbostic sokay = USEPREC;
22538859Sbostic prec = atoi(p1);
22638859Sbostic while (isdigit(*++p1));
22755201Sbostic } else
22838859Sbostic sokay = NOTOKAY;
22938859Sbostic }
23038859Sbostic
23155201Sbostic p2 = p1 + 1; /* Set end pointer. */
23255201Sbostic cs[0] = *p1; /* Set conversion string. */
23355201Sbostic cs[1] = '\0';
23438859Sbostic
23538859Sbostic /*
23655201Sbostic * Figure out the byte count for each conversion;
23738859Sbostic * rewrite the format as necessary, set up blank-
23838859Sbostic * padding for end of data.
23938859Sbostic */
24055201Sbostic switch(cs[0]) {
24138859Sbostic case 'c':
24238859Sbostic pr->flags = F_CHAR;
24338859Sbostic switch(fu->bcnt) {
24438859Sbostic case 0: case 1:
24538859Sbostic pr->bcnt = 1;
24638859Sbostic break;
24738859Sbostic default:
24838859Sbostic p1[1] = '\0';
24938859Sbostic badcnt(p1);
25038859Sbostic }
25138859Sbostic break;
25238859Sbostic case 'd': case 'i':
25338859Sbostic pr->flags = F_INT;
25455201Sbostic goto isint;
25538859Sbostic case 'o': case 'u': case 'x': case 'X':
25638859Sbostic pr->flags = F_UINT;
25755201Sbostic isint: cs[2] = '\0';
25855201Sbostic cs[1] = cs[0];
25955201Sbostic cs[0] = 'q';
26055201Sbostic switch(fu->bcnt) {
26138859Sbostic case 0: case 4:
26238859Sbostic pr->bcnt = 4;
26338859Sbostic break;
26438859Sbostic case 1:
26538859Sbostic pr->bcnt = 1;
26638859Sbostic break;
26738859Sbostic case 2:
26838859Sbostic pr->bcnt = 2;
26938859Sbostic break;
27038859Sbostic default:
27138859Sbostic p1[1] = '\0';
27238859Sbostic badcnt(p1);
27338859Sbostic }
27438859Sbostic break;
27538859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G':
27638859Sbostic pr->flags = F_DBL;
27738859Sbostic switch(fu->bcnt) {
27838859Sbostic case 0: case 8:
27938859Sbostic pr->bcnt = 8;
28038859Sbostic break;
28138859Sbostic case 4:
28238859Sbostic pr->bcnt = 4;
28338859Sbostic break;
28438859Sbostic default:
28538859Sbostic p1[1] = '\0';
28638859Sbostic badcnt(p1);
28738859Sbostic }
28838859Sbostic break;
28938859Sbostic case 's':
29038859Sbostic pr->flags = F_STR;
29138859Sbostic switch(sokay) {
29238859Sbostic case NOTOKAY:
29338859Sbostic badsfmt();
29438859Sbostic case USEBCNT:
29538859Sbostic pr->bcnt = fu->bcnt;
29638859Sbostic break;
29738859Sbostic case USEPREC:
29838859Sbostic pr->bcnt = prec;
29938859Sbostic break;
30038859Sbostic }
30138859Sbostic break;
30238859Sbostic case '_':
30338859Sbostic ++p2;
30438859Sbostic switch(p1[1]) {
30538859Sbostic case 'A':
30638859Sbostic endfu = fu;
30738859Sbostic fu->flags |= F_IGNORE;
30838859Sbostic /* FALLTHROUGH */
30938859Sbostic case 'a':
31038859Sbostic pr->flags = F_ADDRESS;
31138859Sbostic ++p2;
31238859Sbostic switch(p1[2]) {
31338859Sbostic case 'd': case 'o': case'x':
31455201Sbostic cs[0] = 'q';
31555201Sbostic cs[1] = p1[2];
31655201Sbostic cs[2] = '\0';
31738859Sbostic break;
31838859Sbostic default:
31938859Sbostic p1[3] = '\0';
32038859Sbostic badconv(p1);
32138859Sbostic }
32238859Sbostic break;
32338859Sbostic case 'c':
32438859Sbostic pr->flags = F_C;
32555201Sbostic /* cs[0] = 'c'; set in conv_c */
32655201Sbostic goto isint2;
32738859Sbostic case 'p':
32838859Sbostic pr->flags = F_P;
32955201Sbostic cs[0] = 'c';
33055201Sbostic goto isint2;
33138859Sbostic case 'u':
33238859Sbostic pr->flags = F_U;
33355201Sbostic /* cs[0] = 'c'; set in conv_u */
33455201Sbostic isint2: switch(fu->bcnt) {
33538859Sbostic case 0: case 1:
33638859Sbostic pr->bcnt = 1;
33738859Sbostic break;
33838859Sbostic default:
33938859Sbostic p1[2] = '\0';
34038859Sbostic badcnt(p1);
34138859Sbostic }
34238859Sbostic break;
34338859Sbostic default:
34438859Sbostic p1[2] = '\0';
34538859Sbostic badconv(p1);
34638859Sbostic }
34738859Sbostic break;
34838859Sbostic default:
34938859Sbostic p1[1] = '\0';
35038859Sbostic badconv(p1);
35138859Sbostic }
35238859Sbostic
35338859Sbostic /*
35455201Sbostic * Copy to PR format string, set conversion character
35538859Sbostic * pointer, update original.
35638859Sbostic */
35738859Sbostic savech = *p2;
35855201Sbostic p1[0] = '\0';
35955201Sbostic pr->fmt = emalloc(strlen(fmtp) + 2);
36055201Sbostic (void)strcpy(pr->fmt, fmtp);
36155201Sbostic (void)strcat(pr->fmt, cs);
36238859Sbostic *p2 = savech;
36338859Sbostic pr->cchar = pr->fmt + (p1 - fmtp);
36438859Sbostic fmtp = p2;
36538859Sbostic
36655201Sbostic /* Only one conversion character if byte count. */
36755201Sbostic if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
36855201Sbostic err("byte count with multiple conversion characters");
36938859Sbostic }
37038859Sbostic /*
37155201Sbostic * If format unit byte count not specified, figure it out
37238859Sbostic * so can adjust rep count later.
37338859Sbostic */
37438859Sbostic if (!fu->bcnt)
37538859Sbostic for (pr = fu->nextpr; pr; pr = pr->nextpr)
37638859Sbostic fu->bcnt += pr->bcnt;
37738859Sbostic }
37838859Sbostic /*
37955201Sbostic * If the format string interprets any data at all, and it's
38038859Sbostic * not the same as the blocksize, and its last format unit
38138859Sbostic * interprets any data at all, and has no iteration count,
38238859Sbostic * repeat it as necessary.
38338859Sbostic *
38455201Sbostic * If, rep count is greater than 1, no trailing whitespace
38538859Sbostic * gets output from the last iteration of the format unit.
38638859Sbostic */
38738859Sbostic for (fu = fs->nextfu;; fu = fu->nextfu) {
38838859Sbostic if (!fu->nextfu && fs->bcnt < blocksize &&
38938859Sbostic !(fu->flags&F_SETREP) && fu->bcnt)
39038859Sbostic fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
39138859Sbostic if (fu->reps > 1) {
39238859Sbostic for (pr = fu->nextpr;; pr = pr->nextpr)
39338859Sbostic if (!pr->nextpr)
39438859Sbostic break;
39538859Sbostic for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
39638859Sbostic p2 = isspace(*p1) ? p1 : NULL;
39738859Sbostic if (p2)
39838859Sbostic pr->nospace = p2;
39938859Sbostic }
40038859Sbostic if (!fu->nextfu)
40138859Sbostic break;
40238859Sbostic }
40355201Sbostic #ifdef DEBUG
40455201Sbostic for (fu = fs->nextfu; fu; fu = fu->nextfu) {
40555201Sbostic (void)printf("fmt:");
40655201Sbostic for (pr = fu->nextpr; pr; pr = pr->nextpr)
40755201Sbostic (void)printf(" {%s}", pr->fmt);
40855201Sbostic (void)printf("\n");
40955201Sbostic }
41055201Sbostic #endif
41138859Sbostic }
41238859Sbostic
41355201Sbostic void
escape(p1)41438859Sbostic escape(p1)
41538859Sbostic register char *p1;
41638859Sbostic {
41738859Sbostic register char *p2;
41838859Sbostic
41938859Sbostic /* alphabetic escape sequences have to be done in place */
42038859Sbostic for (p2 = p1;; ++p1, ++p2) {
42138859Sbostic if (!*p1) {
42238859Sbostic *p2 = *p1;
42338859Sbostic break;
42438859Sbostic }
42538859Sbostic if (*p1 == '\\')
42638859Sbostic switch(*++p1) {
42738859Sbostic case 'a':
42838859Sbostic /* *p2 = '\a'; */
42938859Sbostic *p2 = '\007';
43038859Sbostic break;
43138859Sbostic case 'b':
43238859Sbostic *p2 = '\b';
43338859Sbostic break;
43438859Sbostic case 'f':
43538859Sbostic *p2 = '\f';
43638859Sbostic break;
43738859Sbostic case 'n':
43838859Sbostic *p2 = '\n';
43938859Sbostic break;
44038859Sbostic case 'r':
44138859Sbostic *p2 = '\r';
44238859Sbostic break;
44338859Sbostic case 't':
44438859Sbostic *p2 = '\t';
44538859Sbostic break;
44638859Sbostic case 'v':
44738859Sbostic *p2 = '\v';
44838859Sbostic break;
44938859Sbostic default:
45038859Sbostic *p2 = *p1;
45138859Sbostic break;
45238859Sbostic }
45338859Sbostic }
45438859Sbostic }
45538859Sbostic
45655201Sbostic void
badcnt(s)45738859Sbostic badcnt(s)
45838859Sbostic char *s;
45938859Sbostic {
46055201Sbostic err("%s: bad byte count", s);
46138859Sbostic }
46238859Sbostic
46355201Sbostic void
badsfmt()46438859Sbostic badsfmt()
46538859Sbostic {
46655201Sbostic err("%%s: requires a precision or a byte count\n");
46738859Sbostic }
46838859Sbostic
46955201Sbostic void
badfmt(fmt)47038859Sbostic badfmt(fmt)
47138859Sbostic char *fmt;
47238859Sbostic {
47355201Sbostic err("\"%s\": bad format\n", fmt);
47438859Sbostic }
47538859Sbostic
47655201Sbostic void
badconv(ch)47738859Sbostic badconv(ch)
47838859Sbostic char *ch;
47938859Sbostic {
48055201Sbostic err("%%%s: bad conversion character\n", ch);
48138859Sbostic }
482