parse.c revision 80290
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 3527315Scharnier#if 0 361590Srgrimesstatic char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; 3727315Scharnier#endif 3827315Scharnierstatic const char rcsid[] = 3950477Speter "$FreeBSD: head/usr.bin/hexdump/parse.c 80290 2001-07-24 14:11:09Z obrien $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes#include <sys/types.h> 431590Srgrimes 4427315Scharnier#include <err.h> 451590Srgrimes#include <fcntl.h> 461590Srgrimes#include <stdio.h> 471590Srgrimes#include <stdlib.h> 481590Srgrimes#include <ctype.h> 491590Srgrimes#include <string.h> 501590Srgrimes#include "hexdump.h" 511590Srgrimes 521590SrgrimesFU *endfu; /* format at end-of-data */ 531590Srgrimes 541590Srgrimesvoid 551590Srgrimesaddfile(name) 561590Srgrimes char *name; 571590Srgrimes{ 5830921Sache register unsigned char *p; 591590Srgrimes FILE *fp; 601590Srgrimes int ch; 611590Srgrimes char buf[2048 + 1]; 621590Srgrimes 631590Srgrimes if ((fp = fopen(name, "r")) == NULL) 6427315Scharnier err(1, "%s", name); 651590Srgrimes while (fgets(buf, sizeof(buf), fp)) { 661590Srgrimes if (!(p = index(buf, '\n'))) { 6727315Scharnier warnx("line too long"); 681590Srgrimes while ((ch = getchar()) != '\n' && ch != EOF); 691590Srgrimes continue; 701590Srgrimes } 711590Srgrimes *p = '\0'; 721590Srgrimes for (p = buf; *p && isspace(*p); ++p); 731590Srgrimes if (!*p || *p == '#') 741590Srgrimes continue; 751590Srgrimes add(p); 761590Srgrimes } 771590Srgrimes (void)fclose(fp); 781590Srgrimes} 791590Srgrimes 801590Srgrimesvoid 811590Srgrimesadd(fmt) 821590Srgrimes char *fmt; 831590Srgrimes{ 8430921Sache unsigned char *p, *savep; 851590Srgrimes static FS **nextfs; 861590Srgrimes FS *tfs; 871590Srgrimes FU *tfu, **nextfu; 881590Srgrimes 891590Srgrimes /* start new linked list of format units */ 9080290Sobrien if ((tfs = calloc(1, sizeof(FS))) == NULL) 9180290Sobrien err(1, NULL); 921590Srgrimes if (!fshead) 931590Srgrimes fshead = tfs; 941590Srgrimes else 951590Srgrimes *nextfs = tfs; 961590Srgrimes nextfs = &tfs->nextfs; 971590Srgrimes nextfu = &tfs->nextfu; 981590Srgrimes 991590Srgrimes /* take the format string and break it up into format units */ 1001590Srgrimes for (p = fmt;;) { 1011590Srgrimes /* skip leading white space */ 1021590Srgrimes for (; isspace(*p); ++p); 1031590Srgrimes if (!*p) 1041590Srgrimes break; 1051590Srgrimes 1061590Srgrimes /* allocate a new format unit and link it in */ 10780290Sobrien if ((tfu = calloc(1, sizeof(FU))) == NULL) 10880290Sobrien err(1, NULL); 1091590Srgrimes *nextfu = tfu; 1101590Srgrimes nextfu = &tfu->nextfu; 1111590Srgrimes tfu->reps = 1; 1121590Srgrimes 1131590Srgrimes /* if leading digit, repetition count */ 1141590Srgrimes if (isdigit(*p)) { 1151590Srgrimes for (savep = p; isdigit(*p); ++p); 1161590Srgrimes if (!isspace(*p) && *p != '/') 1171590Srgrimes badfmt(fmt); 1181590Srgrimes /* may overwrite either white space or slash */ 1191590Srgrimes tfu->reps = atoi(savep); 1201590Srgrimes tfu->flags = F_SETREP; 1211590Srgrimes /* skip trailing white space */ 1221590Srgrimes for (++p; isspace(*p); ++p); 1231590Srgrimes } 1241590Srgrimes 1251590Srgrimes /* skip slash and trailing white space */ 1261590Srgrimes if (*p == '/') 1271590Srgrimes while (isspace(*++p)); 1281590Srgrimes 1291590Srgrimes /* byte count */ 1301590Srgrimes if (isdigit(*p)) { 1311590Srgrimes for (savep = p; isdigit(*p); ++p); 1321590Srgrimes if (!isspace(*p)) 1331590Srgrimes badfmt(fmt); 1341590Srgrimes tfu->bcnt = atoi(savep); 1351590Srgrimes /* skip trailing white space */ 1361590Srgrimes for (++p; isspace(*p); ++p); 1371590Srgrimes } 1381590Srgrimes 1391590Srgrimes /* format */ 1401590Srgrimes if (*p != '"') 1411590Srgrimes badfmt(fmt); 1421590Srgrimes for (savep = ++p; *p != '"';) 1431590Srgrimes if (*p++ == 0) 1441590Srgrimes badfmt(fmt); 1451590Srgrimes if (!(tfu->fmt = malloc(p - savep + 1))) 14680290Sobrien err(1, NULL); 1471590Srgrimes (void) strncpy(tfu->fmt, savep, p - savep); 1481590Srgrimes tfu->fmt[p - savep] = '\0'; 1491590Srgrimes escape(tfu->fmt); 1501590Srgrimes p++; 1511590Srgrimes } 1521590Srgrimes} 1531590Srgrimes 1541590Srgrimesstatic char *spec = ".#-+ 0123456789"; 1551590Srgrimes 1561590Srgrimesint 1571590Srgrimessize(fs) 1581590Srgrimes FS *fs; 1591590Srgrimes{ 1601590Srgrimes register FU *fu; 1611590Srgrimes register int bcnt, cursize; 16230921Sache register unsigned char *fmt; 1631590Srgrimes int prec; 1641590Srgrimes 1651590Srgrimes /* figure out the data block size needed for each format unit */ 1661590Srgrimes for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { 1671590Srgrimes if (fu->bcnt) { 1681590Srgrimes cursize += fu->bcnt * fu->reps; 1691590Srgrimes continue; 1701590Srgrimes } 1711590Srgrimes for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { 1721590Srgrimes if (*fmt != '%') 1731590Srgrimes continue; 1741590Srgrimes /* 1751590Srgrimes * skip any special chars -- save precision in 1761590Srgrimes * case it's a %s format. 1771590Srgrimes */ 1781590Srgrimes while (index(spec + 1, *++fmt)); 1791590Srgrimes if (*fmt == '.' && isdigit(*++fmt)) { 1801590Srgrimes prec = atoi(fmt); 1811590Srgrimes while (isdigit(*++fmt)); 1821590Srgrimes } 1831590Srgrimes switch(*fmt) { 1841590Srgrimes case 'c': 1851590Srgrimes bcnt += 1; 1861590Srgrimes break; 1871590Srgrimes case 'd': case 'i': case 'o': case 'u': 1881590Srgrimes case 'x': case 'X': 1891590Srgrimes bcnt += 4; 1901590Srgrimes break; 1911590Srgrimes case 'e': case 'E': case 'f': case 'g': case 'G': 1921590Srgrimes bcnt += 8; 1931590Srgrimes break; 1941590Srgrimes case 's': 1951590Srgrimes bcnt += prec; 1961590Srgrimes break; 1971590Srgrimes case '_': 1981590Srgrimes switch(*++fmt) { 1991590Srgrimes case 'c': case 'p': case 'u': 2001590Srgrimes bcnt += 1; 2011590Srgrimes break; 2021590Srgrimes } 2031590Srgrimes } 2041590Srgrimes } 2051590Srgrimes cursize += bcnt * fu->reps; 2061590Srgrimes } 2071590Srgrimes return (cursize); 2081590Srgrimes} 2091590Srgrimes 2101590Srgrimesvoid 2111590Srgrimesrewrite(fs) 2121590Srgrimes FS *fs; 2131590Srgrimes{ 2141590Srgrimes enum { NOTOKAY, USEBCNT, USEPREC } sokay; 2151590Srgrimes register PR *pr, **nextpr; 2161590Srgrimes register FU *fu; 21730921Sache unsigned char *p1, *p2, *fmtp; 21830921Sache char savech, cs[3]; 2191590Srgrimes int nconv, prec; 2201590Srgrimes 2211590Srgrimes for (fu = fs->nextfu; fu; fu = fu->nextfu) { 2221590Srgrimes /* 2231590Srgrimes * Break each format unit into print units; each conversion 2241590Srgrimes * character gets its own. 2251590Srgrimes */ 2261590Srgrimes for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 22780290Sobrien if ((pr = calloc(1, sizeof(PR))) == NULL) 22880290Sobrien err(1, NULL); 2291590Srgrimes if (!fu->nextpr) 2301590Srgrimes fu->nextpr = pr; 2311590Srgrimes else 2321590Srgrimes *nextpr = pr; 2331590Srgrimes 2341590Srgrimes /* Skip preceding text and up to the next % sign. */ 2351590Srgrimes for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); 2361590Srgrimes 2371590Srgrimes /* Only text in the string. */ 2381590Srgrimes if (!*p1) { 2391590Srgrimes pr->fmt = fmtp; 2401590Srgrimes pr->flags = F_TEXT; 2411590Srgrimes break; 2421590Srgrimes } 2431590Srgrimes 2441590Srgrimes /* 2451590Srgrimes * Get precision for %s -- if have a byte count, don't 2461590Srgrimes * need it. 2471590Srgrimes */ 2481590Srgrimes if (fu->bcnt) { 2491590Srgrimes sokay = USEBCNT; 2501590Srgrimes /* Skip to conversion character. */ 2511590Srgrimes for (++p1; index(spec, *p1); ++p1); 2521590Srgrimes } else { 2531590Srgrimes /* Skip any special chars, field width. */ 2541590Srgrimes while (index(spec + 1, *++p1)); 2551590Srgrimes if (*p1 == '.' && isdigit(*++p1)) { 2561590Srgrimes sokay = USEPREC; 2571590Srgrimes prec = atoi(p1); 2581590Srgrimes while (isdigit(*++p1)); 2591590Srgrimes } else 2601590Srgrimes sokay = NOTOKAY; 2611590Srgrimes } 2621590Srgrimes 2631590Srgrimes p2 = p1 + 1; /* Set end pointer. */ 2641590Srgrimes cs[0] = *p1; /* Set conversion string. */ 2651590Srgrimes cs[1] = '\0'; 2661590Srgrimes 2671590Srgrimes /* 2681590Srgrimes * Figure out the byte count for each conversion; 2691590Srgrimes * rewrite the format as necessary, set up blank- 2701590Srgrimes * padding for end of data. 2711590Srgrimes */ 2721590Srgrimes switch(cs[0]) { 2731590Srgrimes case 'c': 2741590Srgrimes pr->flags = F_CHAR; 2751590Srgrimes switch(fu->bcnt) { 2761590Srgrimes case 0: case 1: 2771590Srgrimes pr->bcnt = 1; 2781590Srgrimes break; 2791590Srgrimes default: 2801590Srgrimes p1[1] = '\0'; 2811590Srgrimes badcnt(p1); 2821590Srgrimes } 2831590Srgrimes break; 2841590Srgrimes case 'd': case 'i': 2851590Srgrimes pr->flags = F_INT; 2861590Srgrimes goto isint; 2871590Srgrimes case 'o': case 'u': case 'x': case 'X': 2881590Srgrimes pr->flags = F_UINT; 2891590Srgrimesisint: cs[2] = '\0'; 2901590Srgrimes cs[1] = cs[0]; 2911590Srgrimes cs[0] = 'q'; 2921590Srgrimes switch(fu->bcnt) { 2931590Srgrimes case 0: case 4: 2941590Srgrimes pr->bcnt = 4; 2951590Srgrimes break; 2961590Srgrimes case 1: 2971590Srgrimes pr->bcnt = 1; 2981590Srgrimes break; 2991590Srgrimes case 2: 3001590Srgrimes pr->bcnt = 2; 3011590Srgrimes break; 3021590Srgrimes default: 3031590Srgrimes p1[1] = '\0'; 3041590Srgrimes badcnt(p1); 3051590Srgrimes } 3061590Srgrimes break; 3071590Srgrimes case 'e': case 'E': case 'f': case 'g': case 'G': 3081590Srgrimes pr->flags = F_DBL; 3091590Srgrimes switch(fu->bcnt) { 3101590Srgrimes case 0: case 8: 3111590Srgrimes pr->bcnt = 8; 3121590Srgrimes break; 3131590Srgrimes case 4: 3141590Srgrimes pr->bcnt = 4; 3151590Srgrimes break; 3161590Srgrimes default: 3171590Srgrimes p1[1] = '\0'; 3181590Srgrimes badcnt(p1); 3191590Srgrimes } 3201590Srgrimes break; 3211590Srgrimes case 's': 3221590Srgrimes pr->flags = F_STR; 3231590Srgrimes switch(sokay) { 3241590Srgrimes case NOTOKAY: 3251590Srgrimes badsfmt(); 3261590Srgrimes case USEBCNT: 3271590Srgrimes pr->bcnt = fu->bcnt; 3281590Srgrimes break; 3291590Srgrimes case USEPREC: 3301590Srgrimes pr->bcnt = prec; 3311590Srgrimes break; 3321590Srgrimes } 3331590Srgrimes break; 3341590Srgrimes case '_': 3351590Srgrimes ++p2; 3361590Srgrimes switch(p1[1]) { 3371590Srgrimes case 'A': 3381590Srgrimes endfu = fu; 3391590Srgrimes fu->flags |= F_IGNORE; 3401590Srgrimes /* FALLTHROUGH */ 3411590Srgrimes case 'a': 3421590Srgrimes pr->flags = F_ADDRESS; 3431590Srgrimes ++p2; 3441590Srgrimes switch(p1[2]) { 3451590Srgrimes case 'd': case 'o': case'x': 3461590Srgrimes cs[0] = 'q'; 3471590Srgrimes cs[1] = p1[2]; 3481590Srgrimes cs[2] = '\0'; 3491590Srgrimes break; 3501590Srgrimes default: 3511590Srgrimes p1[3] = '\0'; 3521590Srgrimes badconv(p1); 3531590Srgrimes } 3541590Srgrimes break; 3551590Srgrimes case 'c': 3561590Srgrimes pr->flags = F_C; 3571590Srgrimes /* cs[0] = 'c'; set in conv_c */ 3581590Srgrimes goto isint2; 3591590Srgrimes case 'p': 3601590Srgrimes pr->flags = F_P; 3611590Srgrimes cs[0] = 'c'; 3621590Srgrimes goto isint2; 3631590Srgrimes case 'u': 3641590Srgrimes pr->flags = F_U; 3651590Srgrimes /* cs[0] = 'c'; set in conv_u */ 3661590Srgrimesisint2: switch(fu->bcnt) { 3671590Srgrimes case 0: case 1: 3681590Srgrimes pr->bcnt = 1; 3691590Srgrimes break; 3701590Srgrimes default: 3711590Srgrimes p1[2] = '\0'; 3721590Srgrimes badcnt(p1); 3731590Srgrimes } 3741590Srgrimes break; 3751590Srgrimes default: 3761590Srgrimes p1[2] = '\0'; 3771590Srgrimes badconv(p1); 3781590Srgrimes } 3791590Srgrimes break; 3801590Srgrimes default: 3811590Srgrimes p1[1] = '\0'; 3821590Srgrimes badconv(p1); 3831590Srgrimes } 3841590Srgrimes 3851590Srgrimes /* 3861590Srgrimes * Copy to PR format string, set conversion character 3871590Srgrimes * pointer, update original. 3881590Srgrimes */ 3891590Srgrimes savech = *p2; 3901590Srgrimes p1[0] = '\0'; 39180290Sobrien if ((pr->fmt = calloc(1, strlen(fmtp) + 2)) == NULL) 39280290Sobrien err(1, NULL); 3931590Srgrimes (void)strcpy(pr->fmt, fmtp); 3941590Srgrimes (void)strcat(pr->fmt, cs); 3951590Srgrimes *p2 = savech; 3961590Srgrimes pr->cchar = pr->fmt + (p1 - fmtp); 3971590Srgrimes fmtp = p2; 3981590Srgrimes 3991590Srgrimes /* Only one conversion character if byte count. */ 4001590Srgrimes if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) 40127315Scharnier errx(1, "byte count with multiple conversion characters"); 4021590Srgrimes } 4031590Srgrimes /* 4041590Srgrimes * If format unit byte count not specified, figure it out 4051590Srgrimes * so can adjust rep count later. 4061590Srgrimes */ 4071590Srgrimes if (!fu->bcnt) 4081590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4091590Srgrimes fu->bcnt += pr->bcnt; 4101590Srgrimes } 4111590Srgrimes /* 4121590Srgrimes * If the format string interprets any data at all, and it's 4131590Srgrimes * not the same as the blocksize, and its last format unit 4141590Srgrimes * interprets any data at all, and has no iteration count, 4151590Srgrimes * repeat it as necessary. 4161590Srgrimes * 4171590Srgrimes * If, rep count is greater than 1, no trailing whitespace 4181590Srgrimes * gets output from the last iteration of the format unit. 4191590Srgrimes */ 4201590Srgrimes for (fu = fs->nextfu;; fu = fu->nextfu) { 4211590Srgrimes if (!fu->nextfu && fs->bcnt < blocksize && 4221590Srgrimes !(fu->flags&F_SETREP) && fu->bcnt) 4231590Srgrimes fu->reps += (blocksize - fs->bcnt) / fu->bcnt; 4241590Srgrimes if (fu->reps > 1) { 4251590Srgrimes for (pr = fu->nextpr;; pr = pr->nextpr) 4261590Srgrimes if (!pr->nextpr) 4271590Srgrimes break; 4281590Srgrimes for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 4291590Srgrimes p2 = isspace(*p1) ? p1 : NULL; 4301590Srgrimes if (p2) 4311590Srgrimes pr->nospace = p2; 4321590Srgrimes } 4331590Srgrimes if (!fu->nextfu) 4341590Srgrimes break; 4351590Srgrimes } 4361590Srgrimes#ifdef DEBUG 4371590Srgrimes for (fu = fs->nextfu; fu; fu = fu->nextfu) { 4381590Srgrimes (void)printf("fmt:"); 4391590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4401590Srgrimes (void)printf(" {%s}", pr->fmt); 4411590Srgrimes (void)printf("\n"); 4421590Srgrimes } 4431590Srgrimes#endif 4441590Srgrimes} 4451590Srgrimes 4461590Srgrimesvoid 4471590Srgrimesescape(p1) 4481590Srgrimes register char *p1; 4491590Srgrimes{ 4501590Srgrimes register char *p2; 4511590Srgrimes 4521590Srgrimes /* alphabetic escape sequences have to be done in place */ 4531590Srgrimes for (p2 = p1;; ++p1, ++p2) { 4541590Srgrimes if (!*p1) { 4551590Srgrimes *p2 = *p1; 4561590Srgrimes break; 4571590Srgrimes } 4581590Srgrimes if (*p1 == '\\') 4591590Srgrimes switch(*++p1) { 4601590Srgrimes case 'a': 4611590Srgrimes /* *p2 = '\a'; */ 4621590Srgrimes *p2 = '\007'; 4631590Srgrimes break; 4641590Srgrimes case 'b': 4651590Srgrimes *p2 = '\b'; 4661590Srgrimes break; 4671590Srgrimes case 'f': 4681590Srgrimes *p2 = '\f'; 4691590Srgrimes break; 4701590Srgrimes case 'n': 4711590Srgrimes *p2 = '\n'; 4721590Srgrimes break; 4731590Srgrimes case 'r': 4741590Srgrimes *p2 = '\r'; 4751590Srgrimes break; 4761590Srgrimes case 't': 4771590Srgrimes *p2 = '\t'; 4781590Srgrimes break; 4791590Srgrimes case 'v': 4801590Srgrimes *p2 = '\v'; 4811590Srgrimes break; 4821590Srgrimes default: 4831590Srgrimes *p2 = *p1; 4841590Srgrimes break; 4851590Srgrimes } 4861590Srgrimes } 4871590Srgrimes} 4881590Srgrimes 4891590Srgrimesvoid 4901590Srgrimesbadcnt(s) 4911590Srgrimes char *s; 4921590Srgrimes{ 49327315Scharnier errx(1, "%s: bad byte count", s); 4941590Srgrimes} 4951590Srgrimes 4961590Srgrimesvoid 4971590Srgrimesbadsfmt() 4981590Srgrimes{ 49927315Scharnier errx(1, "%%s: requires a precision or a byte count"); 5001590Srgrimes} 5011590Srgrimes 5021590Srgrimesvoid 5031590Srgrimesbadfmt(fmt) 5041590Srgrimes char *fmt; 5051590Srgrimes{ 50627315Scharnier errx(1, "\"%s\": bad format", fmt); 5071590Srgrimes} 5081590Srgrimes 5091590Srgrimesvoid 5101590Srgrimesbadconv(ch) 5111590Srgrimes char *ch; 5121590Srgrimes{ 51327315Scharnier errx(1, "%%%s: bad conversion character", ch); 5141590Srgrimes} 515