1*38859Sbostic /* 2*38859Sbostic * Copyright (c) 1989 The Regents of the University of California. 3*38859Sbostic * All rights reserved. 4*38859Sbostic * 5*38859Sbostic * Redistribution and use in source and binary forms are permitted 6*38859Sbostic * provided that the above copyright notice and this paragraph are 7*38859Sbostic * duplicated in all such forms and that any documentation, 8*38859Sbostic * advertising materials, and other materials related to such 9*38859Sbostic * distribution and use acknowledge that the software was developed 10*38859Sbostic * by the University of California, Berkeley. The name of the 11*38859Sbostic * University may not be used to endorse or promote products derived 12*38859Sbostic * from this software without specific prior written permission. 13*38859Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38859Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38859Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*38859Sbostic */ 17*38859Sbostic 18*38859Sbostic #ifndef lint 19*38859Sbostic static char sccsid[] = "@(#)parse.c 5.1 (Berkeley) 08/29/89"; 20*38859Sbostic #endif /* not lint */ 21*38859Sbostic 22*38859Sbostic #include <sys/types.h> 23*38859Sbostic #include <sys/file.h> 24*38859Sbostic #include <stdio.h> 25*38859Sbostic #include <ctype.h> 26*38859Sbostic #include <strings.h> 27*38859Sbostic #include "hexdump.h" 28*38859Sbostic 29*38859Sbostic FU *endfu; /* format at end-of-data */ 30*38859Sbostic 31*38859Sbostic addfile(name) 32*38859Sbostic char *name; 33*38859Sbostic { 34*38859Sbostic register char *p; 35*38859Sbostic FILE *fp; 36*38859Sbostic int ch; 37*38859Sbostic char buf[2048 + 1]; 38*38859Sbostic 39*38859Sbostic if (!(fp = fopen(name, "r"))) { 40*38859Sbostic (void)fprintf(stderr, "hexdump: can't read %s.\n", name); 41*38859Sbostic exit(1); 42*38859Sbostic } 43*38859Sbostic while (fgets(buf, sizeof(buf), fp)) { 44*38859Sbostic if (!(p = index(buf, '\n'))) { 45*38859Sbostic (void)fprintf(stderr, "hexdump: line too long.\n"); 46*38859Sbostic while ((ch = getchar()) != '\n' && ch != EOF); 47*38859Sbostic continue; 48*38859Sbostic } 49*38859Sbostic *p = '\0'; 50*38859Sbostic for (p = buf; *p && isspace(*p); ++p); 51*38859Sbostic if (!*p || *p == '#') 52*38859Sbostic continue; 53*38859Sbostic add(p); 54*38859Sbostic } 55*38859Sbostic (void)fclose(fp); 56*38859Sbostic } 57*38859Sbostic 58*38859Sbostic add(fmt) 59*38859Sbostic char *fmt; 60*38859Sbostic { 61*38859Sbostic register char *p; 62*38859Sbostic static FS **nextfs; 63*38859Sbostic FS *tfs; 64*38859Sbostic FU *tfu, **nextfu; 65*38859Sbostic char savech, *savep, *emalloc(), *strdup(); 66*38859Sbostic 67*38859Sbostic /* start new linked list of format units */ 68*38859Sbostic /* NOSTRICT */ 69*38859Sbostic tfs = (FS *)emalloc(sizeof(FS)); 70*38859Sbostic if (!fshead) 71*38859Sbostic fshead = tfs; 72*38859Sbostic else 73*38859Sbostic *nextfs = tfs; 74*38859Sbostic nextfs = &tfs->nextfs; 75*38859Sbostic nextfu = &tfs->nextfu; 76*38859Sbostic 77*38859Sbostic /* take the format string and break it up into format units */ 78*38859Sbostic for (p = fmt;;) { 79*38859Sbostic /* skip leading white space */ 80*38859Sbostic for (; isspace(*p); ++p); 81*38859Sbostic if (!*p) 82*38859Sbostic break; 83*38859Sbostic 84*38859Sbostic /* allocate a new format unit and link it in */ 85*38859Sbostic /* NOSTRICT */ 86*38859Sbostic tfu = (FU *)emalloc(sizeof(FU)); 87*38859Sbostic *nextfu = tfu; 88*38859Sbostic nextfu = &tfu->nextfu; 89*38859Sbostic tfu->reps = 1; 90*38859Sbostic 91*38859Sbostic /* if leading digit, repetition count */ 92*38859Sbostic if (isdigit(*p)) { 93*38859Sbostic for (savep = p; isdigit(*p); ++p); 94*38859Sbostic if (!isspace(*p) && *p != '/') 95*38859Sbostic badfmt(fmt); 96*38859Sbostic /* may overwrite either white space or slash */ 97*38859Sbostic savech = *p; 98*38859Sbostic *p = '\0'; 99*38859Sbostic tfu->reps = atoi(savep); 100*38859Sbostic tfu->flags = F_SETREP; 101*38859Sbostic *p = savech; 102*38859Sbostic /* skip trailing white space */ 103*38859Sbostic for (++p; isspace(*p); ++p); 104*38859Sbostic } 105*38859Sbostic 106*38859Sbostic /* skip slash and trailing white space */ 107*38859Sbostic if (*p == '/') 108*38859Sbostic while (isspace(*++p)); 109*38859Sbostic 110*38859Sbostic /* byte count */ 111*38859Sbostic if (isdigit(*p)) { 112*38859Sbostic for (savep = p; isdigit(*p); ++p); 113*38859Sbostic if (!isspace(*p)) 114*38859Sbostic badfmt(fmt); 115*38859Sbostic savech = *p; 116*38859Sbostic *p = '\0'; 117*38859Sbostic tfu->bcnt = atoi(savep); 118*38859Sbostic *p = savech; 119*38859Sbostic /* skip trailing white space */ 120*38859Sbostic for (++p; isspace(*p); ++p); 121*38859Sbostic } 122*38859Sbostic 123*38859Sbostic /* format */ 124*38859Sbostic if (*p != '"') 125*38859Sbostic badfmt(fmt); 126*38859Sbostic for (savep = ++p; *p != '"'; ++p); 127*38859Sbostic if (*p != '"') 128*38859Sbostic badfmt(fmt); 129*38859Sbostic savech = *p; 130*38859Sbostic *p = '\0'; 131*38859Sbostic if (!(tfu->fmt = strdup(savep))) 132*38859Sbostic nomem(); 133*38859Sbostic escape(tfu->fmt); 134*38859Sbostic *p++ = savech; 135*38859Sbostic } 136*38859Sbostic } 137*38859Sbostic 138*38859Sbostic static char *spec = ".#-+ 0123456789"; 139*38859Sbostic size(fs) 140*38859Sbostic FS *fs; 141*38859Sbostic { 142*38859Sbostic register FU *fu; 143*38859Sbostic register int bcnt, cursize; 144*38859Sbostic register char *fmt; 145*38859Sbostic int prec; 146*38859Sbostic 147*38859Sbostic /* figure out the data block size needed for each format unit */ 148*38859Sbostic for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { 149*38859Sbostic if (fu->bcnt) { 150*38859Sbostic cursize += fu->bcnt * fu->reps; 151*38859Sbostic continue; 152*38859Sbostic } 153*38859Sbostic for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { 154*38859Sbostic if (*fmt != '%') 155*38859Sbostic continue; 156*38859Sbostic /* 157*38859Sbostic * skip any special chars -- save precision in 158*38859Sbostic * case it's a %s format. 159*38859Sbostic */ 160*38859Sbostic while (index(spec + 1, *++fmt)); 161*38859Sbostic if (*fmt == '.' && isdigit(*++fmt)) { 162*38859Sbostic prec = atoi(fmt); 163*38859Sbostic while (isdigit(*++fmt)); 164*38859Sbostic } 165*38859Sbostic switch(*fmt) { 166*38859Sbostic case 'c': 167*38859Sbostic bcnt += 1; 168*38859Sbostic break; 169*38859Sbostic case 'd': case 'i': case 'o': case 'u': 170*38859Sbostic case 'x': case 'X': 171*38859Sbostic bcnt += 4; 172*38859Sbostic break; 173*38859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': 174*38859Sbostic bcnt += 8; 175*38859Sbostic break; 176*38859Sbostic case 's': 177*38859Sbostic bcnt += prec; 178*38859Sbostic break; 179*38859Sbostic case '_': 180*38859Sbostic switch(*++fmt) { 181*38859Sbostic case 'c': case 'p': case 'u': 182*38859Sbostic bcnt += 1; 183*38859Sbostic break; 184*38859Sbostic } 185*38859Sbostic } 186*38859Sbostic } 187*38859Sbostic cursize += bcnt * fu->reps; 188*38859Sbostic } 189*38859Sbostic return(cursize); 190*38859Sbostic } 191*38859Sbostic 192*38859Sbostic rewrite(fs) 193*38859Sbostic FS *fs; 194*38859Sbostic { 195*38859Sbostic enum { NOTOKAY, USEBCNT, USEPREC } sokay; 196*38859Sbostic register PR *pr, **nextpr; 197*38859Sbostic register FU *fu; 198*38859Sbostic register char *p1, *p2; 199*38859Sbostic char savech, *fmtp; 200*38859Sbostic int nconv, prec; 201*38859Sbostic 202*38859Sbostic for (fu = fs->nextfu; fu; fu = fu->nextfu) { 203*38859Sbostic /* 204*38859Sbostic * break each format unit into print units; each 205*38859Sbostic * conversion character gets its own. 206*38859Sbostic */ 207*38859Sbostic for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 208*38859Sbostic /* NOSTRICT */ 209*38859Sbostic pr = (PR *)emalloc(sizeof(PR)); 210*38859Sbostic if (!fu->nextpr) 211*38859Sbostic fu->nextpr = pr; 212*38859Sbostic else 213*38859Sbostic *nextpr = pr; 214*38859Sbostic 215*38859Sbostic /* skip preceding text and up to the next % sign */ 216*38859Sbostic for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); 217*38859Sbostic 218*38859Sbostic /* only text in the string */ 219*38859Sbostic if (!*p1) { 220*38859Sbostic pr->fmt = fmtp; 221*38859Sbostic pr->flags = F_TEXT; 222*38859Sbostic break; 223*38859Sbostic } 224*38859Sbostic 225*38859Sbostic /* 226*38859Sbostic * get precision for %s -- if have a byte count, don't 227*38859Sbostic * need it. 228*38859Sbostic */ 229*38859Sbostic if (fu->bcnt) { 230*38859Sbostic sokay = USEBCNT; 231*38859Sbostic /* skip to conversion character */ 232*38859Sbostic for (++p1; index(spec, *p1); ++p1); 233*38859Sbostic } else { 234*38859Sbostic /* skip any special chars, field width */ 235*38859Sbostic while (index(spec + 1, *++p1)); 236*38859Sbostic if (*p1 == '.' && isdigit(*++p1)) { 237*38859Sbostic sokay = USEPREC; 238*38859Sbostic prec = atoi(p1); 239*38859Sbostic while (isdigit(*++p1)); 240*38859Sbostic } 241*38859Sbostic else 242*38859Sbostic sokay = NOTOKAY; 243*38859Sbostic } 244*38859Sbostic 245*38859Sbostic p2 = p1 + 1; /* set end pointer */ 246*38859Sbostic 247*38859Sbostic /* 248*38859Sbostic * figure out the byte count for each conversion; 249*38859Sbostic * rewrite the format as necessary, set up blank- 250*38859Sbostic * padding for end of data. 251*38859Sbostic */ 252*38859Sbostic switch(*p1) { 253*38859Sbostic case 'c': 254*38859Sbostic pr->flags = F_CHAR; 255*38859Sbostic switch(fu->bcnt) { 256*38859Sbostic case 0: case 1: 257*38859Sbostic pr->bcnt = 1; 258*38859Sbostic break; 259*38859Sbostic default: 260*38859Sbostic p1[1] = '\0'; 261*38859Sbostic badcnt(p1); 262*38859Sbostic } 263*38859Sbostic break; 264*38859Sbostic case 'd': case 'i': 265*38859Sbostic pr->flags = F_INT; 266*38859Sbostic goto sw1; 267*38859Sbostic case 'o': case 'u': case 'x': case 'X': 268*38859Sbostic pr->flags = F_UINT; 269*38859Sbostic sw1: switch(fu->bcnt) { 270*38859Sbostic case 0: case 4: 271*38859Sbostic pr->bcnt = 4; 272*38859Sbostic break; 273*38859Sbostic case 1: 274*38859Sbostic pr->bcnt = 1; 275*38859Sbostic break; 276*38859Sbostic case 2: 277*38859Sbostic pr->bcnt = 2; 278*38859Sbostic break; 279*38859Sbostic default: 280*38859Sbostic p1[1] = '\0'; 281*38859Sbostic badcnt(p1); 282*38859Sbostic } 283*38859Sbostic break; 284*38859Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': 285*38859Sbostic pr->flags = F_DBL; 286*38859Sbostic switch(fu->bcnt) { 287*38859Sbostic case 0: case 8: 288*38859Sbostic pr->bcnt = 8; 289*38859Sbostic break; 290*38859Sbostic case 4: 291*38859Sbostic pr->bcnt = 4; 292*38859Sbostic break; 293*38859Sbostic default: 294*38859Sbostic p1[1] = '\0'; 295*38859Sbostic badcnt(p1); 296*38859Sbostic } 297*38859Sbostic break; 298*38859Sbostic case 's': 299*38859Sbostic pr->flags = F_STR; 300*38859Sbostic switch(sokay) { 301*38859Sbostic case NOTOKAY: 302*38859Sbostic badsfmt(); 303*38859Sbostic case USEBCNT: 304*38859Sbostic pr->bcnt = fu->bcnt; 305*38859Sbostic break; 306*38859Sbostic case USEPREC: 307*38859Sbostic pr->bcnt = prec; 308*38859Sbostic break; 309*38859Sbostic } 310*38859Sbostic break; 311*38859Sbostic case '_': 312*38859Sbostic ++p2; 313*38859Sbostic switch(p1[1]) { 314*38859Sbostic case 'A': 315*38859Sbostic endfu = fu; 316*38859Sbostic fu->flags |= F_IGNORE; 317*38859Sbostic /* FALLTHROUGH */ 318*38859Sbostic case 'a': 319*38859Sbostic pr->flags = F_ADDRESS; 320*38859Sbostic ++p2; 321*38859Sbostic switch(p1[2]) { 322*38859Sbostic case 'd': case 'o': case'x': 323*38859Sbostic *p1 = p1[2]; 324*38859Sbostic break; 325*38859Sbostic default: 326*38859Sbostic p1[3] = '\0'; 327*38859Sbostic badconv(p1); 328*38859Sbostic } 329*38859Sbostic break; 330*38859Sbostic case 'c': 331*38859Sbostic pr->flags = F_C; 332*38859Sbostic /* *p1 = 'c'; set in conv_c */ 333*38859Sbostic goto sw2; 334*38859Sbostic case 'p': 335*38859Sbostic pr->flags = F_P; 336*38859Sbostic *p1 = 'c'; 337*38859Sbostic goto sw2; 338*38859Sbostic case 'u': 339*38859Sbostic pr->flags = F_U; 340*38859Sbostic /* *p1 = 'c'; set in conv_u */ 341*38859Sbostic sw2: switch(fu->bcnt) { 342*38859Sbostic case 0: case 1: 343*38859Sbostic pr->bcnt = 1; 344*38859Sbostic break; 345*38859Sbostic default: 346*38859Sbostic p1[2] = '\0'; 347*38859Sbostic badcnt(p1); 348*38859Sbostic } 349*38859Sbostic break; 350*38859Sbostic default: 351*38859Sbostic p1[2] = '\0'; 352*38859Sbostic badconv(p1); 353*38859Sbostic } 354*38859Sbostic break; 355*38859Sbostic default: 356*38859Sbostic p1[1] = '\0'; 357*38859Sbostic badconv(p1); 358*38859Sbostic } 359*38859Sbostic 360*38859Sbostic /* 361*38859Sbostic * copy to PR format string, set conversion character 362*38859Sbostic * pointer, update original. 363*38859Sbostic */ 364*38859Sbostic savech = *p2; 365*38859Sbostic p1[1] = '\0'; 366*38859Sbostic if (!(pr->fmt = strdup(fmtp))) 367*38859Sbostic nomem(); 368*38859Sbostic *p2 = savech; 369*38859Sbostic pr->cchar = pr->fmt + (p1 - fmtp); 370*38859Sbostic fmtp = p2; 371*38859Sbostic 372*38859Sbostic /* only one conversion character if byte count */ 373*38859Sbostic if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) { 374*38859Sbostic (void)fprintf(stderr, 375*38859Sbostic "hexdump: byte count with multiple conversion characters.\n"); 376*38859Sbostic exit(1); 377*38859Sbostic } 378*38859Sbostic } 379*38859Sbostic /* 380*38859Sbostic * if format unit byte count not specified, figure it out 381*38859Sbostic * so can adjust rep count later. 382*38859Sbostic */ 383*38859Sbostic if (!fu->bcnt) 384*38859Sbostic for (pr = fu->nextpr; pr; pr = pr->nextpr) 385*38859Sbostic fu->bcnt += pr->bcnt; 386*38859Sbostic } 387*38859Sbostic /* 388*38859Sbostic * if the format string interprets any data at all, and it's 389*38859Sbostic * not the same as the blocksize, and its last format unit 390*38859Sbostic * interprets any data at all, and has no iteration count, 391*38859Sbostic * repeat it as necessary. 392*38859Sbostic * 393*38859Sbostic * if, rep count is greater than 1, no trailing whitespace 394*38859Sbostic * gets output from the last iteration of the format unit. 395*38859Sbostic */ 396*38859Sbostic for (fu = fs->nextfu;; fu = fu->nextfu) { 397*38859Sbostic if (!fu->nextfu && fs->bcnt < blocksize && 398*38859Sbostic !(fu->flags&F_SETREP) && fu->bcnt) 399*38859Sbostic fu->reps += (blocksize - fs->bcnt) / fu->bcnt; 400*38859Sbostic if (fu->reps > 1) { 401*38859Sbostic for (pr = fu->nextpr;; pr = pr->nextpr) 402*38859Sbostic if (!pr->nextpr) 403*38859Sbostic break; 404*38859Sbostic for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 405*38859Sbostic p2 = isspace(*p1) ? p1 : NULL; 406*38859Sbostic if (p2) 407*38859Sbostic pr->nospace = p2; 408*38859Sbostic } 409*38859Sbostic if (!fu->nextfu) 410*38859Sbostic break; 411*38859Sbostic } 412*38859Sbostic } 413*38859Sbostic 414*38859Sbostic 415*38859Sbostic escape(p1) 416*38859Sbostic register char *p1; 417*38859Sbostic { 418*38859Sbostic register char *p2; 419*38859Sbostic 420*38859Sbostic /* alphabetic escape sequences have to be done in place */ 421*38859Sbostic for (p2 = p1;; ++p1, ++p2) { 422*38859Sbostic if (!*p1) { 423*38859Sbostic *p2 = *p1; 424*38859Sbostic break; 425*38859Sbostic } 426*38859Sbostic if (*p1 == '\\') 427*38859Sbostic switch(*++p1) { 428*38859Sbostic case 'a': 429*38859Sbostic /* *p2 = '\a'; */ 430*38859Sbostic *p2 = '\007'; 431*38859Sbostic break; 432*38859Sbostic case 'b': 433*38859Sbostic *p2 = '\b'; 434*38859Sbostic break; 435*38859Sbostic case 'f': 436*38859Sbostic *p2 = '\f'; 437*38859Sbostic break; 438*38859Sbostic case 'n': 439*38859Sbostic *p2 = '\n'; 440*38859Sbostic break; 441*38859Sbostic case 'r': 442*38859Sbostic *p2 = '\r'; 443*38859Sbostic break; 444*38859Sbostic case 't': 445*38859Sbostic *p2 = '\t'; 446*38859Sbostic break; 447*38859Sbostic case 'v': 448*38859Sbostic *p2 = '\v'; 449*38859Sbostic break; 450*38859Sbostic default: 451*38859Sbostic *p2 = *p1; 452*38859Sbostic break; 453*38859Sbostic } 454*38859Sbostic } 455*38859Sbostic } 456*38859Sbostic 457*38859Sbostic badcnt(s) 458*38859Sbostic char *s; 459*38859Sbostic { 460*38859Sbostic (void)fprintf(stderr, 461*38859Sbostic "hexdump: bad byte count for conversion character %s.\n", s); 462*38859Sbostic exit(1); 463*38859Sbostic } 464*38859Sbostic 465*38859Sbostic badsfmt() 466*38859Sbostic { 467*38859Sbostic (void)fprintf(stderr, 468*38859Sbostic "hexdump: %%s requires a precision or a byte count.\n"); 469*38859Sbostic exit(1); 470*38859Sbostic } 471*38859Sbostic 472*38859Sbostic badfmt(fmt) 473*38859Sbostic char *fmt; 474*38859Sbostic { 475*38859Sbostic (void)fprintf(stderr, "hexdump: bad format {%s}\n", fmt); 476*38859Sbostic exit(1); 477*38859Sbostic } 478*38859Sbostic 479*38859Sbostic badconv(ch) 480*38859Sbostic char *ch; 481*38859Sbostic { 482*38859Sbostic (void)fprintf(stderr, "hexdump: bad conversion character %s.\n", ch); 483*38859Sbostic exit(1); 484*38859Sbostic } 485