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