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