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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3127315Scharnier#if 0 321590Srgrimesstatic char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; 3327315Scharnier#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include <sys/types.h> 391590Srgrimes 4027315Scharnier#include <err.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 51102944Sdwmaloneaddfile(char *name) 521590Srgrimes{ 53102944Sdwmalone unsigned char *p; 541590Srgrimes FILE *fp; 551590Srgrimes int ch; 561590Srgrimes char buf[2048 + 1]; 571590Srgrimes 581590Srgrimes if ((fp = fopen(name, "r")) == NULL) 5927315Scharnier err(1, "%s", name); 601590Srgrimes while (fgets(buf, sizeof(buf), fp)) { 611590Srgrimes if (!(p = index(buf, '\n'))) { 6227315Scharnier warnx("line too long"); 631590Srgrimes while ((ch = getchar()) != '\n' && ch != EOF); 641590Srgrimes continue; 651590Srgrimes } 661590Srgrimes *p = '\0'; 671590Srgrimes for (p = buf; *p && isspace(*p); ++p); 681590Srgrimes if (!*p || *p == '#') 691590Srgrimes continue; 701590Srgrimes add(p); 711590Srgrimes } 721590Srgrimes (void)fclose(fp); 731590Srgrimes} 741590Srgrimes 751590Srgrimesvoid 76102944Sdwmaloneadd(const char *fmt) 771590Srgrimes{ 7887203Smarkm unsigned const char *p, *savep; 791590Srgrimes static FS **nextfs; 801590Srgrimes FS *tfs; 811590Srgrimes FU *tfu, **nextfu; 821590Srgrimes 831590Srgrimes /* start new linked list of format units */ 8480290Sobrien if ((tfs = calloc(1, sizeof(FS))) == NULL) 8580290Sobrien err(1, NULL); 861590Srgrimes if (!fshead) 871590Srgrimes fshead = tfs; 881590Srgrimes else 891590Srgrimes *nextfs = tfs; 901590Srgrimes nextfs = &tfs->nextfs; 911590Srgrimes nextfu = &tfs->nextfu; 921590Srgrimes 931590Srgrimes /* take the format string and break it up into format units */ 941590Srgrimes for (p = fmt;;) { 951590Srgrimes /* skip leading white space */ 961590Srgrimes for (; isspace(*p); ++p); 971590Srgrimes if (!*p) 981590Srgrimes break; 991590Srgrimes 1001590Srgrimes /* allocate a new format unit and link it in */ 10180290Sobrien if ((tfu = calloc(1, sizeof(FU))) == NULL) 10280290Sobrien err(1, NULL); 1031590Srgrimes *nextfu = tfu; 1041590Srgrimes nextfu = &tfu->nextfu; 1051590Srgrimes tfu->reps = 1; 1061590Srgrimes 1071590Srgrimes /* if leading digit, repetition count */ 1081590Srgrimes if (isdigit(*p)) { 1091590Srgrimes for (savep = p; isdigit(*p); ++p); 1101590Srgrimes if (!isspace(*p) && *p != '/') 1111590Srgrimes badfmt(fmt); 1121590Srgrimes /* may overwrite either white space or slash */ 1131590Srgrimes tfu->reps = atoi(savep); 1141590Srgrimes tfu->flags = F_SETREP; 1151590Srgrimes /* skip trailing white space */ 1161590Srgrimes for (++p; isspace(*p); ++p); 1171590Srgrimes } 1181590Srgrimes 1191590Srgrimes /* skip slash and trailing white space */ 1201590Srgrimes if (*p == '/') 1211590Srgrimes while (isspace(*++p)); 1221590Srgrimes 1231590Srgrimes /* byte count */ 1241590Srgrimes if (isdigit(*p)) { 1251590Srgrimes for (savep = p; isdigit(*p); ++p); 1261590Srgrimes if (!isspace(*p)) 1271590Srgrimes badfmt(fmt); 1281590Srgrimes tfu->bcnt = atoi(savep); 1291590Srgrimes /* skip trailing white space */ 1301590Srgrimes for (++p; isspace(*p); ++p); 1311590Srgrimes } 1321590Srgrimes 1331590Srgrimes /* format */ 1341590Srgrimes if (*p != '"') 1351590Srgrimes badfmt(fmt); 1361590Srgrimes for (savep = ++p; *p != '"';) 1371590Srgrimes if (*p++ == 0) 1381590Srgrimes badfmt(fmt); 1391590Srgrimes if (!(tfu->fmt = malloc(p - savep + 1))) 14080290Sobrien err(1, NULL); 141194796Sdelphij (void) strlcpy(tfu->fmt, savep, p - savep + 1); 1421590Srgrimes escape(tfu->fmt); 1431590Srgrimes p++; 1441590Srgrimes } 1451590Srgrimes} 1461590Srgrimes 14791840Sobrienstatic const char *spec = ".#-+ 0123456789"; 1481590Srgrimes 1491590Srgrimesint 150102944Sdwmalonesize(FS *fs) 1511590Srgrimes{ 152102944Sdwmalone FU *fu; 153102944Sdwmalone int bcnt, cursize; 154102944Sdwmalone unsigned char *fmt; 1551590Srgrimes int prec; 1561590Srgrimes 1571590Srgrimes /* figure out the data block size needed for each format unit */ 1581590Srgrimes for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { 1591590Srgrimes if (fu->bcnt) { 1601590Srgrimes cursize += fu->bcnt * fu->reps; 1611590Srgrimes continue; 1621590Srgrimes } 1631590Srgrimes for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { 1641590Srgrimes if (*fmt != '%') 1651590Srgrimes continue; 1661590Srgrimes /* 1671590Srgrimes * skip any special chars -- save precision in 1681590Srgrimes * case it's a %s format. 1691590Srgrimes */ 1701590Srgrimes while (index(spec + 1, *++fmt)); 1711590Srgrimes if (*fmt == '.' && isdigit(*++fmt)) { 1721590Srgrimes prec = atoi(fmt); 1731590Srgrimes while (isdigit(*++fmt)); 1741590Srgrimes } 1751590Srgrimes switch(*fmt) { 1761590Srgrimes case 'c': 1771590Srgrimes bcnt += 1; 1781590Srgrimes break; 1791590Srgrimes case 'd': case 'i': case 'o': case 'u': 1801590Srgrimes case 'x': case 'X': 1811590Srgrimes bcnt += 4; 1821590Srgrimes break; 1831590Srgrimes case 'e': case 'E': case 'f': case 'g': case 'G': 1841590Srgrimes bcnt += 8; 1851590Srgrimes break; 1861590Srgrimes case 's': 1871590Srgrimes bcnt += prec; 1881590Srgrimes break; 1891590Srgrimes case '_': 1901590Srgrimes switch(*++fmt) { 1911590Srgrimes case 'c': case 'p': case 'u': 1921590Srgrimes bcnt += 1; 1931590Srgrimes break; 1941590Srgrimes } 1951590Srgrimes } 1961590Srgrimes } 1971590Srgrimes cursize += bcnt * fu->reps; 1981590Srgrimes } 1991590Srgrimes return (cursize); 2001590Srgrimes} 2011590Srgrimes 2021590Srgrimesvoid 203102944Sdwmalonerewrite(FS *fs) 2041590Srgrimes{ 2051590Srgrimes enum { NOTOKAY, USEBCNT, USEPREC } sokay; 206102944Sdwmalone PR *pr, **nextpr; 207102944Sdwmalone FU *fu; 20830921Sache unsigned char *p1, *p2, *fmtp; 20930921Sache char savech, cs[3]; 2101590Srgrimes int nconv, prec; 211161132Smaxim size_t len; 2121590Srgrimes 213132541Sjohan prec = 0; 214132541Sjohan 2151590Srgrimes for (fu = fs->nextfu; fu; fu = fu->nextfu) { 2161590Srgrimes /* 2171590Srgrimes * Break each format unit into print units; each conversion 2181590Srgrimes * character gets its own. 2191590Srgrimes */ 220262927Sbrueffer nextpr = &fu->nextpr; 2211590Srgrimes for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 22280290Sobrien if ((pr = calloc(1, sizeof(PR))) == NULL) 22380290Sobrien err(1, NULL); 224262927Sbrueffer *nextpr = pr; 2251590Srgrimes 2261590Srgrimes /* Skip preceding text and up to the next % sign. */ 2271590Srgrimes for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); 2281590Srgrimes 2291590Srgrimes /* Only text in the string. */ 2301590Srgrimes if (!*p1) { 2311590Srgrimes pr->fmt = fmtp; 2321590Srgrimes pr->flags = F_TEXT; 2331590Srgrimes break; 2341590Srgrimes } 2351590Srgrimes 2361590Srgrimes /* 2371590Srgrimes * Get precision for %s -- if have a byte count, don't 2381590Srgrimes * need it. 2391590Srgrimes */ 2401590Srgrimes if (fu->bcnt) { 2411590Srgrimes sokay = USEBCNT; 2421590Srgrimes /* Skip to conversion character. */ 2431590Srgrimes for (++p1; index(spec, *p1); ++p1); 2441590Srgrimes } else { 2451590Srgrimes /* Skip any special chars, field width. */ 2461590Srgrimes while (index(spec + 1, *++p1)); 2471590Srgrimes if (*p1 == '.' && isdigit(*++p1)) { 2481590Srgrimes sokay = USEPREC; 2491590Srgrimes prec = atoi(p1); 2501590Srgrimes while (isdigit(*++p1)); 2511590Srgrimes } else 2521590Srgrimes sokay = NOTOKAY; 2531590Srgrimes } 2541590Srgrimes 255231578Stijl p2 = *p1 ? p1 + 1 : p1; /* Set end pointer -- make sure 256231578Stijl * that it's non-NUL/-NULL first 257231578Stijl * though. */ 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: 31196795Stjr if (fu->bcnt == sizeof(long double)) { 31296795Stjr cs[2] = '\0'; 31396795Stjr cs[1] = cs[0]; 31496795Stjr cs[0] = 'L'; 31596795Stjr pr->bcnt = sizeof(long double); 31696795Stjr } else { 31796795Stjr p1[1] = '\0'; 31896795Stjr badcnt(p1); 31996795Stjr } 3201590Srgrimes } 3211590Srgrimes break; 3221590Srgrimes case 's': 3231590Srgrimes pr->flags = F_STR; 3241590Srgrimes switch(sokay) { 3251590Srgrimes case NOTOKAY: 3261590Srgrimes badsfmt(); 3271590Srgrimes case USEBCNT: 3281590Srgrimes pr->bcnt = fu->bcnt; 3291590Srgrimes break; 3301590Srgrimes case USEPREC: 3311590Srgrimes pr->bcnt = prec; 3321590Srgrimes break; 3331590Srgrimes } 3341590Srgrimes break; 3351590Srgrimes case '_': 3361590Srgrimes ++p2; 3371590Srgrimes switch(p1[1]) { 3381590Srgrimes case 'A': 3391590Srgrimes endfu = fu; 3401590Srgrimes fu->flags |= F_IGNORE; 3411590Srgrimes /* FALLTHROUGH */ 3421590Srgrimes case 'a': 3431590Srgrimes pr->flags = F_ADDRESS; 3441590Srgrimes ++p2; 3451590Srgrimes switch(p1[2]) { 3461590Srgrimes case 'd': case 'o': case'x': 3471590Srgrimes cs[0] = 'q'; 3481590Srgrimes cs[1] = p1[2]; 3491590Srgrimes cs[2] = '\0'; 3501590Srgrimes break; 3511590Srgrimes default: 3521590Srgrimes p1[3] = '\0'; 3531590Srgrimes badconv(p1); 3541590Srgrimes } 3551590Srgrimes break; 3561590Srgrimes case 'c': 3571590Srgrimes pr->flags = F_C; 3581590Srgrimes /* cs[0] = 'c'; set in conv_c */ 3591590Srgrimes goto isint2; 3601590Srgrimes case 'p': 3611590Srgrimes pr->flags = F_P; 3621590Srgrimes cs[0] = 'c'; 3631590Srgrimes goto isint2; 3641590Srgrimes case 'u': 3651590Srgrimes pr->flags = F_U; 3661590Srgrimes /* cs[0] = 'c'; set in conv_u */ 3671590Srgrimesisint2: switch(fu->bcnt) { 3681590Srgrimes case 0: case 1: 3691590Srgrimes pr->bcnt = 1; 3701590Srgrimes break; 3711590Srgrimes default: 3721590Srgrimes p1[2] = '\0'; 3731590Srgrimes badcnt(p1); 3741590Srgrimes } 3751590Srgrimes break; 3761590Srgrimes default: 3771590Srgrimes p1[2] = '\0'; 3781590Srgrimes badconv(p1); 3791590Srgrimes } 3801590Srgrimes break; 3811590Srgrimes default: 3821590Srgrimes p1[1] = '\0'; 3831590Srgrimes badconv(p1); 3841590Srgrimes } 3851590Srgrimes 3861590Srgrimes /* 3871590Srgrimes * Copy to PR format string, set conversion character 3881590Srgrimes * pointer, update original. 3891590Srgrimes */ 3901590Srgrimes savech = *p2; 3911590Srgrimes p1[0] = '\0'; 392161132Smaxim len = strlen(fmtp) + strlen(cs) + 1; 393161132Smaxim if ((pr->fmt = calloc(1, len)) == NULL) 39480290Sobrien err(1, NULL); 395161132Smaxim snprintf(pr->fmt, len, "%s%s", fmtp, cs); 3961590Srgrimes *p2 = savech; 3971590Srgrimes pr->cchar = pr->fmt + (p1 - fmtp); 3981590Srgrimes fmtp = p2; 3991590Srgrimes 4001590Srgrimes /* Only one conversion character if byte count. */ 4011590Srgrimes if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) 40227315Scharnier errx(1, "byte count with multiple conversion characters"); 4031590Srgrimes } 4041590Srgrimes /* 4051590Srgrimes * If format unit byte count not specified, figure it out 4061590Srgrimes * so can adjust rep count later. 4071590Srgrimes */ 4081590Srgrimes if (!fu->bcnt) 4091590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4101590Srgrimes fu->bcnt += pr->bcnt; 4111590Srgrimes } 4121590Srgrimes /* 4131590Srgrimes * If the format string interprets any data at all, and it's 4141590Srgrimes * not the same as the blocksize, and its last format unit 4151590Srgrimes * interprets any data at all, and has no iteration count, 4161590Srgrimes * repeat it as necessary. 4171590Srgrimes * 4181590Srgrimes * If, rep count is greater than 1, no trailing whitespace 4191590Srgrimes * gets output from the last iteration of the format unit. 4201590Srgrimes */ 42197329Stjr for (fu = fs->nextfu; fu; fu = fu->nextfu) { 4221590Srgrimes if (!fu->nextfu && fs->bcnt < blocksize && 4231590Srgrimes !(fu->flags&F_SETREP) && fu->bcnt) 4241590Srgrimes fu->reps += (blocksize - fs->bcnt) / fu->bcnt; 4251590Srgrimes if (fu->reps > 1) { 4261590Srgrimes for (pr = fu->nextpr;; pr = pr->nextpr) 4271590Srgrimes if (!pr->nextpr) 4281590Srgrimes break; 4291590Srgrimes for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 4301590Srgrimes p2 = isspace(*p1) ? p1 : NULL; 4311590Srgrimes if (p2) 4321590Srgrimes pr->nospace = p2; 4331590Srgrimes } 4341590Srgrimes } 4351590Srgrimes#ifdef DEBUG 4361590Srgrimes for (fu = fs->nextfu; fu; fu = fu->nextfu) { 4371590Srgrimes (void)printf("fmt:"); 4381590Srgrimes for (pr = fu->nextpr; pr; pr = pr->nextpr) 4391590Srgrimes (void)printf(" {%s}", pr->fmt); 4401590Srgrimes (void)printf("\n"); 4411590Srgrimes } 4421590Srgrimes#endif 4431590Srgrimes} 4441590Srgrimes 4451590Srgrimesvoid 446102944Sdwmaloneescape(char *p1) 4471590Srgrimes{ 448102944Sdwmalone char *p2; 4491590Srgrimes 4501590Srgrimes /* alphabetic escape sequences have to be done in place */ 451231578Stijl for (p2 = p1;; p1++, p2++) { 452231578Stijl if (*p1 == '\\') { 453231578Stijl p1++; 454231578Stijl switch(*p1) { 455231578Stijl case '\0': 456231578Stijl *p2 = '\\'; 457231578Stijl *++p2 = '\0'; 458231578Stijl return; 4591590Srgrimes case 'a': 4601590Srgrimes /* *p2 = '\a'; */ 4611590Srgrimes *p2 = '\007'; 4621590Srgrimes break; 4631590Srgrimes case 'b': 4641590Srgrimes *p2 = '\b'; 4651590Srgrimes break; 4661590Srgrimes case 'f': 4671590Srgrimes *p2 = '\f'; 4681590Srgrimes break; 4691590Srgrimes case 'n': 4701590Srgrimes *p2 = '\n'; 4711590Srgrimes break; 4721590Srgrimes case 'r': 4731590Srgrimes *p2 = '\r'; 4741590Srgrimes break; 4751590Srgrimes case 't': 4761590Srgrimes *p2 = '\t'; 4771590Srgrimes break; 4781590Srgrimes case 'v': 4791590Srgrimes *p2 = '\v'; 4801590Srgrimes break; 4811590Srgrimes default: 4821590Srgrimes *p2 = *p1; 4831590Srgrimes break; 4841590Srgrimes } 485231578Stijl } else { 486231578Stijl *p2 = *p1; 487231578Stijl if (*p1 == '\0') 488231578Stijl return; 489231578Stijl } 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