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: }

Defined functions

add defined in line 60; used 68 times
addfile defined in line 33; used 1 times
badcnt defined in line 475; used 4 times
badconv defined in line 497; used 4 times
badfmt defined in line 490; used 4 times
badsfmt defined in line 483; used 1 times
escape defined in line 433; used 1 times
rewrite defined in line 194; used 1 times
size defined in line 141; used 1 times

Defined variables

endfu defined in line 31; used 1 times
sccsid defined in line 21; never used
spec defined in line 140; used 3 times
Last modified: 1990-06-02
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4100
Valid CSS Valid XHTML 1.0 Strict