|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)parse.c 5.4 (Berkeley) 6/1/90";
22: #endif /* not lint */
23:
24: #include <sys/types.h>
25: #include <sys/file.h>
26: #include <stdio.h>
27: #include <ctype.h>
28: #include <string.h>
29: #include "hexdump.h"
30:
31: FU *endfu; /* format at end-of-data */
32:
33: addfile(name)
34: char *name;
35: {
36: register char *p;
37: FILE *fp;
38: int ch;
39: char buf[2048 + 1];
40:
41: if (!(fp = fopen(name, "r"))) {
42: (void)fprintf(stderr, "hexdump: can't read %s.\n", name);
43: exit(1);
44: }
45: while (fgets(buf, sizeof(buf), fp)) {
46: if (!(p = index(buf, '\n'))) {
47: (void)fprintf(stderr, "hexdump: line too long.\n");
48: while ((ch = getchar()) != '\n' && ch != EOF);
49: continue;
50: }
51: *p = '\0';
52: for (p = buf; *p && isspace(*p); ++p);
53: if (!*p || *p == '#')
54: continue;
55: add(p);
56: }
57: (void)fclose(fp);
58: }
59:
60: add(fmt)
61: char *fmt;
62: {
63: register char *p;
64: static FS **nextfs;
65: FS *tfs;
66: FU *tfu, **nextfu;
67: char savech, *savep, *emalloc(), *strdup();
68:
69: /* start new linked list of format units */
70: /* NOSTRICT */
71: tfs = (FS *)emalloc(sizeof(FS));
72: if (!fshead)
73: fshead = tfs;
74: else
75: *nextfs = tfs;
76: nextfs = &tfs->nextfs;
77: nextfu = &tfs->nextfu;
78:
79: /* take the format string and break it up into format units */
80: for (p = fmt;;) {
81: /* skip leading white space */
82: for (; isspace(*p); ++p);
83: if (!*p)
84: break;
85:
86: /* allocate a new format unit and link it in */
87: /* NOSTRICT */
88: tfu = (FU *)emalloc(sizeof(FU));
89: *nextfu = tfu;
90: nextfu = &tfu->nextfu;
91: tfu->reps = 1;
92:
93: /* if leading digit, repetition count */
94: if (isdigit(*p)) {
95: for (savep = p; isdigit(*p); ++p);
96: if (!isspace(*p) && *p != '/')
97: badfmt(fmt);
98: /* may overwrite either white space or slash */
99: savech = *p;
100: *p = '\0';
101: tfu->reps = atoi(savep);
102: tfu->flags = F_SETREP;
103: *p = savech;
104: /* skip trailing white space */
105: for (++p; isspace(*p); ++p);
106: }
107:
108: /* skip slash and trailing white space */
109: if (*p == '/')
110: while (isspace(*++p));
111:
112: /* byte count */
113: if (isdigit(*p)) {
114: for (savep = p; isdigit(*p); ++p);
115: if (!isspace(*p))
116: badfmt(fmt);
117: savech = *p;
118: *p = '\0';
119: tfu->bcnt = atoi(savep);
120: *p = savech;
121: /* skip trailing white space */
122: for (++p; isspace(*p); ++p);
123: }
124:
125: /* format */
126: if (*p != '"')
127: badfmt(fmt);
128: for (savep = ++p; *p != '"'; ++p);
129: if (*p != '"')
130: badfmt(fmt);
131: savech = *p;
132: *p = '\0';
133: if (!(tfu->fmt = strdup(savep)))
134: nomem();
135: escape(tfu->fmt);
136: *p++ = savech;
137: }
138: }
139:
140: static char *spec = ".#-+ 0123456789";
141: size(fs)
142: FS *fs;
143: {
144: register FU *fu;
145: register int bcnt, cursize;
146: register char *fmt;
147: int prec;
148:
149: /* figure out the data block size needed for each format unit */
150: for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
151: if (fu->bcnt) {
152: cursize += fu->bcnt * fu->reps;
153: continue;
154: }
155: for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
156: if (*fmt != '%')
157: continue;
158: /*
159: * skip any special chars -- save precision in
160: * case it's a %s format.
161: */
162: while (index(spec + 1, *++fmt));
163: if (*fmt == '.' && isdigit(*++fmt)) {
164: prec = atoi(fmt);
165: while (isdigit(*++fmt));
166: }
167: switch(*fmt) {
168: case 'c':
169: bcnt += 1;
170: break;
171: case 'd': case 'i': case 'o': case 'u':
172: case 'x': case 'X':
173: bcnt += 4;
174: break;
175: case 'e': case 'E': case 'f': case 'g': case 'G':
176: bcnt += 8;
177: break;
178: case 's':
179: bcnt += prec;
180: break;
181: case '_':
182: switch(*++fmt) {
183: case 'c': case 'p': case 'u':
184: bcnt += 1;
185: break;
186: }
187: }
188: }
189: cursize += bcnt * fu->reps;
190: }
191: return(cursize);
192: }
193:
194: rewrite(fs)
195: FS *fs;
196: {
197: enum { NOTOKAY, USEBCNT, USEPREC } sokay;
198: register PR *pr, **nextpr;
199: register FU *fu;
200: register char *p1, *p2;
201: char savech, *fmtp;
202: int nconv, prec;
203:
204: for (fu = fs->nextfu; fu; fu = fu->nextfu) {
205: /*
206: * break each format unit into print units; each
207: * conversion character gets its own.
208: */
209: for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
210: /* NOSTRICT */
211: pr = (PR *)emalloc(sizeof(PR));
212: if (!fu->nextpr)
213: fu->nextpr = pr;
214: else
215: *nextpr = pr;
216:
217: /* skip preceding text and up to the next % sign */
218: for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
219:
220: /* only text in the string */
221: if (!*p1) {
222: pr->fmt = fmtp;
223: pr->flags = F_TEXT;
224: break;
225: }
226:
227: /*
228: * get precision for %s -- if have a byte count, don't
229: * need it.
230: */
231: if (fu->bcnt) {
232: sokay = USEBCNT;
233: /* skip to conversion character */
234: for (++p1; index(spec, *p1); ++p1);
235: } else {
236: /* skip any special chars, field width */
237: while (index(spec + 1, *++p1));
238: if (*p1 == '.' && isdigit(*++p1)) {
239: sokay = USEPREC;
240: prec = atoi(p1);
241: while (isdigit(*++p1));
242: }
243: else
244: sokay = NOTOKAY;
245: }
246:
247: p2 = p1 + 1; /* set end pointer */
248:
249: /*
250: * figure out the byte count for each conversion;
251: * rewrite the format as necessary, set up blank-
252: * padding for end of data.
253: */
254: switch(*p1) {
255: case 'c':
256: pr->flags = F_CHAR;
257: switch(fu->bcnt) {
258: case 0: case 1:
259: pr->bcnt = 1;
260: break;
261: default:
262: p1[1] = '\0';
263: badcnt(p1);
264: }
265: break;
266: case 'd': case 'i':
267: pr->flags = F_INT;
268: goto sw1;
269: case 'l':
270: ++p2;
271: switch(p1[1]) {
272: case 'd': case 'i':
273: ++p1;
274: pr->flags = F_INT;
275: goto sw1;
276: case 'o': case 'u': case 'x': case 'X':
277: ++p1;
278: pr->flags = F_UINT;
279: goto sw1;
280: default:
281: p1[2] = '\0';
282: badconv(p1);
283: }
284: /* NOTREACHED */
285: case 'o': case 'u': case 'x': case 'X':
286: pr->flags = F_UINT;
287: sw1: switch(fu->bcnt) {
288: case 0: case 4:
289: pr->bcnt = 4;
290: break;
291: case 1:
292: pr->bcnt = 1;
293: break;
294: case 2:
295: pr->bcnt = 2;
296: break;
297: default:
298: p1[1] = '\0';
299: badcnt(p1);
300: }
301: break;
302: case 'e': case 'E': case 'f': case 'g': case 'G':
303: pr->flags = F_DBL;
304: switch(fu->bcnt) {
305: case 0: case 8:
306: pr->bcnt = 8;
307: break;
308: case 4:
309: pr->bcnt = 4;
310: break;
311: default:
312: p1[1] = '\0';
313: badcnt(p1);
314: }
315: break;
316: case 's':
317: pr->flags = F_STR;
318: switch(sokay) {
319: case NOTOKAY:
320: badsfmt();
321: case USEBCNT:
322: pr->bcnt = fu->bcnt;
323: break;
324: case USEPREC:
325: pr->bcnt = prec;
326: break;
327: }
328: break;
329: case '_':
330: ++p2;
331: switch(p1[1]) {
332: case 'A':
333: endfu = fu;
334: fu->flags |= F_IGNORE;
335: /* FALLTHROUGH */
336: case 'a':
337: pr->flags = F_ADDRESS;
338: ++p2;
339: switch(p1[2]) {
340: case 'd': case 'o': case'x':
341: *p1 = p1[2];
342: break;
343: default:
344: p1[3] = '\0';
345: badconv(p1);
346: }
347: break;
348: case 'c':
349: pr->flags = F_C;
350: /* *p1 = 'c'; set in conv_c */
351: goto sw2;
352: case 'p':
353: pr->flags = F_P;
354: *p1 = 'c';
355: goto sw2;
356: case 'u':
357: pr->flags = F_U;
358: /* *p1 = 'c'; set in conv_u */
359: sw2: switch(fu->bcnt) {
360: case 0: case 1:
361: pr->bcnt = 1;
362: break;
363: default:
364: p1[2] = '\0';
365: badcnt(p1);
366: }
367: break;
368: default:
369: p1[2] = '\0';
370: badconv(p1);
371: }
372: break;
373: default:
374: p1[1] = '\0';
375: badconv(p1);
376: }
377:
378: /*
379: * copy to PR format string, set conversion character
380: * pointer, update original.
381: */
382: savech = *p2;
383: p1[1] = '\0';
384: if (!(pr->fmt = strdup(fmtp)))
385: nomem();
386: *p2 = savech;
387: pr->cchar = pr->fmt + (p1 - fmtp);
388: fmtp = p2;
389:
390: /* only one conversion character if byte count */
391: if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) {
392: (void)fprintf(stderr,
393: "hexdump: byte count with multiple conversion characters.\n");
394: exit(1);
395: }
396: }
397: /*
398: * if format unit byte count not specified, figure it out
399: * so can adjust rep count later.
400: */
401: if (!fu->bcnt)
402: for (pr = fu->nextpr; pr; pr = pr->nextpr)
403: fu->bcnt += pr->bcnt;
404: }
405: /*
406: * if the format string interprets any data at all, and it's
407: * not the same as the blocksize, and its last format unit
408: * interprets any data at all, and has no iteration count,
409: * repeat it as necessary.
410: *
411: * if, rep count is greater than 1, no trailing whitespace
412: * gets output from the last iteration of the format unit.
413: */
414: for (fu = fs->nextfu;; fu = fu->nextfu) {
415: if (!fu->nextfu && fs->bcnt < blocksize &&
416: !(fu->flags&F_SETREP) && fu->bcnt)
417: fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
418: if (fu->reps > 1) {
419: for (pr = fu->nextpr;; pr = pr->nextpr)
420: if (!pr->nextpr)
421: break;
422: for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
423: p2 = isspace(*p1) ? p1 : NULL;
424: if (p2)
425: pr->nospace = p2;
426: }
427: if (!fu->nextfu)
428: break;
429: }
430: }
431:
432:
433: escape(p1)
434: register char *p1;
435: {
436: register char *p2;
437:
438: /* alphabetic escape sequences have to be done in place */
439: for (p2 = p1;; ++p1, ++p2) {
440: if (!*p1) {
441: *p2 = *p1;
442: break;
443: }
444: if (*p1 == '\\')
445: switch(*++p1) {
446: case 'a':
447: /* *p2 = '\a'; */
448: *p2 = '\007';
449: break;
450: case 'b':
451: *p2 = '\b';
452: break;
453: case 'f':
454: *p2 = '\f';
455: break;
456: case 'n':
457: *p2 = '\n';
458: break;
459: case 'r':
460: *p2 = '\r';
461: break;
462: case 't':
463: *p2 = '\t';
464: break;
465: case 'v':
466: *p2 = '\v';
467: break;
468: default:
469: *p2 = *p1;
470: break;
471: }
472: }
473: }
474:
475: badcnt(s)
476: char *s;
477: {
478: (void)fprintf(stderr,
479: "hexdump: bad byte count for conversion character %s.\n", s);
480: exit(1);
481: }
482:
483: badsfmt()
484: {
485: (void)fprintf(stderr,
486: "hexdump: %%s requires a precision or a byte count.\n");
487: exit(1);
488: }
489:
490: badfmt(fmt)
491: char *fmt;
492: {
493: (void)fprintf(stderr, "hexdump: bad format {%s}\n", fmt);
494: exit(1);
495: }
496:
497: badconv(ch)
498: char *ch;
499: {
500: (void)fprintf(stderr, "hexdump: bad conversion character %%%s.\n", ch);
501: exit(1);
502: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.