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