parse.c revision 161132
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 381590Srgrimes#endif /* not lint */ 3999112Sobrien#include <sys/cdefs.h> 4099112Sobrien__FBSDID("$FreeBSD: head/usr.bin/hexdump/parse.c 161132 2006-08-09 19:12:10Z maxim $"); 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 55102944Sdwmaloneaddfile(char *name) 561590Srgrimes{ 57102944Sdwmalone unsigned char *p; 581590Srgrimes FILE *fp; 591590Srgrimes int ch; 601590Srgrimes char buf[2048 + 1]; 611590Srgrimes 621590Srgrimes if ((fp = fopen(name, "r")) == NULL) 6327315Scharnier err(1, "%s", name); 641590Srgrimes while (fgets(buf, sizeof(buf), fp)) { 651590Srgrimes if (!(p = index(buf, '\n'))) { 6627315Scharnier warnx("line too long"); 671590Srgrimes while ((ch = getchar()) != '\n' && ch != EOF); 681590Srgrimes continue; 691590Srgrimes } 701590Srgrimes *p = '\0'; 711590Srgrimes for (p = buf; *p && isspace(*p); ++p); 721590Srgrimes if (!*p || *p == '#') 731590Srgrimes continue; 741590Srgrimes add(p); 751590Srgrimes } 761590Srgrimes (void)fclose(fp); 771590Srgrimes} 781590Srgrimes 791590Srgrimesvoid 80102944Sdwmaloneadd(const char *fmt) 811590Srgrimes{ 8287203Smarkm unsigned const char *p, *savep; 831590Srgrimes static FS **nextfs; 841590Srgrimes FS *tfs; 851590Srgrimes FU *tfu, **nextfu; 861590Srgrimes 871590Srgrimes /* start new linked list of format units */ 8880290Sobrien if ((tfs = calloc(1, sizeof(FS))) == NULL) 8980290Sobrien err(1, NULL); 901590Srgrimes if (!fshead) 911590Srgrimes fshead = tfs; 921590Srgrimes else 931590Srgrimes *nextfs = tfs; 941590Srgrimes nextfs = &tfs->nextfs; 951590Srgrimes nextfu = &tfs->nextfu; 961590Srgrimes 971590Srgrimes /* take the format string and break it up into format units */ 981590Srgrimes for (p = fmt;;) { 991590Srgrimes /* skip leading white space */ 1001590Srgrimes for (; isspace(*p); ++p); 1011590Srgrimes if (!*p) 1021590Srgrimes break; 1031590Srgrimes 1041590Srgrimes /* allocate a new format unit and link it in */ 10580290Sobrien if ((tfu = calloc(1, sizeof(FU))) == NULL) 10680290Sobrien err(1, NULL); 1071590Srgrimes *nextfu = tfu; 1081590Srgrimes nextfu = &tfu->nextfu; 1091590Srgrimes tfu->reps = 1; 1101590Srgrimes 1111590Srgrimes /* if leading digit, repetition count */ 1121590Srgrimes if (isdigit(*p)) { 1131590Srgrimes for (savep = p; isdigit(*p); ++p); 1141590Srgrimes if (!isspace(*p) && *p != '/') 1151590Srgrimes badfmt(fmt); 1161590Srgrimes /* may overwrite either white space or slash */ 1171590Srgrimes tfu->reps = atoi(savep); 1181590Srgrimes tfu->flags = F_SETREP; 1191590Srgrimes /* skip trailing white space */ 1201590Srgrimes for (++p; isspace(*p); ++p); 1211590Srgrimes } 1221590Srgrimes 1231590Srgrimes /* skip slash and trailing white space */ 1241590Srgrimes if (*p == '/') 1251590Srgrimes while (isspace(*++p)); 1261590Srgrimes 1271590Srgrimes /* byte count */ 1281590Srgrimes if (isdigit(*p)) { 1291590Srgrimes for (savep = p; isdigit(*p); ++p); 1301590Srgrimes if (!isspace(*p)) 1311590Srgrimes badfmt(fmt); 1321590Srgrimes tfu->bcnt = atoi(savep); 1331590Srgrimes /* skip trailing white space */ 1341590Srgrimes for (++p; isspace(*p); ++p); 1351590Srgrimes } 1361590Srgrimes 1371590Srgrimes /* format */ 1381590Srgrimes if (*p != '"') 1391590Srgrimes badfmt(fmt); 1401590Srgrimes for (savep = ++p; *p != '"';) 1411590Srgrimes if (*p++ == 0) 1421590Srgrimes badfmt(fmt); 1431590Srgrimes if (!(tfu->fmt = malloc(p - savep + 1))) 14480290Sobrien err(1, NULL); 1451590Srgrimes (void) strncpy(tfu->fmt, savep, p - savep); 1461590Srgrimes tfu->fmt[p - savep] = '\0'; 1471590Srgrimes escape(tfu->fmt); 1481590Srgrimes p++; 1491590Srgrimes } 1501590Srgrimes} 1511590Srgrimes 15291840Sobrienstatic const char *spec = ".#-+ 0123456789"; 1531590Srgrimes 1541590Srgrimesint 155102944Sdwmalonesize(FS *fs) 1561590Srgrimes{ 157102944Sdwmalone FU *fu; 158102944Sdwmalone int bcnt, cursize; 159102944Sdwmalone unsigned char *fmt; 1601590Srgrimes int prec; 1611590Srgrimes 1621590Srgrimes /* figure out the data block size needed for each format unit */ 1631590Srgrimes for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { 1641590Srgrimes if (fu->bcnt) { 1651590Srgrimes cursize += fu->bcnt * fu->reps; 1661590Srgrimes continue; 1671590Srgrimes } 1681590Srgrimes for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { 1691590Srgrimes if (*fmt != '%') 1701590Srgrimes continue; 1711590Srgrimes /* 1721590Srgrimes * skip any special chars -- save precision in 1731590Srgrimes * case it's a %s format. 1741590Srgrimes */ 1751590Srgrimes while (index(spec + 1, *++fmt)); 1761590Srgrimes if (*fmt == '.' && isdigit(*++fmt)) { 1771590Srgrimes prec = atoi(fmt); 1781590Srgrimes while (isdigit(*++fmt)); 1791590Srgrimes } 1801590Srgrimes switch(*fmt) { 1811590Srgrimes case 'c': 1821590Srgrimes bcnt += 1; 1831590Srgrimes break; 1841590Srgrimes case 'd': case 'i': case 'o': case 'u': 1851590Srgrimes case 'x': case 'X': 1861590Srgrimes bcnt += 4; 1871590Srgrimes break; 1881590Srgrimes case 'e': case 'E': case 'f': case 'g': case 'G': 1891590Srgrimes bcnt += 8; 1901590Srgrimes break; 1911590Srgrimes case 's': 1921590Srgrimes bcnt += prec; 1931590Srgrimes break; 1941590Srgrimes case '_': 1951590Srgrimes switch(*++fmt) { 1961590Srgrimes case 'c': case 'p': case 'u': 1971590Srgrimes bcnt += 1; 1981590Srgrimes break; 1991590Srgrimes } 2001590Srgrimes } 2011590Srgrimes } 2021590Srgrimes cursize += bcnt * fu->reps; 2031590Srgrimes } 2041590Srgrimes return (cursize); 2051590Srgrimes} 2061590Srgrimes 2071590Srgrimesvoid 208102944Sdwmalonerewrite(FS *fs) 2091590Srgrimes{ 2101590Srgrimes enum { NOTOKAY, USEBCNT, USEPREC } sokay; 211102944Sdwmalone PR *pr, **nextpr; 212102944Sdwmalone FU *fu; 21330921Sache unsigned char *p1, *p2, *fmtp; 21430921Sache char savech, cs[3]; 2151590Srgrimes int nconv, prec; 216161132Smaxim size_t len; 2171590Srgrimes 218132541Sjohan nextpr = NULL; 219132541Sjohan prec = 0; 220132541Sjohan 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: 31796795Stjr if (fu->bcnt == sizeof(long double)) { 31896795Stjr cs[2] = '\0'; 31996795Stjr cs[1] = cs[0]; 32096795Stjr cs[0] = 'L'; 32196795Stjr pr->bcnt = sizeof(long double); 32296795Stjr } else { 32396795Stjr p1[1] = '\0'; 32496795Stjr badcnt(p1); 32596795Stjr } 3261590Srgrimes } 3271590Srgrimes break; 3281590Srgrimes case 's': 3291590Srgrimes pr->flags = F_STR; 3301590Srgrimes switch(sokay) { 3311590Srgrimes case NOTOKAY: 3321590Srgrimes badsfmt(); 3331590Srgrimes case USEBCNT: 3341590Srgrimes pr->bcnt = fu->bcnt; 3351590Srgrimes break; 3361590Srgrimes case USEPREC: 3371590Srgrimes pr->bcnt = prec; 3381590Srgrimes break; 3391590Srgrimes } 3401590Srgrimes break; 3411590Srgrimes case '_': 3421590Srgrimes ++p2; 3431590Srgrimes switch(p1[1]) { 3441590Srgrimes case 'A': 3451590Srgrimes endfu = fu; 3461590Srgrimes fu->flags |= F_IGNORE; 3471590Srgrimes /* FALLTHROUGH */ 3481590Srgrimes case 'a': 3491590Srgrimes pr->flags = F_ADDRESS; 3501590Srgrimes ++p2; 3511590Srgrimes switch(p1[2]) { 3521590Srgrimes case 'd': case 'o': case'x': 3531590Srgrimes cs[0] = 'q'; 3541590Srgrimes cs[1] = p1[2]; 3551590Srgrimes cs[2] = '\0'; 3561590Srgrimes break; 3571590Srgrimes default: 3581590Srgrimes p1[3] = '\0'; 3591590Srgrimes badconv(p1); 3601590Srgrimes } 3611590Srgrimes break; 3621590Srgrimes case 'c': 3631590Srgrimes pr->flags = F_C; 3641590Srgrimes /* cs[0] = 'c'; set in conv_c */ 3651590Srgrimes goto isint2; 3661590Srgrimes case 'p': 3671590Srgrimes pr->flags = F_P; 3681590Srgrimes cs[0] = 'c'; 3691590Srgrimes goto isint2; 3701590Srgrimes case 'u': 3711590Srgrimes pr->flags = F_U; 3721590Srgrimes /* cs[0] = 'c'; set in conv_u */ 3731590Srgrimesisint2: switch(fu->bcnt) { 3741590Srgrimes case 0: case 1: 3751590Srgrimes pr->bcnt = 1; 3761590Srgrimes break; 3771590Srgrimes default: 3781590Srgrimes p1[2] = '\0'; 3791590Srgrimes badcnt(p1); 3801590Srgrimes } 3811590Srgrimes break; 3821590Srgrimes default: 3831590Srgrimes p1[2] = '\0'; 3841590Srgrimes badconv(p1); 3851590Srgrimes } 3861590Srgrimes break; 3871590Srgrimes default: 3881590Srgrimes p1[1] = '\0'; 3891590Srgrimes badconv(p1); 3901590Srgrimes } 3911590Srgrimes 3921590Srgrimes /* 3931590Srgrimes * Copy to PR format string, set conversion character 3941590Srgrimes * pointer, update original. 3951590Srgrimes */ 3961590Srgrimes savech = *p2; 3971590Srgrimes p1[0] = '\0'; 398161132Smaxim len = strlen(fmtp) + strlen(cs) + 1; 399161132Smaxim if ((pr->fmt = calloc(1, len)) == NULL) 40080290Sobrien err(1, NULL); 401161132Smaxim snprintf(pr->fmt, len, "%s%s", fmtp, cs); 4021590Srgrimes *p2 = savech; 4031590Srgrimes pr->cchar = pr->fmt + (p1 - fmtp); 4041590Srgrimes fmtp = p2; 4051590Srgrimes 4061590Srgrimes /* Only one conversion character if byte count. */ 4071590Srgrimes if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) 40827315Scharnier errx(1, "byte count with multiple conversion characters"); 4091590Srgrimes } 4101590Srgrimes /* 4111590Srgrimes * If format unit byte count not specified, figure it out 4121590Srgrimes * so can adjust rep count later. 4131590Srgrimes */ 4141590Srgrimes if (!fu->bcnt) 4151590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4161590Srgrimes fu->bcnt += pr->bcnt; 4171590Srgrimes } 4181590Srgrimes /* 4191590Srgrimes * If the format string interprets any data at all, and it's 4201590Srgrimes * not the same as the blocksize, and its last format unit 4211590Srgrimes * interprets any data at all, and has no iteration count, 4221590Srgrimes * repeat it as necessary. 4231590Srgrimes * 4241590Srgrimes * If, rep count is greater than 1, no trailing whitespace 4251590Srgrimes * gets output from the last iteration of the format unit. 4261590Srgrimes */ 42797329Stjr for (fu = fs->nextfu; fu; fu = fu->nextfu) { 4281590Srgrimes if (!fu->nextfu && fs->bcnt < blocksize && 4291590Srgrimes !(fu->flags&F_SETREP) && fu->bcnt) 4301590Srgrimes fu->reps += (blocksize - fs->bcnt) / fu->bcnt; 4311590Srgrimes if (fu->reps > 1) { 4321590Srgrimes for (pr = fu->nextpr;; pr = pr->nextpr) 4331590Srgrimes if (!pr->nextpr) 4341590Srgrimes break; 4351590Srgrimes for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 4361590Srgrimes p2 = isspace(*p1) ? p1 : NULL; 4371590Srgrimes if (p2) 4381590Srgrimes pr->nospace = p2; 4391590Srgrimes } 4401590Srgrimes } 4411590Srgrimes#ifdef DEBUG 4421590Srgrimes for (fu = fs->nextfu; fu; fu = fu->nextfu) { 4431590Srgrimes (void)printf("fmt:"); 4441590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4451590Srgrimes (void)printf(" {%s}", pr->fmt); 4461590Srgrimes (void)printf("\n"); 4471590Srgrimes } 4481590Srgrimes#endif 4491590Srgrimes} 4501590Srgrimes 4511590Srgrimesvoid 452102944Sdwmaloneescape(char *p1) 4531590Srgrimes{ 454102944Sdwmalone char *p2; 4551590Srgrimes 4561590Srgrimes /* alphabetic escape sequences have to be done in place */ 4571590Srgrimes for (p2 = p1;; ++p1, ++p2) { 4581590Srgrimes if (!*p1) { 4591590Srgrimes *p2 = *p1; 4601590Srgrimes break; 4611590Srgrimes } 4621590Srgrimes if (*p1 == '\\') 4631590Srgrimes switch(*++p1) { 4641590Srgrimes case 'a': 4651590Srgrimes /* *p2 = '\a'; */ 4661590Srgrimes *p2 = '\007'; 4671590Srgrimes break; 4681590Srgrimes case 'b': 4691590Srgrimes *p2 = '\b'; 4701590Srgrimes break; 4711590Srgrimes case 'f': 4721590Srgrimes *p2 = '\f'; 4731590Srgrimes break; 4741590Srgrimes case 'n': 4751590Srgrimes *p2 = '\n'; 4761590Srgrimes break; 4771590Srgrimes case 'r': 4781590Srgrimes *p2 = '\r'; 4791590Srgrimes break; 4801590Srgrimes case 't': 4811590Srgrimes *p2 = '\t'; 4821590Srgrimes break; 4831590Srgrimes case 'v': 4841590Srgrimes *p2 = '\v'; 4851590Srgrimes break; 4861590Srgrimes default: 4871590Srgrimes *p2 = *p1; 4881590Srgrimes break; 4891590Srgrimes } 4901590Srgrimes } 4911590Srgrimes} 4921590Srgrimes 4931590Srgrimesvoid 494102944Sdwmalonebadcnt(char *s) 4951590Srgrimes{ 49627315Scharnier errx(1, "%s: bad byte count", s); 4971590Srgrimes} 4981590Srgrimes 4991590Srgrimesvoid 500102944Sdwmalonebadsfmt(void) 5011590Srgrimes{ 50227315Scharnier errx(1, "%%s: requires a precision or a byte count"); 5031590Srgrimes} 5041590Srgrimes 5051590Srgrimesvoid 506102944Sdwmalonebadfmt(const char *fmt) 5071590Srgrimes{ 50827315Scharnier errx(1, "\"%s\": bad format", fmt); 5091590Srgrimes} 5101590Srgrimes 5111590Srgrimesvoid 512102944Sdwmalonebadconv(char *ch) 5131590Srgrimes{ 51427315Scharnier errx(1, "%%%s: bad conversion character", ch); 5151590Srgrimes} 516