Annotation of src/usr.bin/hexdump/parse.c, Revision 1.12
1.12 ! millert 1: /* $OpenBSD: parse.c,v 1.11 2003/04/05 16:13:47 deraadt Exp $ */
1.9 pvalchev 2: /* $NetBSD: parse.c,v 1.12 2001/12/07 13:37:39 bjh21 Exp $ */
1.2 deraadt 3:
1.1 deraadt 4: /*
1.9 pvalchev 5: * Copyright (c) 1989, 1993
6: * The Regents of the University of California. All rights reserved.
1.1 deraadt 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.
1.12 ! millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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: @(#)parse.c 5.6 (Berkeley) 3/9/91";*/
1.12 ! millert 35: static char rcsid[] = "$OpenBSD: parse.c,v 1.11 2003/04/05 16:13:47 deraadt Exp $";
1.1 deraadt 36: #endif /* not lint */
37:
38: #include <sys/types.h>
39: #include <sys/file.h>
1.9 pvalchev 40:
41: #include <ctype.h>
42: #include <err.h>
43: #include <errno.h>
44: #include <fcntl.h>
1.1 deraadt 45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
1.9 pvalchev 48:
1.1 deraadt 49: #include "hexdump.h"
50:
51: FU *endfu; /* format at end-of-data */
52:
1.6 pvalchev 53: void
1.1 deraadt 54: addfile(name)
55: char *name;
56: {
1.8 mpech 57: char *p;
1.1 deraadt 58: FILE *fp;
1.9 pvalchev 59: int ch;
60: char buf[2048 + 1];
1.1 deraadt 61:
1.9 pvalchev 62: if ((fp = fopen(name, "r")) == NULL)
63: err(1, "fopen %s", name);
64: while (fgets(buf, sizeof(buf), fp)) {
65: if (!(p = strchr(buf, '\n'))) {
66: warnx("line too long.");
67: while ((ch = getchar()) != '\n' && ch != EOF);
1.1 deraadt 68: continue;
69: }
1.9 pvalchev 70: *p = '\0';
71: for (p = buf; *p && isspace((unsigned char)*p); ++p);
1.1 deraadt 72: if (!*p || *p == '#')
73: continue;
74: add(p);
75: }
76: (void)fclose(fp);
77: }
78:
1.6 pvalchev 79: void
1.1 deraadt 80: add(fmt)
1.9 pvalchev 81: const char *fmt;
1.1 deraadt 82: {
1.9 pvalchev 83: const char *p;
1.1 deraadt 84: static FS **nextfs;
85: FS *tfs;
86: FU *tfu, **nextfu;
1.9 pvalchev 87: const char *savep;
1.1 deraadt 88:
89: /* start new linked list of format units */
1.9 pvalchev 90: tfs = emalloc(sizeof(FS));
1.1 deraadt 91: if (!fshead)
92: fshead = tfs;
93: else
94: *nextfs = tfs;
95: nextfs = &tfs->nextfs;
96: nextfu = &tfs->nextfu;
97:
98: /* take the format string and break it up into format units */
99: for (p = fmt;;) {
100: /* skip leading white space */
1.9 pvalchev 101: for (; isspace((unsigned char)*p); ++p);
1.1 deraadt 102: if (!*p)
103: break;
104:
105: /* allocate a new format unit and link it in */
1.9 pvalchev 106: tfu = emalloc(sizeof(FU));
1.1 deraadt 107: *nextfu = tfu;
108: nextfu = &tfu->nextfu;
109: tfu->reps = 1;
110:
111: /* if leading digit, repetition count */
1.9 pvalchev 112: if (isdigit((unsigned char)*p)) {
113: for (savep = p; isdigit((unsigned char)*p); ++p);
114: if (!isspace((unsigned char)*p) && *p != '/')
115: badfmt(fmt);
1.1 deraadt 116: /* may overwrite either white space or slash */
117: tfu->reps = atoi(savep);
118: tfu->flags = F_SETREP;
119: /* skip trailing white space */
1.9 pvalchev 120: for (++p; isspace((unsigned char)*p); ++p);
1.1 deraadt 121: }
122:
123: /* skip slash and trailing white space */
124: if (*p == '/')
1.9 pvalchev 125: while (isspace((unsigned char)*++p));
1.1 deraadt 126:
127: /* byte count */
1.9 pvalchev 128: if (isdigit((unsigned char)*p)) {
129: for (savep = p; isdigit((unsigned char)*p); ++p);
130: if (!isspace((unsigned char)*p))
131: badfmt(fmt);
1.1 deraadt 132: tfu->bcnt = atoi(savep);
133: /* skip trailing white space */
1.9 pvalchev 134: for (++p; isspace((unsigned char)*p); ++p);
1.1 deraadt 135: }
136:
137: /* format */
138: if (*p != '"')
1.9 pvalchev 139: badfmt(fmt);
1.1 deraadt 140: for (savep = ++p; *p != '"';)
141: if (*p++ == 0)
1.9 pvalchev 142: badfmt(fmt);
1.1 deraadt 143: if (!(tfu->fmt = malloc(p - savep + 1)))
1.9 pvalchev 144: nomem();
1.1 deraadt 145: (void) strncpy(tfu->fmt, savep, p - savep);
146: tfu->fmt[p - savep] = '\0';
147: escape(tfu->fmt);
148: p++;
149: }
150: }
151:
1.7 mickey 152: static const char *spec = ".#-+ 0123456789";
1.9 pvalchev 153:
1.6 pvalchev 154: int
1.1 deraadt 155: size(fs)
156: FS *fs;
157: {
1.8 mpech 158: FU *fu;
159: int bcnt, cursize;
160: char *fmt;
1.1 deraadt 161: int prec;
162:
163: /* figure out the data block size needed for each format unit */
164: for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
165: if (fu->bcnt) {
166: cursize += fu->bcnt * fu->reps;
167: continue;
168: }
169: for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
170: if (*fmt != '%')
171: continue;
172: /*
173: * skip any special chars -- save precision in
174: * case it's a %s format.
175: */
1.3 millert 176: while (strchr(spec + 1, *++fmt));
1.9 pvalchev 177: if (*fmt == '.' && isdigit((unsigned char)*++fmt)) {
1.1 deraadt 178: prec = atoi(fmt);
1.9 pvalchev 179: while (isdigit((unsigned char)*++fmt));
1.1 deraadt 180: }
181: switch(*fmt) {
182: case 'c':
183: bcnt += 1;
184: break;
185: case 'd': case 'i': case 'o': case 'u':
186: case 'x': case 'X':
187: bcnt += 4;
188: break;
189: case 'e': case 'E': case 'f': case 'g': case 'G':
190: bcnt += 8;
191: break;
192: case 's':
193: bcnt += prec;
194: break;
195: case '_':
196: switch(*++fmt) {
197: case 'c': case 'p': case 'u':
198: bcnt += 1;
199: break;
200: }
201: }
202: }
203: cursize += bcnt * fu->reps;
204: }
1.9 pvalchev 205: return (cursize);
1.1 deraadt 206: }
207:
1.6 pvalchev 208: void
1.1 deraadt 209: rewrite(fs)
210: FS *fs;
211: {
212: enum { NOTOKAY, USEBCNT, USEPREC } sokay;
1.8 mpech 213: PR *pr, **nextpr;
214: FU *fu;
215: char *p1, *p2;
1.9 pvalchev 216: char savech, *fmtp, cs[3];
1.1 deraadt 217: int nconv, prec;
1.11 deraadt 218: size_t len;
1.1 deraadt 219:
1.9 pvalchev 220: nextpr = NULL;
221: prec = 0;
1.1 deraadt 222: for (fu = fs->nextfu; fu; fu = fu->nextfu) {
223: /*
1.9 pvalchev 224: * Break each format unit into print units; each conversion
225: * character gets its own.
1.1 deraadt 226: */
227: for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
1.9 pvalchev 228: pr = emalloc(sizeof(PR));
1.1 deraadt 229: if (!fu->nextpr)
230: fu->nextpr = pr;
231: else
232: *nextpr = pr;
233:
1.9 pvalchev 234: /* Skip preceding text and up to the next % sign. */
1.1 deraadt 235: for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
236:
1.9 pvalchev 237: /* Only text in the string. */
1.1 deraadt 238: if (!*p1) {
239: pr->fmt = fmtp;
240: pr->flags = F_TEXT;
241: break;
242: }
243:
244: /*
1.9 pvalchev 245: * Get precision for %s -- if have a byte count, don't
1.1 deraadt 246: * need it.
247: */
248: if (fu->bcnt) {
249: sokay = USEBCNT;
1.9 pvalchev 250: /* Skip to conversion character. */
1.3 millert 251: for (++p1; strchr(spec, *p1); ++p1);
1.1 deraadt 252: } else {
1.9 pvalchev 253: /* Skip any special chars, field width. */
1.3 millert 254: while (strchr(spec + 1, *++p1));
1.9 pvalchev 255: if (*p1 == '.' &&
256: isdigit((unsigned char)*++p1)) {
1.1 deraadt 257: sokay = USEPREC;
258: prec = atoi(p1);
1.9 pvalchev 259: while (isdigit((unsigned char)*++p1))
260: continue;
261: } else
1.1 deraadt 262: sokay = NOTOKAY;
263: }
264:
1.9 pvalchev 265: p2 = p1 + 1; /* Set end pointer. */
266: cs[0] = *p1; /* Set conversion string. */
267: cs[1] = '\0';
1.1 deraadt 268:
269: /*
1.9 pvalchev 270: * Figure out the byte count for each conversion;
1.1 deraadt 271: * rewrite the format as necessary, set up blank-
272: * padding for end of data.
273: */
1.9 pvalchev 274: switch(cs[0]) {
1.1 deraadt 275: case 'c':
276: pr->flags = F_CHAR;
277: switch(fu->bcnt) {
278: case 0: case 1:
279: pr->bcnt = 1;
280: break;
281: default:
1.9 pvalchev 282: p1[1] = '\0';
283: badcnt(p1);
1.1 deraadt 284: }
285: break;
286: case 'd': case 'i':
287: pr->flags = F_INT;
1.9 pvalchev 288: goto isint;
1.1 deraadt 289: case 'o': case 'u': case 'x': case 'X':
290: pr->flags = F_UINT;
1.9 pvalchev 291: isint: cs[2] = '\0';
292: cs[1] = cs[0];
293: cs[0] = 'q';
294: switch(fu->bcnt) {
1.1 deraadt 295: case 0: case 4:
296: pr->bcnt = 4;
297: break;
298: case 1:
299: pr->bcnt = 1;
300: break;
301: case 2:
302: pr->bcnt = 2;
303: break;
1.9 pvalchev 304: case 8:
305: pr->bcnt = 8;
306: break;
1.1 deraadt 307: default:
1.9 pvalchev 308: p1[1] = '\0';
309: badcnt(p1);
1.1 deraadt 310: }
311: break;
312: case 'e': case 'E': case 'f': case 'g': case 'G':
313: pr->flags = F_DBL;
314: switch(fu->bcnt) {
315: case 0: case 8:
316: pr->bcnt = 8;
317: break;
318: case 4:
319: pr->bcnt = 4;
320: break;
321: default:
1.9 pvalchev 322: p1[1] = '\0';
323: badcnt(p1);
1.1 deraadt 324: }
325: break;
326: case 's':
327: pr->flags = F_STR;
328: switch(sokay) {
329: case NOTOKAY:
1.9 pvalchev 330: badsfmt();
1.1 deraadt 331: case USEBCNT:
332: pr->bcnt = fu->bcnt;
333: break;
334: case USEPREC:
335: pr->bcnt = prec;
336: break;
337: }
338: break;
339: case '_':
340: ++p2;
341: switch(p1[1]) {
342: case 'A':
343: endfu = fu;
344: fu->flags |= F_IGNORE;
345: /* FALLTHROUGH */
346: case 'a':
347: pr->flags = F_ADDRESS;
348: ++p2;
349: switch(p1[2]) {
350: case 'd': case 'o': case'x':
1.9 pvalchev 351: cs[0] = 'q';
352: cs[1] = p1[2];
353: cs[2] = '\0';
1.1 deraadt 354: break;
355: default:
356: p1[3] = '\0';
1.9 pvalchev 357: badconv(p1);
1.1 deraadt 358: }
359: break;
360: case 'c':
361: pr->flags = F_C;
1.9 pvalchev 362: /* cs[0] = 'c'; set in conv_c */
363: goto isint2;
1.1 deraadt 364: case 'p':
365: pr->flags = F_P;
1.9 pvalchev 366: cs[0] = 'c';
367: goto isint2;
1.1 deraadt 368: case 'u':
369: pr->flags = F_U;
1.9 pvalchev 370: /* cs[0] = 'c'; set in conv_u */
371: isint2: switch(fu->bcnt) {
1.1 deraadt 372: case 0: case 1:
373: pr->bcnt = 1;
374: break;
375: default:
376: p1[2] = '\0';
1.9 pvalchev 377: badcnt(p1);
1.1 deraadt 378: }
379: break;
380: default:
381: p1[2] = '\0';
1.9 pvalchev 382: badconv(p1);
1.1 deraadt 383: }
384: break;
385: default:
1.9 pvalchev 386: p1[1] = '\0';
387: badconv(p1);
1.1 deraadt 388: }
389:
390: /*
1.9 pvalchev 391: * Copy to PR format string, set conversion character
1.1 deraadt 392: * pointer, update original.
393: */
394: savech = *p2;
1.9 pvalchev 395: p1[0] = '\0';
1.11 deraadt 396: len = strlen(fmtp) + strlen(cs) + 1;
397: pr->fmt = emalloc(len);
398: snprintf(pr->fmt, len, "%s%s", fmtp, cs);
1.1 deraadt 399: *p2 = savech;
400: pr->cchar = pr->fmt + (p1 - fmtp);
401: fmtp = p2;
402:
1.9 pvalchev 403: /* Only one conversion character if byte count. */
1.7 mickey 404: if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
405: errx(1,
1.9 pvalchev 406: "byte count with multiple conversion characters");
1.1 deraadt 407: }
408: /*
1.9 pvalchev 409: * If format unit byte count not specified, figure it out
1.1 deraadt 410: * so can adjust rep count later.
411: */
412: if (!fu->bcnt)
413: for (pr = fu->nextpr; pr; pr = pr->nextpr)
414: fu->bcnt += pr->bcnt;
415: }
416: /*
1.9 pvalchev 417: * If the format string interprets any data at all, and it's
1.1 deraadt 418: * not the same as the blocksize, and its last format unit
419: * interprets any data at all, and has no iteration count,
420: * repeat it as necessary.
421: *
1.9 pvalchev 422: * If, rep count is greater than 1, no trailing whitespace
1.1 deraadt 423: * gets output from the last iteration of the format unit.
424: */
1.9 pvalchev 425: for (fu = fs->nextfu; fu; fu = fu->nextfu) {
1.1 deraadt 426: if (!fu->nextfu && fs->bcnt < blocksize &&
427: !(fu->flags&F_SETREP) && fu->bcnt)
428: fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
429: if (fu->reps > 1) {
430: for (pr = fu->nextpr;; pr = pr->nextpr)
431: if (!pr->nextpr)
432: break;
433: for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
1.9 pvalchev 434: p2 = isspace((unsigned char)*p1) ? p1 : NULL;
1.1 deraadt 435: if (p2)
436: pr->nospace = p2;
437: }
438: }
1.9 pvalchev 439: #ifdef DEBUG
440: for (fu = fs->nextfu; fu; fu = fu->nextfu) {
441: (void)printf("fmt:");
442: for (pr = fu->nextpr; pr; pr = pr->nextpr)
443: (void)printf(" {%s}", pr->fmt);
444: (void)printf("\n");
445: }
446: #endif
1.1 deraadt 447: }
448:
1.6 pvalchev 449: void
1.1 deraadt 450: escape(p1)
1.8 mpech 451: char *p1;
1.1 deraadt 452: {
1.8 mpech 453: char *p2;
1.1 deraadt 454:
455: /* alphabetic escape sequences have to be done in place */
456: for (p2 = p1;; ++p1, ++p2) {
457: if (!*p1) {
458: *p2 = *p1;
459: break;
460: }
461: if (*p1 == '\\')
462: switch(*++p1) {
463: case 'a':
464: /* *p2 = '\a'; */
465: *p2 = '\007';
466: break;
467: case 'b':
468: *p2 = '\b';
469: break;
470: case 'f':
471: *p2 = '\f';
472: break;
473: case 'n':
474: *p2 = '\n';
475: break;
476: case 'r':
477: *p2 = '\r';
478: break;
479: case 't':
480: *p2 = '\t';
481: break;
482: case 'v':
483: *p2 = '\v';
484: break;
485: default:
486: *p2 = *p1;
487: break;
488: }
489: }
1.9 pvalchev 490: }
491:
492: void
493: badcnt(s)
494: char *s;
495: {
496: errx(1, "%s: bad byte count", s);
497: }
498:
499: void
500: badsfmt()
501: {
1.10 mpech 502: errx(1, "%%s: requires a precision or a byte count");
1.9 pvalchev 503: }
504:
505: void
506: badfmt(fmt)
507: const char *fmt;
508: {
1.10 mpech 509: errx(1, "\"%s\": bad format", fmt);
1.9 pvalchev 510: }
511:
512: void
513: badconv(ch)
514: char *ch;
515: {
1.10 mpech 516: errx(1, "%%%s: bad conversion character", ch);
1.1 deraadt 517: }