138859Sbostic /* 238859Sbostic * Copyright (c) 1989 The Regents of the University of California. 338859Sbostic * All rights reserved. 438859Sbostic * 542734Sbostic * %sccs.include.redist.c% 638859Sbostic */ 738859Sbostic 838859Sbostic #ifndef lint 9*55201Sbostic static char sccsid[] = "@(#)parse.c 5.7 (Berkeley) 07/14/92"; 1038859Sbostic #endif /* not lint */ 1138859Sbostic 1238859Sbostic #include <sys/types.h> 13*55201Sbostic 14*55201Sbostic #include <errno.h> 15*55201Sbostic #include <fcntl.h> 1638859Sbostic #include <stdio.h> 1747173Sbostic #include <stdlib.h> 1838859Sbostic #include <ctype.h> 1942056Sbostic #include <string.h> 2038859Sbostic #include "hexdump.h" 2138859Sbostic 2238859Sbostic FU *endfu; /* format at end-of-data */ 2338859Sbostic 24*55201Sbostic void 2538859Sbostic addfile(name) 2638859Sbostic char *name; 2738859Sbostic { 2838859Sbostic register char *p; 2938859Sbostic FILE *fp; 3038859Sbostic int ch; 3138859Sbostic char buf[2048 + 1]; 3238859Sbostic 33*55201Sbostic if ((fp = fopen(name, "r")) == NULL) 34*55201Sbostic err("%s: %s\n", name, strerror(errno)); 3538859Sbostic while (fgets(buf, sizeof(buf), fp)) { 3638859Sbostic if (!(p = index(buf, '\n'))) { 3738859Sbostic (void)fprintf(stderr, "hexdump: line too long.\n"); 3838859Sbostic while ((ch = getchar()) != '\n' && ch != EOF); 3938859Sbostic continue; 4038859Sbostic } 4138859Sbostic *p = '\0'; 4238859Sbostic for (p = buf; *p && isspace(*p); ++p); 4338859Sbostic if (!*p || *p == '#') 4438859Sbostic continue; 4538859Sbostic add(p); 4638859Sbostic } 4738859Sbostic (void)fclose(fp); 4838859Sbostic } 4938859Sbostic 50*55201Sbostic void 5147173Sbostic add(fmt) 5247173Sbostic char *fmt; 5338859Sbostic { 5438859Sbostic register char *p; 5538859Sbostic static FS **nextfs; 5638859Sbostic FS *tfs; 5738859Sbostic FU *tfu, **nextfu; 58*55201Sbostic char *savep; 5938859Sbostic 6038859Sbostic /* start new linked list of format units */ 61*55201Sbostic tfs = emalloc(sizeof(FS)); 6238859Sbostic if (!fshead) 6338859Sbostic fshead = tfs; 6438859Sbostic else 6538859Sbostic *nextfs = tfs; 6638859Sbostic nextfs = &tfs->nextfs; 6738859Sbostic nextfu = &tfs->nextfu; 6838859Sbostic 6938859Sbostic /* take the format string and break it up into format units */ 7038859Sbostic for (p = fmt;;) { 7138859Sbostic /* skip leading white space */ 7238859Sbostic for (; isspace(*p); ++p); 7338859Sbostic if (!*p) 7438859Sbostic break; 7538859Sbostic 7638859Sbostic /* allocate a new format unit and link it in */ 77*55201Sbostic tfu = emalloc(sizeof(FU)); 7838859Sbostic *nextfu = tfu; 7938859Sbostic nextfu = &tfu->nextfu; 8038859Sbostic tfu->reps = 1; 8138859Sbostic 8238859Sbostic /* if leading digit, repetition count */ 8338859Sbostic if (isdigit(*p)) { 8438859Sbostic for (savep = p; isdigit(*p); ++p); 8538859Sbostic if (!isspace(*p) && *p != '/') 8638859Sbostic badfmt(fmt); 8738859Sbostic /* may overwrite either white space or slash */ 8838859Sbostic tfu->reps = atoi(savep); 8938859Sbostic tfu->flags = F_SETREP; 9038859Sbostic /* skip trailing white space */ 9138859Sbostic for (++p; isspace(*p); ++p); 9238859Sbostic } 9338859Sbostic 9438859Sbostic /* skip slash and trailing white space */ 9538859Sbostic if (*p == '/') 9638859Sbostic while (isspace(*++p)); 9738859Sbostic 9838859Sbostic /* byte count */ 9938859Sbostic if (isdigit(*p)) { 10038859Sbostic for (savep = p; isdigit(*p); ++p); 10138859Sbostic if (!isspace(*p)) 10238859Sbostic badfmt(fmt); 10338859Sbostic tfu->bcnt = atoi(savep); 10438859Sbostic /* skip trailing white space */ 10538859Sbostic for (++p; isspace(*p); ++p); 10638859Sbostic } 10738859Sbostic 10838859Sbostic /* format */ 10938859Sbostic if (*p != '"') 11038859Sbostic badfmt(fmt); 11147173Sbostic for (savep = ++p; *p != '"';) 11247173Sbostic if (*p++ == 0) 11347173Sbostic badfmt(fmt); 11447173Sbostic if (!(tfu->fmt = malloc(p - savep + 1))) 11538859Sbostic nomem(); 11647173Sbostic (void) strncpy(tfu->fmt, savep, p - savep); 11747173Sbostic tfu->fmt[p - savep] = '\0'; 11838859Sbostic escape(tfu->fmt); 11947173Sbostic p++; 12038859Sbostic } 12138859Sbostic } 12238859Sbostic 12338859Sbostic static char *spec = ".#-+ 0123456789"; 124*55201Sbostic 125*55201Sbostic int 12638859Sbostic size(fs) 12738859Sbostic FS *fs; 12838859Sbostic { 12938859Sbostic register FU *fu; 13038859Sbostic register int bcnt, cursize; 13138859Sbostic register char *fmt; 13238859Sbostic int prec; 13338859Sbostic 13438859Sbostic /* figure out the data block size needed for each format unit */ 13538859Sbostic for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { 13638859Sbostic if (fu->bcnt) { 13738859Sbostic cursize += fu->bcnt * fu->reps; 13838859Sbostic continue; 13938859Sbostic } 14038859Sbostic for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { 14138859Sbostic if (*fmt != '%') 14238859Sbostic continue; 14338859Sbostic /* 14438859Sbostic * skip any special chars -- save precision in 14538859Sbostic * case it's a %s format. 14638859Sbostic */ 14738859Sbostic while (index(spec + 1, *++fmt)); 14838859Sbostic if (*fmt == '.' && isdigit(*++fmt)) { 14938859Sbostic prec = atoi(fmt); 15038859Sbostic while (isdigit(*++fmt)); 15138859Sbostic } 15238859Sbostic switch(*fmt) { 15338859Sbostic case 'c': 15438859Sbostic bcnt += 1; 15538859Sbostic break; 15638859Sbostic case 'd': case 'i': case 'o': case 'u': 15738859Sbostic case 'x': case 'X': 15838859Sbostic bcnt += 4; 15938859Sbostic break; 16038859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': 16138859Sbostic bcnt += 8; 16238859Sbostic break; 16338859Sbostic case 's': 16438859Sbostic bcnt += prec; 16538859Sbostic break; 16638859Sbostic case '_': 16738859Sbostic switch(*++fmt) { 16838859Sbostic case 'c': case 'p': case 'u': 16938859Sbostic bcnt += 1; 17038859Sbostic break; 17138859Sbostic } 17238859Sbostic } 17338859Sbostic } 17438859Sbostic cursize += bcnt * fu->reps; 17538859Sbostic } 176*55201Sbostic return (cursize); 17738859Sbostic } 17838859Sbostic 179*55201Sbostic void 18038859Sbostic rewrite(fs) 18138859Sbostic FS *fs; 18238859Sbostic { 18338859Sbostic enum { NOTOKAY, USEBCNT, USEPREC } sokay; 18438859Sbostic register PR *pr, **nextpr; 18538859Sbostic register FU *fu; 18638859Sbostic register char *p1, *p2; 187*55201Sbostic char savech, *fmtp, cs[3]; 18838859Sbostic int nconv, prec; 18938859Sbostic 19038859Sbostic for (fu = fs->nextfu; fu; fu = fu->nextfu) { 19138859Sbostic /* 192*55201Sbostic * Break each format unit into print units; each conversion 193*55201Sbostic * character gets its own. 19438859Sbostic */ 19538859Sbostic for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 196*55201Sbostic pr = emalloc(sizeof(PR)); 19738859Sbostic if (!fu->nextpr) 19838859Sbostic fu->nextpr = pr; 19938859Sbostic else 20038859Sbostic *nextpr = pr; 20138859Sbostic 202*55201Sbostic /* Skip preceding text and up to the next % sign. */ 20338859Sbostic for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); 20438859Sbostic 205*55201Sbostic /* Only text in the string. */ 20638859Sbostic if (!*p1) { 20738859Sbostic pr->fmt = fmtp; 20838859Sbostic pr->flags = F_TEXT; 20938859Sbostic break; 21038859Sbostic } 21138859Sbostic 21238859Sbostic /* 213*55201Sbostic * Get precision for %s -- if have a byte count, don't 21438859Sbostic * need it. 21538859Sbostic */ 21638859Sbostic if (fu->bcnt) { 21738859Sbostic sokay = USEBCNT; 218*55201Sbostic /* Skip to conversion character. */ 21938859Sbostic for (++p1; index(spec, *p1); ++p1); 22038859Sbostic } else { 221*55201Sbostic /* Skip any special chars, field width. */ 22238859Sbostic while (index(spec + 1, *++p1)); 22338859Sbostic if (*p1 == '.' && isdigit(*++p1)) { 22438859Sbostic sokay = USEPREC; 22538859Sbostic prec = atoi(p1); 22638859Sbostic while (isdigit(*++p1)); 227*55201Sbostic } else 22838859Sbostic sokay = NOTOKAY; 22938859Sbostic } 23038859Sbostic 231*55201Sbostic p2 = p1 + 1; /* Set end pointer. */ 232*55201Sbostic cs[0] = *p1; /* Set conversion string. */ 233*55201Sbostic cs[1] = '\0'; 23438859Sbostic 23538859Sbostic /* 236*55201Sbostic * Figure out the byte count for each conversion; 23738859Sbostic * rewrite the format as necessary, set up blank- 23838859Sbostic * padding for end of data. 23938859Sbostic */ 240*55201Sbostic switch(cs[0]) { 24138859Sbostic case 'c': 24238859Sbostic pr->flags = F_CHAR; 24338859Sbostic switch(fu->bcnt) { 24438859Sbostic case 0: case 1: 24538859Sbostic pr->bcnt = 1; 24638859Sbostic break; 24738859Sbostic default: 24838859Sbostic p1[1] = '\0'; 24938859Sbostic badcnt(p1); 25038859Sbostic } 25138859Sbostic break; 25238859Sbostic case 'd': case 'i': 25338859Sbostic pr->flags = F_INT; 254*55201Sbostic goto isint; 25538859Sbostic case 'o': case 'u': case 'x': case 'X': 25638859Sbostic pr->flags = F_UINT; 257*55201Sbostic isint: cs[2] = '\0'; 258*55201Sbostic cs[1] = cs[0]; 259*55201Sbostic cs[0] = 'q'; 260*55201Sbostic switch(fu->bcnt) { 26138859Sbostic case 0: case 4: 26238859Sbostic pr->bcnt = 4; 26338859Sbostic break; 26438859Sbostic case 1: 26538859Sbostic pr->bcnt = 1; 26638859Sbostic break; 26738859Sbostic case 2: 26838859Sbostic pr->bcnt = 2; 26938859Sbostic break; 27038859Sbostic default: 27138859Sbostic p1[1] = '\0'; 27238859Sbostic badcnt(p1); 27338859Sbostic } 27438859Sbostic break; 27538859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': 27638859Sbostic pr->flags = F_DBL; 27738859Sbostic switch(fu->bcnt) { 27838859Sbostic case 0: case 8: 27938859Sbostic pr->bcnt = 8; 28038859Sbostic break; 28138859Sbostic case 4: 28238859Sbostic pr->bcnt = 4; 28338859Sbostic break; 28438859Sbostic default: 28538859Sbostic p1[1] = '\0'; 28638859Sbostic badcnt(p1); 28738859Sbostic } 28838859Sbostic break; 28938859Sbostic case 's': 29038859Sbostic pr->flags = F_STR; 29138859Sbostic switch(sokay) { 29238859Sbostic case NOTOKAY: 29338859Sbostic badsfmt(); 29438859Sbostic case USEBCNT: 29538859Sbostic pr->bcnt = fu->bcnt; 29638859Sbostic break; 29738859Sbostic case USEPREC: 29838859Sbostic pr->bcnt = prec; 29938859Sbostic break; 30038859Sbostic } 30138859Sbostic break; 30238859Sbostic case '_': 30338859Sbostic ++p2; 30438859Sbostic switch(p1[1]) { 30538859Sbostic case 'A': 30638859Sbostic endfu = fu; 30738859Sbostic fu->flags |= F_IGNORE; 30838859Sbostic /* FALLTHROUGH */ 30938859Sbostic case 'a': 31038859Sbostic pr->flags = F_ADDRESS; 31138859Sbostic ++p2; 31238859Sbostic switch(p1[2]) { 31338859Sbostic case 'd': case 'o': case'x': 314*55201Sbostic cs[0] = 'q'; 315*55201Sbostic cs[1] = p1[2]; 316*55201Sbostic cs[2] = '\0'; 31738859Sbostic break; 31838859Sbostic default: 31938859Sbostic p1[3] = '\0'; 32038859Sbostic badconv(p1); 32138859Sbostic } 32238859Sbostic break; 32338859Sbostic case 'c': 32438859Sbostic pr->flags = F_C; 325*55201Sbostic /* cs[0] = 'c'; set in conv_c */ 326*55201Sbostic goto isint2; 32738859Sbostic case 'p': 32838859Sbostic pr->flags = F_P; 329*55201Sbostic cs[0] = 'c'; 330*55201Sbostic goto isint2; 33138859Sbostic case 'u': 33238859Sbostic pr->flags = F_U; 333*55201Sbostic /* cs[0] = 'c'; set in conv_u */ 334*55201Sbostic isint2: switch(fu->bcnt) { 33538859Sbostic case 0: case 1: 33638859Sbostic pr->bcnt = 1; 33738859Sbostic break; 33838859Sbostic default: 33938859Sbostic p1[2] = '\0'; 34038859Sbostic badcnt(p1); 34138859Sbostic } 34238859Sbostic break; 34338859Sbostic default: 34438859Sbostic p1[2] = '\0'; 34538859Sbostic badconv(p1); 34638859Sbostic } 34738859Sbostic break; 34838859Sbostic default: 34938859Sbostic p1[1] = '\0'; 35038859Sbostic badconv(p1); 35138859Sbostic } 35238859Sbostic 35338859Sbostic /* 354*55201Sbostic * Copy to PR format string, set conversion character 35538859Sbostic * pointer, update original. 35638859Sbostic */ 35738859Sbostic savech = *p2; 358*55201Sbostic p1[0] = '\0'; 359*55201Sbostic pr->fmt = emalloc(strlen(fmtp) + 2); 360*55201Sbostic (void)strcpy(pr->fmt, fmtp); 361*55201Sbostic (void)strcat(pr->fmt, cs); 36238859Sbostic *p2 = savech; 36338859Sbostic pr->cchar = pr->fmt + (p1 - fmtp); 36438859Sbostic fmtp = p2; 36538859Sbostic 366*55201Sbostic /* Only one conversion character if byte count. */ 367*55201Sbostic if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) 368*55201Sbostic err("byte count with multiple conversion characters"); 36938859Sbostic } 37038859Sbostic /* 371*55201Sbostic * If format unit byte count not specified, figure it out 37238859Sbostic * so can adjust rep count later. 37338859Sbostic */ 37438859Sbostic if (!fu->bcnt) 37538859Sbostic for (pr = fu->nextpr; pr; pr = pr->nextpr) 37638859Sbostic fu->bcnt += pr->bcnt; 37738859Sbostic } 37838859Sbostic /* 379*55201Sbostic * If the format string interprets any data at all, and it's 38038859Sbostic * not the same as the blocksize, and its last format unit 38138859Sbostic * interprets any data at all, and has no iteration count, 38238859Sbostic * repeat it as necessary. 38338859Sbostic * 384*55201Sbostic * If, rep count is greater than 1, no trailing whitespace 38538859Sbostic * gets output from the last iteration of the format unit. 38638859Sbostic */ 38738859Sbostic for (fu = fs->nextfu;; fu = fu->nextfu) { 38838859Sbostic if (!fu->nextfu && fs->bcnt < blocksize && 38938859Sbostic !(fu->flags&F_SETREP) && fu->bcnt) 39038859Sbostic fu->reps += (blocksize - fs->bcnt) / fu->bcnt; 39138859Sbostic if (fu->reps > 1) { 39238859Sbostic for (pr = fu->nextpr;; pr = pr->nextpr) 39338859Sbostic if (!pr->nextpr) 39438859Sbostic break; 39538859Sbostic for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 39638859Sbostic p2 = isspace(*p1) ? p1 : NULL; 39738859Sbostic if (p2) 39838859Sbostic pr->nospace = p2; 39938859Sbostic } 40038859Sbostic if (!fu->nextfu) 40138859Sbostic break; 40238859Sbostic } 403*55201Sbostic #ifdef DEBUG 404*55201Sbostic for (fu = fs->nextfu; fu; fu = fu->nextfu) { 405*55201Sbostic (void)printf("fmt:"); 406*55201Sbostic for (pr = fu->nextpr; pr; pr = pr->nextpr) 407*55201Sbostic (void)printf(" {%s}", pr->fmt); 408*55201Sbostic (void)printf("\n"); 409*55201Sbostic } 410*55201Sbostic #endif 41138859Sbostic } 41238859Sbostic 413*55201Sbostic void 41438859Sbostic escape(p1) 41538859Sbostic register char *p1; 41638859Sbostic { 41738859Sbostic register char *p2; 41838859Sbostic 41938859Sbostic /* alphabetic escape sequences have to be done in place */ 42038859Sbostic for (p2 = p1;; ++p1, ++p2) { 42138859Sbostic if (!*p1) { 42238859Sbostic *p2 = *p1; 42338859Sbostic break; 42438859Sbostic } 42538859Sbostic if (*p1 == '\\') 42638859Sbostic switch(*++p1) { 42738859Sbostic case 'a': 42838859Sbostic /* *p2 = '\a'; */ 42938859Sbostic *p2 = '\007'; 43038859Sbostic break; 43138859Sbostic case 'b': 43238859Sbostic *p2 = '\b'; 43338859Sbostic break; 43438859Sbostic case 'f': 43538859Sbostic *p2 = '\f'; 43638859Sbostic break; 43738859Sbostic case 'n': 43838859Sbostic *p2 = '\n'; 43938859Sbostic break; 44038859Sbostic case 'r': 44138859Sbostic *p2 = '\r'; 44238859Sbostic break; 44338859Sbostic case 't': 44438859Sbostic *p2 = '\t'; 44538859Sbostic break; 44638859Sbostic case 'v': 44738859Sbostic *p2 = '\v'; 44838859Sbostic break; 44938859Sbostic default: 45038859Sbostic *p2 = *p1; 45138859Sbostic break; 45238859Sbostic } 45338859Sbostic } 45438859Sbostic } 45538859Sbostic 456*55201Sbostic void 45738859Sbostic badcnt(s) 45838859Sbostic char *s; 45938859Sbostic { 460*55201Sbostic err("%s: bad byte count", s); 46138859Sbostic } 46238859Sbostic 463*55201Sbostic void 46438859Sbostic badsfmt() 46538859Sbostic { 466*55201Sbostic err("%%s: requires a precision or a byte count\n"); 46738859Sbostic } 46838859Sbostic 469*55201Sbostic void 47038859Sbostic badfmt(fmt) 47138859Sbostic char *fmt; 47238859Sbostic { 473*55201Sbostic err("\"%s\": bad format\n", fmt); 47438859Sbostic } 47538859Sbostic 476*55201Sbostic void 47738859Sbostic badconv(ch) 47838859Sbostic char *ch; 47938859Sbostic { 480*55201Sbostic err("%%%s: bad conversion character\n", ch); 48138859Sbostic } 482