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