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