parse.c revision 1590
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1989, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimesstatic char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; 361590Srgrimes#endif /* not lint */ 371590Srgrimes 381590Srgrimes#include <sys/types.h> 391590Srgrimes 401590Srgrimes#include <errno.h> 411590Srgrimes#include <fcntl.h> 421590Srgrimes#include <stdio.h> 431590Srgrimes#include <stdlib.h> 441590Srgrimes#include <ctype.h> 451590Srgrimes#include <string.h> 461590Srgrimes#include "hexdump.h" 471590Srgrimes 481590SrgrimesFU *endfu; /* format at end-of-data */ 491590Srgrimes 501590Srgrimesvoid 511590Srgrimesaddfile(name) 521590Srgrimes char *name; 531590Srgrimes{ 541590Srgrimes register char *p; 551590Srgrimes FILE *fp; 561590Srgrimes int ch; 571590Srgrimes char buf[2048 + 1]; 581590Srgrimes 591590Srgrimes if ((fp = fopen(name, "r")) == NULL) 601590Srgrimes err("%s: %s\n", name, strerror(errno)); 611590Srgrimes while (fgets(buf, sizeof(buf), fp)) { 621590Srgrimes if (!(p = index(buf, '\n'))) { 631590Srgrimes (void)fprintf(stderr, "hexdump: line too long.\n"); 641590Srgrimes while ((ch = getchar()) != '\n' && ch != EOF); 651590Srgrimes continue; 661590Srgrimes } 671590Srgrimes *p = '\0'; 681590Srgrimes for (p = buf; *p && isspace(*p); ++p); 691590Srgrimes if (!*p || *p == '#') 701590Srgrimes continue; 711590Srgrimes add(p); 721590Srgrimes } 731590Srgrimes (void)fclose(fp); 741590Srgrimes} 751590Srgrimes 761590Srgrimesvoid 771590Srgrimesadd(fmt) 781590Srgrimes char *fmt; 791590Srgrimes{ 801590Srgrimes register char *p; 811590Srgrimes static FS **nextfs; 821590Srgrimes FS *tfs; 831590Srgrimes FU *tfu, **nextfu; 841590Srgrimes char *savep; 851590Srgrimes 861590Srgrimes /* start new linked list of format units */ 871590Srgrimes tfs = emalloc(sizeof(FS)); 881590Srgrimes if (!fshead) 891590Srgrimes fshead = tfs; 901590Srgrimes else 911590Srgrimes *nextfs = tfs; 921590Srgrimes nextfs = &tfs->nextfs; 931590Srgrimes nextfu = &tfs->nextfu; 941590Srgrimes 951590Srgrimes /* take the format string and break it up into format units */ 961590Srgrimes for (p = fmt;;) { 971590Srgrimes /* skip leading white space */ 981590Srgrimes for (; isspace(*p); ++p); 991590Srgrimes if (!*p) 1001590Srgrimes break; 1011590Srgrimes 1021590Srgrimes /* allocate a new format unit and link it in */ 1031590Srgrimes tfu = emalloc(sizeof(FU)); 1041590Srgrimes *nextfu = tfu; 1051590Srgrimes nextfu = &tfu->nextfu; 1061590Srgrimes tfu->reps = 1; 1071590Srgrimes 1081590Srgrimes /* if leading digit, repetition count */ 1091590Srgrimes if (isdigit(*p)) { 1101590Srgrimes for (savep = p; isdigit(*p); ++p); 1111590Srgrimes if (!isspace(*p) && *p != '/') 1121590Srgrimes badfmt(fmt); 1131590Srgrimes /* may overwrite either white space or slash */ 1141590Srgrimes tfu->reps = atoi(savep); 1151590Srgrimes tfu->flags = F_SETREP; 1161590Srgrimes /* skip trailing white space */ 1171590Srgrimes for (++p; isspace(*p); ++p); 1181590Srgrimes } 1191590Srgrimes 1201590Srgrimes /* skip slash and trailing white space */ 1211590Srgrimes if (*p == '/') 1221590Srgrimes while (isspace(*++p)); 1231590Srgrimes 1241590Srgrimes /* byte count */ 1251590Srgrimes if (isdigit(*p)) { 1261590Srgrimes for (savep = p; isdigit(*p); ++p); 1271590Srgrimes if (!isspace(*p)) 1281590Srgrimes badfmt(fmt); 1291590Srgrimes tfu->bcnt = atoi(savep); 1301590Srgrimes /* skip trailing white space */ 1311590Srgrimes for (++p; isspace(*p); ++p); 1321590Srgrimes } 1331590Srgrimes 1341590Srgrimes /* format */ 1351590Srgrimes if (*p != '"') 1361590Srgrimes badfmt(fmt); 1371590Srgrimes for (savep = ++p; *p != '"';) 1381590Srgrimes if (*p++ == 0) 1391590Srgrimes badfmt(fmt); 1401590Srgrimes if (!(tfu->fmt = malloc(p - savep + 1))) 1411590Srgrimes nomem(); 1421590Srgrimes (void) strncpy(tfu->fmt, savep, p - savep); 1431590Srgrimes tfu->fmt[p - savep] = '\0'; 1441590Srgrimes escape(tfu->fmt); 1451590Srgrimes p++; 1461590Srgrimes } 1471590Srgrimes} 1481590Srgrimes 1491590Srgrimesstatic char *spec = ".#-+ 0123456789"; 1501590Srgrimes 1511590Srgrimesint 1521590Srgrimessize(fs) 1531590Srgrimes FS *fs; 1541590Srgrimes{ 1551590Srgrimes register FU *fu; 1561590Srgrimes register int bcnt, cursize; 1571590Srgrimes register char *fmt; 1581590Srgrimes int prec; 1591590Srgrimes 1601590Srgrimes /* figure out the data block size needed for each format unit */ 1611590Srgrimes for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { 1621590Srgrimes if (fu->bcnt) { 1631590Srgrimes cursize += fu->bcnt * fu->reps; 1641590Srgrimes continue; 1651590Srgrimes } 1661590Srgrimes for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { 1671590Srgrimes if (*fmt != '%') 1681590Srgrimes continue; 1691590Srgrimes /* 1701590Srgrimes * skip any special chars -- save precision in 1711590Srgrimes * case it's a %s format. 1721590Srgrimes */ 1731590Srgrimes while (index(spec + 1, *++fmt)); 1741590Srgrimes if (*fmt == '.' && isdigit(*++fmt)) { 1751590Srgrimes prec = atoi(fmt); 1761590Srgrimes while (isdigit(*++fmt)); 1771590Srgrimes } 1781590Srgrimes switch(*fmt) { 1791590Srgrimes case 'c': 1801590Srgrimes bcnt += 1; 1811590Srgrimes break; 1821590Srgrimes case 'd': case 'i': case 'o': case 'u': 1831590Srgrimes case 'x': case 'X': 1841590Srgrimes bcnt += 4; 1851590Srgrimes break; 1861590Srgrimes case 'e': case 'E': case 'f': case 'g': case 'G': 1871590Srgrimes bcnt += 8; 1881590Srgrimes break; 1891590Srgrimes case 's': 1901590Srgrimes bcnt += prec; 1911590Srgrimes break; 1921590Srgrimes case '_': 1931590Srgrimes switch(*++fmt) { 1941590Srgrimes case 'c': case 'p': case 'u': 1951590Srgrimes bcnt += 1; 1961590Srgrimes break; 1971590Srgrimes } 1981590Srgrimes } 1991590Srgrimes } 2001590Srgrimes cursize += bcnt * fu->reps; 2011590Srgrimes } 2021590Srgrimes return (cursize); 2031590Srgrimes} 2041590Srgrimes 2051590Srgrimesvoid 2061590Srgrimesrewrite(fs) 2071590Srgrimes FS *fs; 2081590Srgrimes{ 2091590Srgrimes enum { NOTOKAY, USEBCNT, USEPREC } sokay; 2101590Srgrimes register PR *pr, **nextpr; 2111590Srgrimes register FU *fu; 2121590Srgrimes register char *p1, *p2; 2131590Srgrimes char savech, *fmtp, cs[3]; 2141590Srgrimes int nconv, prec; 2151590Srgrimes 2161590Srgrimes for (fu = fs->nextfu; fu; fu = fu->nextfu) { 2171590Srgrimes /* 2181590Srgrimes * Break each format unit into print units; each conversion 2191590Srgrimes * character gets its own. 2201590Srgrimes */ 2211590Srgrimes for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 2221590Srgrimes pr = emalloc(sizeof(PR)); 2231590Srgrimes if (!fu->nextpr) 2241590Srgrimes fu->nextpr = pr; 2251590Srgrimes else 2261590Srgrimes *nextpr = pr; 2271590Srgrimes 2281590Srgrimes /* Skip preceding text and up to the next % sign. */ 2291590Srgrimes for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); 2301590Srgrimes 2311590Srgrimes /* Only text in the string. */ 2321590Srgrimes if (!*p1) { 2331590Srgrimes pr->fmt = fmtp; 2341590Srgrimes pr->flags = F_TEXT; 2351590Srgrimes break; 2361590Srgrimes } 2371590Srgrimes 2381590Srgrimes /* 2391590Srgrimes * Get precision for %s -- if have a byte count, don't 2401590Srgrimes * need it. 2411590Srgrimes */ 2421590Srgrimes if (fu->bcnt) { 2431590Srgrimes sokay = USEBCNT; 2441590Srgrimes /* Skip to conversion character. */ 2451590Srgrimes for (++p1; index(spec, *p1); ++p1); 2461590Srgrimes } else { 2471590Srgrimes /* Skip any special chars, field width. */ 2481590Srgrimes while (index(spec + 1, *++p1)); 2491590Srgrimes if (*p1 == '.' && isdigit(*++p1)) { 2501590Srgrimes sokay = USEPREC; 2511590Srgrimes prec = atoi(p1); 2521590Srgrimes while (isdigit(*++p1)); 2531590Srgrimes } else 2541590Srgrimes sokay = NOTOKAY; 2551590Srgrimes } 2561590Srgrimes 2571590Srgrimes p2 = p1 + 1; /* Set end pointer. */ 2581590Srgrimes cs[0] = *p1; /* Set conversion string. */ 2591590Srgrimes cs[1] = '\0'; 2601590Srgrimes 2611590Srgrimes /* 2621590Srgrimes * Figure out the byte count for each conversion; 2631590Srgrimes * rewrite the format as necessary, set up blank- 2641590Srgrimes * padding for end of data. 2651590Srgrimes */ 2661590Srgrimes switch(cs[0]) { 2671590Srgrimes case 'c': 2681590Srgrimes pr->flags = F_CHAR; 2691590Srgrimes switch(fu->bcnt) { 2701590Srgrimes case 0: case 1: 2711590Srgrimes pr->bcnt = 1; 2721590Srgrimes break; 2731590Srgrimes default: 2741590Srgrimes p1[1] = '\0'; 2751590Srgrimes badcnt(p1); 2761590Srgrimes } 2771590Srgrimes break; 2781590Srgrimes case 'd': case 'i': 2791590Srgrimes pr->flags = F_INT; 2801590Srgrimes goto isint; 2811590Srgrimes case 'o': case 'u': case 'x': case 'X': 2821590Srgrimes pr->flags = F_UINT; 2831590Srgrimesisint: cs[2] = '\0'; 2841590Srgrimes cs[1] = cs[0]; 2851590Srgrimes cs[0] = 'q'; 2861590Srgrimes switch(fu->bcnt) { 2871590Srgrimes case 0: case 4: 2881590Srgrimes pr->bcnt = 4; 2891590Srgrimes break; 2901590Srgrimes case 1: 2911590Srgrimes pr->bcnt = 1; 2921590Srgrimes break; 2931590Srgrimes case 2: 2941590Srgrimes pr->bcnt = 2; 2951590Srgrimes break; 2961590Srgrimes default: 2971590Srgrimes p1[1] = '\0'; 2981590Srgrimes badcnt(p1); 2991590Srgrimes } 3001590Srgrimes break; 3011590Srgrimes case 'e': case 'E': case 'f': case 'g': case 'G': 3021590Srgrimes pr->flags = F_DBL; 3031590Srgrimes switch(fu->bcnt) { 3041590Srgrimes case 0: case 8: 3051590Srgrimes pr->bcnt = 8; 3061590Srgrimes break; 3071590Srgrimes case 4: 3081590Srgrimes pr->bcnt = 4; 3091590Srgrimes break; 3101590Srgrimes default: 3111590Srgrimes p1[1] = '\0'; 3121590Srgrimes badcnt(p1); 3131590Srgrimes } 3141590Srgrimes break; 3151590Srgrimes case 's': 3161590Srgrimes pr->flags = F_STR; 3171590Srgrimes switch(sokay) { 3181590Srgrimes case NOTOKAY: 3191590Srgrimes badsfmt(); 3201590Srgrimes case USEBCNT: 3211590Srgrimes pr->bcnt = fu->bcnt; 3221590Srgrimes break; 3231590Srgrimes case USEPREC: 3241590Srgrimes pr->bcnt = prec; 3251590Srgrimes break; 3261590Srgrimes } 3271590Srgrimes break; 3281590Srgrimes case '_': 3291590Srgrimes ++p2; 3301590Srgrimes switch(p1[1]) { 3311590Srgrimes case 'A': 3321590Srgrimes endfu = fu; 3331590Srgrimes fu->flags |= F_IGNORE; 3341590Srgrimes /* FALLTHROUGH */ 3351590Srgrimes case 'a': 3361590Srgrimes pr->flags = F_ADDRESS; 3371590Srgrimes ++p2; 3381590Srgrimes switch(p1[2]) { 3391590Srgrimes case 'd': case 'o': case'x': 3401590Srgrimes cs[0] = 'q'; 3411590Srgrimes cs[1] = p1[2]; 3421590Srgrimes cs[2] = '\0'; 3431590Srgrimes break; 3441590Srgrimes default: 3451590Srgrimes p1[3] = '\0'; 3461590Srgrimes badconv(p1); 3471590Srgrimes } 3481590Srgrimes break; 3491590Srgrimes case 'c': 3501590Srgrimes pr->flags = F_C; 3511590Srgrimes /* cs[0] = 'c'; set in conv_c */ 3521590Srgrimes goto isint2; 3531590Srgrimes case 'p': 3541590Srgrimes pr->flags = F_P; 3551590Srgrimes cs[0] = 'c'; 3561590Srgrimes goto isint2; 3571590Srgrimes case 'u': 3581590Srgrimes pr->flags = F_U; 3591590Srgrimes /* cs[0] = 'c'; set in conv_u */ 3601590Srgrimesisint2: switch(fu->bcnt) { 3611590Srgrimes case 0: case 1: 3621590Srgrimes pr->bcnt = 1; 3631590Srgrimes break; 3641590Srgrimes default: 3651590Srgrimes p1[2] = '\0'; 3661590Srgrimes badcnt(p1); 3671590Srgrimes } 3681590Srgrimes break; 3691590Srgrimes default: 3701590Srgrimes p1[2] = '\0'; 3711590Srgrimes badconv(p1); 3721590Srgrimes } 3731590Srgrimes break; 3741590Srgrimes default: 3751590Srgrimes p1[1] = '\0'; 3761590Srgrimes badconv(p1); 3771590Srgrimes } 3781590Srgrimes 3791590Srgrimes /* 3801590Srgrimes * Copy to PR format string, set conversion character 3811590Srgrimes * pointer, update original. 3821590Srgrimes */ 3831590Srgrimes savech = *p2; 3841590Srgrimes p1[0] = '\0'; 3851590Srgrimes pr->fmt = emalloc(strlen(fmtp) + 2); 3861590Srgrimes (void)strcpy(pr->fmt, fmtp); 3871590Srgrimes (void)strcat(pr->fmt, cs); 3881590Srgrimes *p2 = savech; 3891590Srgrimes pr->cchar = pr->fmt + (p1 - fmtp); 3901590Srgrimes fmtp = p2; 3911590Srgrimes 3921590Srgrimes /* Only one conversion character if byte count. */ 3931590Srgrimes if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) 3941590Srgrimes err("byte count with multiple conversion characters"); 3951590Srgrimes } 3961590Srgrimes /* 3971590Srgrimes * If format unit byte count not specified, figure it out 3981590Srgrimes * so can adjust rep count later. 3991590Srgrimes */ 4001590Srgrimes if (!fu->bcnt) 4011590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4021590Srgrimes fu->bcnt += pr->bcnt; 4031590Srgrimes } 4041590Srgrimes /* 4051590Srgrimes * If the format string interprets any data at all, and it's 4061590Srgrimes * not the same as the blocksize, and its last format unit 4071590Srgrimes * interprets any data at all, and has no iteration count, 4081590Srgrimes * repeat it as necessary. 4091590Srgrimes * 4101590Srgrimes * If, rep count is greater than 1, no trailing whitespace 4111590Srgrimes * gets output from the last iteration of the format unit. 4121590Srgrimes */ 4131590Srgrimes for (fu = fs->nextfu;; fu = fu->nextfu) { 4141590Srgrimes if (!fu->nextfu && fs->bcnt < blocksize && 4151590Srgrimes !(fu->flags&F_SETREP) && fu->bcnt) 4161590Srgrimes fu->reps += (blocksize - fs->bcnt) / fu->bcnt; 4171590Srgrimes if (fu->reps > 1) { 4181590Srgrimes for (pr = fu->nextpr;; pr = pr->nextpr) 4191590Srgrimes if (!pr->nextpr) 4201590Srgrimes break; 4211590Srgrimes for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 4221590Srgrimes p2 = isspace(*p1) ? p1 : NULL; 4231590Srgrimes if (p2) 4241590Srgrimes pr->nospace = p2; 4251590Srgrimes } 4261590Srgrimes if (!fu->nextfu) 4271590Srgrimes break; 4281590Srgrimes } 4291590Srgrimes#ifdef DEBUG 4301590Srgrimes for (fu = fs->nextfu; fu; fu = fu->nextfu) { 4311590Srgrimes (void)printf("fmt:"); 4321590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4331590Srgrimes (void)printf(" {%s}", pr->fmt); 4341590Srgrimes (void)printf("\n"); 4351590Srgrimes } 4361590Srgrimes#endif 4371590Srgrimes} 4381590Srgrimes 4391590Srgrimesvoid 4401590Srgrimesescape(p1) 4411590Srgrimes register char *p1; 4421590Srgrimes{ 4431590Srgrimes register char *p2; 4441590Srgrimes 4451590Srgrimes /* alphabetic escape sequences have to be done in place */ 4461590Srgrimes for (p2 = p1;; ++p1, ++p2) { 4471590Srgrimes if (!*p1) { 4481590Srgrimes *p2 = *p1; 4491590Srgrimes break; 4501590Srgrimes } 4511590Srgrimes if (*p1 == '\\') 4521590Srgrimes switch(*++p1) { 4531590Srgrimes case 'a': 4541590Srgrimes /* *p2 = '\a'; */ 4551590Srgrimes *p2 = '\007'; 4561590Srgrimes break; 4571590Srgrimes case 'b': 4581590Srgrimes *p2 = '\b'; 4591590Srgrimes break; 4601590Srgrimes case 'f': 4611590Srgrimes *p2 = '\f'; 4621590Srgrimes break; 4631590Srgrimes case 'n': 4641590Srgrimes *p2 = '\n'; 4651590Srgrimes break; 4661590Srgrimes case 'r': 4671590Srgrimes *p2 = '\r'; 4681590Srgrimes break; 4691590Srgrimes case 't': 4701590Srgrimes *p2 = '\t'; 4711590Srgrimes break; 4721590Srgrimes case 'v': 4731590Srgrimes *p2 = '\v'; 4741590Srgrimes break; 4751590Srgrimes default: 4761590Srgrimes *p2 = *p1; 4771590Srgrimes break; 4781590Srgrimes } 4791590Srgrimes } 4801590Srgrimes} 4811590Srgrimes 4821590Srgrimesvoid 4831590Srgrimesbadcnt(s) 4841590Srgrimes char *s; 4851590Srgrimes{ 4861590Srgrimes err("%s: bad byte count", s); 4871590Srgrimes} 4881590Srgrimes 4891590Srgrimesvoid 4901590Srgrimesbadsfmt() 4911590Srgrimes{ 4921590Srgrimes err("%%s: requires a precision or a byte count\n"); 4931590Srgrimes} 4941590Srgrimes 4951590Srgrimesvoid 4961590Srgrimesbadfmt(fmt) 4971590Srgrimes char *fmt; 4981590Srgrimes{ 4991590Srgrimes err("\"%s\": bad format\n", fmt); 5001590Srgrimes} 5011590Srgrimes 5021590Srgrimesvoid 5031590Srgrimesbadconv(ch) 5041590Srgrimes char *ch; 5051590Srgrimes{ 5061590Srgrimes err("%%%s: bad conversion character\n", ch); 5071590Srgrimes} 508