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*47173Sbostic static char sccsid[] = "@(#)parse.c 5.6 (Berkeley) 03/09/91"; 1038859Sbostic #endif /* not lint */ 1138859Sbostic 1238859Sbostic #include <sys/types.h> 1338859Sbostic #include <sys/file.h> 1438859Sbostic #include <stdio.h> 15*47173Sbostic #include <stdlib.h> 1638859Sbostic #include <ctype.h> 1742056Sbostic #include <string.h> 1838859Sbostic #include "hexdump.h" 1938859Sbostic 2038859Sbostic FU *endfu; /* format at end-of-data */ 2138859Sbostic 2238859Sbostic addfile(name) 2338859Sbostic char *name; 2438859Sbostic { 2538859Sbostic register char *p; 2638859Sbostic FILE *fp; 2738859Sbostic int ch; 2838859Sbostic char buf[2048 + 1]; 2938859Sbostic 3038859Sbostic if (!(fp = fopen(name, "r"))) { 3138859Sbostic (void)fprintf(stderr, "hexdump: can't read %s.\n", name); 3238859Sbostic exit(1); 3338859Sbostic } 3438859Sbostic while (fgets(buf, sizeof(buf), fp)) { 3538859Sbostic if (!(p = index(buf, '\n'))) { 3638859Sbostic (void)fprintf(stderr, "hexdump: line too long.\n"); 3738859Sbostic while ((ch = getchar()) != '\n' && ch != EOF); 3838859Sbostic continue; 3938859Sbostic } 4038859Sbostic *p = '\0'; 4138859Sbostic for (p = buf; *p && isspace(*p); ++p); 4238859Sbostic if (!*p || *p == '#') 4338859Sbostic continue; 4438859Sbostic add(p); 4538859Sbostic } 4638859Sbostic (void)fclose(fp); 4738859Sbostic } 4838859Sbostic 49*47173Sbostic add(fmt) 50*47173Sbostic char *fmt; 5138859Sbostic { 5238859Sbostic register char *p; 5338859Sbostic static FS **nextfs; 5438859Sbostic FS *tfs; 5538859Sbostic FU *tfu, **nextfu; 56*47173Sbostic char *savep, *emalloc(); 5738859Sbostic 5838859Sbostic /* start new linked list of format units */ 5938859Sbostic /* NOSTRICT */ 6038859Sbostic tfs = (FS *)emalloc(sizeof(FS)); 6138859Sbostic if (!fshead) 6238859Sbostic fshead = tfs; 6338859Sbostic else 6438859Sbostic *nextfs = tfs; 6538859Sbostic nextfs = &tfs->nextfs; 6638859Sbostic nextfu = &tfs->nextfu; 6738859Sbostic 6838859Sbostic /* take the format string and break it up into format units */ 6938859Sbostic for (p = fmt;;) { 7038859Sbostic /* skip leading white space */ 7138859Sbostic for (; isspace(*p); ++p); 7238859Sbostic if (!*p) 7338859Sbostic break; 7438859Sbostic 7538859Sbostic /* allocate a new format unit and link it in */ 7638859Sbostic /* NOSTRICT */ 7738859Sbostic tfu = (FU *)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); 111*47173Sbostic for (savep = ++p; *p != '"';) 112*47173Sbostic if (*p++ == 0) 113*47173Sbostic badfmt(fmt); 114*47173Sbostic if (!(tfu->fmt = malloc(p - savep + 1))) 11538859Sbostic nomem(); 116*47173Sbostic (void) strncpy(tfu->fmt, savep, p - savep); 117*47173Sbostic tfu->fmt[p - savep] = '\0'; 11838859Sbostic escape(tfu->fmt); 119*47173Sbostic p++; 12038859Sbostic } 12138859Sbostic } 12238859Sbostic 12338859Sbostic static char *spec = ".#-+ 0123456789"; 12438859Sbostic size(fs) 12538859Sbostic FS *fs; 12638859Sbostic { 12738859Sbostic register FU *fu; 12838859Sbostic register int bcnt, cursize; 12938859Sbostic register char *fmt; 13038859Sbostic int prec; 13138859Sbostic 13238859Sbostic /* figure out the data block size needed for each format unit */ 13338859Sbostic for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { 13438859Sbostic if (fu->bcnt) { 13538859Sbostic cursize += fu->bcnt * fu->reps; 13638859Sbostic continue; 13738859Sbostic } 13838859Sbostic for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { 13938859Sbostic if (*fmt != '%') 14038859Sbostic continue; 14138859Sbostic /* 14238859Sbostic * skip any special chars -- save precision in 14338859Sbostic * case it's a %s format. 14438859Sbostic */ 14538859Sbostic while (index(spec + 1, *++fmt)); 14638859Sbostic if (*fmt == '.' && isdigit(*++fmt)) { 14738859Sbostic prec = atoi(fmt); 14838859Sbostic while (isdigit(*++fmt)); 14938859Sbostic } 15038859Sbostic switch(*fmt) { 15138859Sbostic case 'c': 15238859Sbostic bcnt += 1; 15338859Sbostic break; 15438859Sbostic case 'd': case 'i': case 'o': case 'u': 15538859Sbostic case 'x': case 'X': 15638859Sbostic bcnt += 4; 15738859Sbostic break; 15838859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': 15938859Sbostic bcnt += 8; 16038859Sbostic break; 16138859Sbostic case 's': 16238859Sbostic bcnt += prec; 16338859Sbostic break; 16438859Sbostic case '_': 16538859Sbostic switch(*++fmt) { 16638859Sbostic case 'c': case 'p': case 'u': 16738859Sbostic bcnt += 1; 16838859Sbostic break; 16938859Sbostic } 17038859Sbostic } 17138859Sbostic } 17238859Sbostic cursize += bcnt * fu->reps; 17338859Sbostic } 17438859Sbostic return(cursize); 17538859Sbostic } 17638859Sbostic 17738859Sbostic rewrite(fs) 17838859Sbostic FS *fs; 17938859Sbostic { 18038859Sbostic enum { NOTOKAY, USEBCNT, USEPREC } sokay; 18138859Sbostic register PR *pr, **nextpr; 18238859Sbostic register FU *fu; 18338859Sbostic register char *p1, *p2; 18438859Sbostic char savech, *fmtp; 18538859Sbostic int nconv, prec; 18638859Sbostic 18738859Sbostic for (fu = fs->nextfu; fu; fu = fu->nextfu) { 18838859Sbostic /* 18938859Sbostic * break each format unit into print units; each 19038859Sbostic * conversion character gets its own. 19138859Sbostic */ 19238859Sbostic for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 19338859Sbostic /* NOSTRICT */ 19438859Sbostic pr = (PR *)emalloc(sizeof(PR)); 19538859Sbostic if (!fu->nextpr) 19638859Sbostic fu->nextpr = pr; 19738859Sbostic else 19838859Sbostic *nextpr = pr; 19938859Sbostic 20038859Sbostic /* skip preceding text and up to the next % sign */ 20138859Sbostic for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); 20238859Sbostic 20338859Sbostic /* only text in the string */ 20438859Sbostic if (!*p1) { 20538859Sbostic pr->fmt = fmtp; 20638859Sbostic pr->flags = F_TEXT; 20738859Sbostic break; 20838859Sbostic } 20938859Sbostic 21038859Sbostic /* 21138859Sbostic * get precision for %s -- if have a byte count, don't 21238859Sbostic * need it. 21338859Sbostic */ 21438859Sbostic if (fu->bcnt) { 21538859Sbostic sokay = USEBCNT; 21638859Sbostic /* skip to conversion character */ 21738859Sbostic for (++p1; index(spec, *p1); ++p1); 21838859Sbostic } else { 21938859Sbostic /* skip any special chars, field width */ 22038859Sbostic while (index(spec + 1, *++p1)); 22138859Sbostic if (*p1 == '.' && isdigit(*++p1)) { 22238859Sbostic sokay = USEPREC; 22338859Sbostic prec = atoi(p1); 22438859Sbostic while (isdigit(*++p1)); 22538859Sbostic } 22638859Sbostic else 22738859Sbostic sokay = NOTOKAY; 22838859Sbostic } 22938859Sbostic 23038859Sbostic p2 = p1 + 1; /* set end pointer */ 23138859Sbostic 23238859Sbostic /* 23338859Sbostic * figure out the byte count for each conversion; 23438859Sbostic * rewrite the format as necessary, set up blank- 23538859Sbostic * padding for end of data. 23638859Sbostic */ 23738859Sbostic switch(*p1) { 23838859Sbostic case 'c': 23938859Sbostic pr->flags = F_CHAR; 24038859Sbostic switch(fu->bcnt) { 24138859Sbostic case 0: case 1: 24238859Sbostic pr->bcnt = 1; 24338859Sbostic break; 24438859Sbostic default: 24538859Sbostic p1[1] = '\0'; 24638859Sbostic badcnt(p1); 24738859Sbostic } 24838859Sbostic break; 24938859Sbostic case 'd': case 'i': 25038859Sbostic pr->flags = F_INT; 25138859Sbostic goto sw1; 25241454Sbostic case 'l': 25341454Sbostic ++p2; 25441454Sbostic switch(p1[1]) { 25541454Sbostic case 'd': case 'i': 25641454Sbostic ++p1; 25741454Sbostic pr->flags = F_INT; 25841454Sbostic goto sw1; 25941454Sbostic case 'o': case 'u': case 'x': case 'X': 26041454Sbostic ++p1; 26141454Sbostic pr->flags = F_UINT; 26241454Sbostic goto sw1; 26341454Sbostic default: 26441454Sbostic p1[2] = '\0'; 26541454Sbostic badconv(p1); 26641454Sbostic } 26741454Sbostic /* NOTREACHED */ 26838859Sbostic case 'o': case 'u': case 'x': case 'X': 26938859Sbostic pr->flags = F_UINT; 27038859Sbostic sw1: switch(fu->bcnt) { 27138859Sbostic case 0: case 4: 27238859Sbostic pr->bcnt = 4; 27338859Sbostic break; 27438859Sbostic case 1: 27538859Sbostic pr->bcnt = 1; 27638859Sbostic break; 27738859Sbostic case 2: 27838859Sbostic pr->bcnt = 2; 27938859Sbostic break; 28038859Sbostic default: 28138859Sbostic p1[1] = '\0'; 28238859Sbostic badcnt(p1); 28338859Sbostic } 28438859Sbostic break; 28538859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': 28638859Sbostic pr->flags = F_DBL; 28738859Sbostic switch(fu->bcnt) { 28838859Sbostic case 0: case 8: 28938859Sbostic pr->bcnt = 8; 29038859Sbostic break; 29138859Sbostic case 4: 29238859Sbostic pr->bcnt = 4; 29338859Sbostic break; 29438859Sbostic default: 29538859Sbostic p1[1] = '\0'; 29638859Sbostic badcnt(p1); 29738859Sbostic } 29838859Sbostic break; 29938859Sbostic case 's': 30038859Sbostic pr->flags = F_STR; 30138859Sbostic switch(sokay) { 30238859Sbostic case NOTOKAY: 30338859Sbostic badsfmt(); 30438859Sbostic case USEBCNT: 30538859Sbostic pr->bcnt = fu->bcnt; 30638859Sbostic break; 30738859Sbostic case USEPREC: 30838859Sbostic pr->bcnt = prec; 30938859Sbostic break; 31038859Sbostic } 31138859Sbostic break; 31238859Sbostic case '_': 31338859Sbostic ++p2; 31438859Sbostic switch(p1[1]) { 31538859Sbostic case 'A': 31638859Sbostic endfu = fu; 31738859Sbostic fu->flags |= F_IGNORE; 31838859Sbostic /* FALLTHROUGH */ 31938859Sbostic case 'a': 32038859Sbostic pr->flags = F_ADDRESS; 32138859Sbostic ++p2; 32238859Sbostic switch(p1[2]) { 32338859Sbostic case 'd': case 'o': case'x': 32438859Sbostic *p1 = p1[2]; 32538859Sbostic break; 32638859Sbostic default: 32738859Sbostic p1[3] = '\0'; 32838859Sbostic badconv(p1); 32938859Sbostic } 33038859Sbostic break; 33138859Sbostic case 'c': 33238859Sbostic pr->flags = F_C; 33338859Sbostic /* *p1 = 'c'; set in conv_c */ 33438859Sbostic goto sw2; 33538859Sbostic case 'p': 33638859Sbostic pr->flags = F_P; 33738859Sbostic *p1 = 'c'; 33838859Sbostic goto sw2; 33938859Sbostic case 'u': 34038859Sbostic pr->flags = F_U; 34138859Sbostic /* *p1 = 'c'; set in conv_u */ 34238859Sbostic sw2: switch(fu->bcnt) { 34338859Sbostic case 0: case 1: 34438859Sbostic pr->bcnt = 1; 34538859Sbostic break; 34638859Sbostic default: 34738859Sbostic p1[2] = '\0'; 34838859Sbostic badcnt(p1); 34938859Sbostic } 35038859Sbostic break; 35138859Sbostic default: 35238859Sbostic p1[2] = '\0'; 35338859Sbostic badconv(p1); 35438859Sbostic } 35538859Sbostic break; 35638859Sbostic default: 35738859Sbostic p1[1] = '\0'; 35838859Sbostic badconv(p1); 35938859Sbostic } 36038859Sbostic 36138859Sbostic /* 36238859Sbostic * copy to PR format string, set conversion character 36338859Sbostic * pointer, update original. 36438859Sbostic */ 36538859Sbostic savech = *p2; 36638859Sbostic p1[1] = '\0'; 36738859Sbostic if (!(pr->fmt = strdup(fmtp))) 36838859Sbostic nomem(); 36938859Sbostic *p2 = savech; 37038859Sbostic pr->cchar = pr->fmt + (p1 - fmtp); 37138859Sbostic fmtp = p2; 37238859Sbostic 37338859Sbostic /* only one conversion character if byte count */ 37438859Sbostic if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) { 37538859Sbostic (void)fprintf(stderr, 37638859Sbostic "hexdump: byte count with multiple conversion characters.\n"); 37738859Sbostic exit(1); 37838859Sbostic } 37938859Sbostic } 38038859Sbostic /* 38138859Sbostic * if format unit byte count not specified, figure it out 38238859Sbostic * so can adjust rep count later. 38338859Sbostic */ 38438859Sbostic if (!fu->bcnt) 38538859Sbostic for (pr = fu->nextpr; pr; pr = pr->nextpr) 38638859Sbostic fu->bcnt += pr->bcnt; 38738859Sbostic } 38838859Sbostic /* 38938859Sbostic * if the format string interprets any data at all, and it's 39038859Sbostic * not the same as the blocksize, and its last format unit 39138859Sbostic * interprets any data at all, and has no iteration count, 39238859Sbostic * repeat it as necessary. 39338859Sbostic * 39438859Sbostic * if, rep count is greater than 1, no trailing whitespace 39538859Sbostic * gets output from the last iteration of the format unit. 39638859Sbostic */ 39738859Sbostic for (fu = fs->nextfu;; fu = fu->nextfu) { 39838859Sbostic if (!fu->nextfu && fs->bcnt < blocksize && 39938859Sbostic !(fu->flags&F_SETREP) && fu->bcnt) 40038859Sbostic fu->reps += (blocksize - fs->bcnt) / fu->bcnt; 40138859Sbostic if (fu->reps > 1) { 40238859Sbostic for (pr = fu->nextpr;; pr = pr->nextpr) 40338859Sbostic if (!pr->nextpr) 40438859Sbostic break; 40538859Sbostic for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 40638859Sbostic p2 = isspace(*p1) ? p1 : NULL; 40738859Sbostic if (p2) 40838859Sbostic pr->nospace = p2; 40938859Sbostic } 41038859Sbostic if (!fu->nextfu) 41138859Sbostic break; 41238859Sbostic } 41338859Sbostic } 41438859Sbostic 41538859Sbostic 41638859Sbostic escape(p1) 41738859Sbostic register char *p1; 41838859Sbostic { 41938859Sbostic register char *p2; 42038859Sbostic 42138859Sbostic /* alphabetic escape sequences have to be done in place */ 42238859Sbostic for (p2 = p1;; ++p1, ++p2) { 42338859Sbostic if (!*p1) { 42438859Sbostic *p2 = *p1; 42538859Sbostic break; 42638859Sbostic } 42738859Sbostic if (*p1 == '\\') 42838859Sbostic switch(*++p1) { 42938859Sbostic case 'a': 43038859Sbostic /* *p2 = '\a'; */ 43138859Sbostic *p2 = '\007'; 43238859Sbostic break; 43338859Sbostic case 'b': 43438859Sbostic *p2 = '\b'; 43538859Sbostic break; 43638859Sbostic case 'f': 43738859Sbostic *p2 = '\f'; 43838859Sbostic break; 43938859Sbostic case 'n': 44038859Sbostic *p2 = '\n'; 44138859Sbostic break; 44238859Sbostic case 'r': 44338859Sbostic *p2 = '\r'; 44438859Sbostic break; 44538859Sbostic case 't': 44638859Sbostic *p2 = '\t'; 44738859Sbostic break; 44838859Sbostic case 'v': 44938859Sbostic *p2 = '\v'; 45038859Sbostic break; 45138859Sbostic default: 45238859Sbostic *p2 = *p1; 45338859Sbostic break; 45438859Sbostic } 45538859Sbostic } 45638859Sbostic } 45738859Sbostic 45838859Sbostic badcnt(s) 45938859Sbostic char *s; 46038859Sbostic { 46138859Sbostic (void)fprintf(stderr, 46238859Sbostic "hexdump: bad byte count for conversion character %s.\n", s); 46338859Sbostic exit(1); 46438859Sbostic } 46538859Sbostic 46638859Sbostic badsfmt() 46738859Sbostic { 46838859Sbostic (void)fprintf(stderr, 46938859Sbostic "hexdump: %%s requires a precision or a byte count.\n"); 47038859Sbostic exit(1); 47138859Sbostic } 47238859Sbostic 47338859Sbostic badfmt(fmt) 47438859Sbostic char *fmt; 47538859Sbostic { 47638859Sbostic (void)fprintf(stderr, "hexdump: bad format {%s}\n", fmt); 47738859Sbostic exit(1); 47838859Sbostic } 47938859Sbostic 48038859Sbostic badconv(ch) 48138859Sbostic char *ch; 48238859Sbostic { 48341454Sbostic (void)fprintf(stderr, "hexdump: bad conversion character %%%s.\n", ch); 48438859Sbostic exit(1); 48538859Sbostic } 486