static char *sccsid = "@(#)od.c 5.12 (Berkeley) 5/14/84"; /* * od -- octal, hex, decimal, character dump of data in a file. * * usage: od [-abBcdDefFhHiIlLopPs[n]vw[n]xX] [file] [[+]offset[.][b] [label]] * * where the option flags have the following meaning: * character object radix signed? * a byte (10) (n.a.) ASCII named byte stream * b byte 8 no byte octal * c byte (8) (no) character with octal non-graphic bytes * d short 10 no * D long 10 no * e,F double (10) double precision floating pt. * f float (10) single precision floating pt. * h,x short 16 no * H,X long 16 no * i short 10 yes * I,l,L long 10 yes * o,B short 8 no (default conversion) * O long 8 no * s[n] string (8) ASCII graphic strings * * p indicate EVEN parity on 'a' conversion * P indicate ODD parity on 'a' conversion * v show all data - don't skip like lines. * w[n] bytes per display line * * More than one format character may be given. * If {file} is not specified, standard input is read. * If {file} is not specified, then {offset} must start with '+'. * {Offset} may be HEX (0xnnn), OCTAL (0nn), or decimal (nnn.). * The default is octal. The same radix will be used to display the address. */ #include #define DBUF_SIZE BUFSIZ #define BIG_DBUF 32 #define NO 0 #define YES 1 #define EVEN -1 #define ODD 1 #define UNSIGNED 0 #define SIGNED 1 #define PADDR 1 #define MIN_SLEN 3 int a_put(); int b_put(); int c_put(); int s_put(); int us_put(); int l_put(); int f_put(); int d_put(); int st_put(); struct dfmt { int df_field; /* external field required for object */ int df_size; /* size (bytes) of object */ int df_radix; /* conversion radix */ int df_signed; /* signed? flag */ int df_paddr; /* "put address on each line?" flag */ int (*df_put)(); /* function to output object */ char *df_fmt; /* output string format */ } *conv_vec[32]; /* vector of conversions to be done */ struct dfmt ascii = { 3, sizeof (char), 10, 0, PADDR, a_put, 0}; struct dfmt byte = { 3, sizeof (char), 8, UNSIGNED, PADDR, b_put, 0}; struct dfmt cchar = { 3, sizeof (char), 8, UNSIGNED, PADDR, c_put, 0}; struct dfmt u_s_oct = { 6, sizeof (short), 8, UNSIGNED, PADDR, us_put, 0}; struct dfmt u_s_dec = { 5, sizeof (short), 10, UNSIGNED, PADDR, us_put, 0}; struct dfmt u_s_hex = { 4, sizeof (short), 16, UNSIGNED, PADDR, us_put, 0}; struct dfmt u_l_oct = {11, sizeof (long), 8, UNSIGNED, PADDR, l_put, 0}; struct dfmt u_l_dec = {10, sizeof (long), 10, UNSIGNED, PADDR, l_put, 0}; struct dfmt u_l_hex = { 8, sizeof (long), 16, UNSIGNED, PADDR, l_put, 0}; struct dfmt s_s_dec = { 6, sizeof (short), 10, SIGNED, PADDR, s_put, 0}; struct dfmt s_l_dec = {11, sizeof (long), 10, SIGNED, PADDR, l_put, 0}; struct dfmt flt = {14, sizeof (float), 10, SIGNED, PADDR, f_put, 0}; struct dfmt dble = {21, sizeof (double), 10, SIGNED, PADDR, d_put, 0}; struct dfmt string = { 0, 0, 8, 0, NO, st_put, 0}; char usage[] ="usage: od [-abcdfhilopswvx] [file] [[+]offset[.][b] [label]]"; char dbuf[DBUF_SIZE]; char lastdbuf[DBUF_SIZE]; int addr_base = 8; /* default address base is OCTAL */ long addr = 0L; /* current file offset */ long label = -1L; /* current label; -1 is "off" */ int dbuf_size = 16; /* file bytes / display line */ int _parity = NO; /* show parity on ascii bytes */ char fmt[] = " %s"; /* 12 blanks */ char *icvt(); char *scvt(); char *underline(); long get_addr(); /* * special form of _ctype */ #define A 01 #define G 02 #define D 04 #define P 010 #define X 020 #define isdigit(c) (_ctype[c] & D) #define isascii(c) (_ctype[c] & A) #define isgraphic(c) (_ctype[c] & G) #define isprint(c) (_ctype[c] & P) #define ishex(c) (_ctype[c] & (X|D)) char _ctype[256] = { /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 010 */ A, A, A, 0, A, A, 0, 0, /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 030 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 040 */ P|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 050 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 060 */ P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A, /* 070 */ P|G|D|A,P|G|D|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 100 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 110 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 120 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 130 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 140 */ P|G|A,X|P|G|A,X|P|G|A,X|P|G|A,X|P|G|A,X|P|G|A,X|P|G|A, P|G|A, /* 150 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 160 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, /* 170 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, 0, /* 200 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 210 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 220 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 230 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 240 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 250 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 260 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 270 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 300 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 310 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 320 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 330 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 340 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 350 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 360 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 370 */ 0, 0, 0, 0, 0, 0, 0, 0, }; main(argc, argv) int argc; char **argv; { register char *p; register char *l; register n, same; struct dfmt *d; struct dfmt **cv = conv_vec; int showall = NO; int field, llen, nelm; int max_llen = 0; argv++; argc--; if(argc > 0) { p = *argv; if(*p == '-') { while(*++p != '\0') { switch(*p) { case 'a': d = &ascii; break; case 'b': d = &byte; break; case 'c': d = &cchar; break; case 'd': d = &u_s_dec; break; case 'D': d = &u_l_dec; break; case 'e': case 'F': d = &dble; break; case 'f': d = &flt; break; case 'h': case 'x': d = &u_s_hex; break; case 'H': case 'X': d = &u_l_hex; break; case 'i': d = &s_s_dec; break; case 'I': case 'l': case 'L': d = &s_l_dec; break; case 'o': case 'B': d = &u_s_oct; break; case 'O': d = &u_l_oct; break; case 'p': _parity = EVEN; continue; case 'P': _parity = ODD; continue; case 's': d = &string; *(cv++) = d; while (isdigit(p[1])) d->df_size = (10 * d->df_size) + (*++p - '0'); if (d->df_size <= 0) d->df_size = MIN_SLEN; showall = YES; continue; case 'w': dbuf_size = 0; while (isdigit(p[1])) dbuf_size = (10 * dbuf_size) + (*++p - '0'); if (dbuf_size == 0) dbuf_size = BIG_DBUF; continue; case 'v': showall = YES; continue; default: printf("od: bad flag -%c\n", *p); puts(usage); exit(1); } *(cv++) = d; } argc--; argv++; } } /* * if nothing spec'd, setup default conversion. */ if(cv == conv_vec) *(cv++) = &u_s_oct; *cv = (struct dfmt *)0; /* * calculate display parameters */ for (cv = conv_vec; d = *cv; cv++) { nelm = (dbuf_size + d->df_size - 1) / d->df_size; llen = nelm * (d->df_field + 1); if (llen > max_llen) max_llen = llen; } /* * setup df_fmt to point to uniform output fields. */ for (cv = conv_vec; d = *cv; cv++) { if (d->df_field) /* only if external field is known */ { nelm = (dbuf_size + d->df_size - 1) / d->df_size; field = max_llen / nelm; d->df_fmt = fmt + 12 - (field - d->df_field); } } /* * input file specified ? */ if(argc > 0 && **argv != '+') { if (freopen(*argv, "r", stdin) == NULL) { perror(*argv); exit(1); } argv++; argc--; } /* * check for possible offset [label] */ if (argc > 0) { addr = get_addr(*argv); offset(addr); argv++; argc--; if (argc > 0) label = get_addr(*argv); } /* * main dump loop */ same = -1; while ((n = fread(dbuf, 1, dbuf_size, stdin)) > 0) { if (same>=0 && bcmp(dbuf, lastdbuf, dbuf_size) == 0 && !showall) { if (same==0) { printf("*\n"); same = 1; } } else { line(n); same = 0; p = dbuf; l = lastdbuf; for (nelm = 0; nelm < dbuf_size; nelm++) { *l++ = *p; *p++ = '\0'; } } addr += n; if (label >= 0) label += n; } /* * Some conversions require "flushing". */ n = 0; for (cv = conv_vec; *cv; cv++) { if ((*cv)->df_paddr) { if (n++ == 0) put_addr(addr, label, '\n'); } else (*((*cv)->df_put))(0, *cv); } } put_addr(a, l, c) long a; long l; char c; { fputs(icvt(a, addr_base, UNSIGNED, 7), stdout); if (l >= 0) printf(" (%s)", icvt(l, addr_base, UNSIGNED, 7)); putchar(c); } line(n) int n; { register i, first; register struct dfmt *c; register struct dfmt **cv = conv_vec; first = YES; while (c = *cv++) { if (c->df_paddr) { if (first) { put_addr(addr, label, ' '); first = NO; } else { putchar('\t'); if (label >= 0) fputs("\t ", stdout); } } i = 0; while (i < n) i += (*(c->df_put))(dbuf+i, c); if (c->df_paddr) putchar('\n'); } } s_put(n, d) short *n; struct dfmt *d; { printf(d->df_fmt, icvt((long)*n, d->df_radix, d->df_signed, d->df_field)); return(d->df_size); } us_put(n, d) unsigned short *n; struct dfmt *d; { printf(d->df_fmt, icvt((long)*n, d->df_radix, d->df_signed, d->df_field)); return(d->df_size); } l_put(n, d) long *n; struct dfmt *d; { printf(d->df_fmt, icvt(*n, d->df_radix, d->df_signed, d->df_field)); return(d->df_size); } d_put(f, d) double *f; struct dfmt *d; { char fbuf[24]; struct l { long n[2]; }; #if vax if ((((struct l *)f)->n[0] & 0xff00) == 0x8000) /* Vax illegal f.p. */ sprintf(fbuf, " %08x %08x", ((struct l *)f)->n[0], ((struct l *)f)->n[1]); else #endif sprintf(fbuf, "%21.14e", *f); printf(d->df_fmt, fbuf); return(d->df_size); } f_put(f, d) float *f; struct dfmt *d; { char fbuf[16]; #if vax if ((*(long *)f & 0xff00) == 0x8000) /* Vax illegal f.p. form */ sprintf(fbuf, " %08x", *(long *)f); else #endif sprintf(fbuf, "%14.7e", *f); printf(d->df_fmt, fbuf); return(d->df_size); } char asc_name[34][4] = { /* 000 */ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", /* 010 */ " bs", " ht", " nl", " vt", " ff", " cr", " so", " si", /* 020 */ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", /* 030 */ "can", " em", "sub", "esc", " fs", " gs", " rs", " us", /* 040 */ " sp", "del" }; a_put(cc, d) char *cc; struct dfmt *d; { int c = *cc; register char *s = " "; register pbit = parity((int)c & 0377); c &= 0177; if (isgraphic(c)) { s[2] = c; if (pbit == _parity) printf(d->df_fmt, underline(s)); else printf(d->df_fmt, s); } else { if (c == 0177) c = ' ' + 1; if (pbit == _parity) printf(d->df_fmt, underline(asc_name[c])); else printf(d->df_fmt, asc_name[c]); } return(1); } parity(word) int word; { register int p = 0; register int w = word; if (w) do { p ^= 1; } while(w &= (~(-w))); return (p? ODD:EVEN); } char * underline(s) char *s; { static char ulbuf[16]; register char *u = ulbuf; while (*s) { if (*s != ' ') { *u++ = '_'; *u++ = '\b'; } *u++ = *s++; } *u = '\0'; return(ulbuf); } b_put(b, d) char *b; struct dfmt *d; { printf(d->df_fmt, icvt((long)*b & 0377, d->df_radix, d->df_signed, d->df_field)); return(1); } c_put(cc, d) char *cc; struct dfmt *d; { register char *s; register int n; register int c = *cc & 0377; s = scvt(c, d); for (n = d->df_field - strlen(s); n > 0; n--) putchar(' '); printf(d->df_fmt, s); return(1); } char *scvt(c, d) int c; struct dfmt *d; { static char s[2]; switch(c) { case '\0': return("\\0"); case '\b': return("\\b"); case '\f': return("\\f"); case '\n': return("\\n"); case '\r': return("\\r"); case '\t': return("\\t"); default: if (isprint(c)) { s[0] = c; return(s); } return(icvt((long)c, d->df_radix, d->df_signed, d->df_field)); } } /* * Look for strings. * A string contains bytes > 037 && < 177, and ends with a null. * The minimum length is given in the dfmt structure. */ #define CNULL '\0' #define S_EMPTY 0 #define S_FILL 1 #define S_CONT 2 #define SBUFSIZE 1024 static char str_buf[SBUFSIZE]; static int str_mode = S_EMPTY; static char *str_ptr; static long str_addr; static long str_label; st_put(cc, d) char *cc; struct dfmt *d; { register int c; if (cc == 0) { pr_sbuf(d, YES); return(1); } c = (*cc & 0377); if (str_mode & S_FILL) { if (isascii(c)) put_sbuf(c, d); else { *str_ptr = CNULL; if (c == NULL) pr_sbuf(d, YES); str_mode = S_EMPTY; } } else if (isascii(c)) { str_mode = S_FILL; str_addr = addr + (cc - dbuf); /* ugly */ if ((str_label = label) >= 0) str_label += (cc - dbuf); /* '' */ str_ptr = str_buf; put_sbuf(c, d); } return(1); } put_sbuf(c, d) int c; struct dfmt *d; { *str_ptr++ = c; if (str_ptr >= (str_buf + SBUFSIZE)) { pr_sbuf(d, NO); str_ptr = str_buf; str_mode |= S_CONT; } } pr_sbuf(d, end) struct dfmt *d; int end; { register char *p = str_buf; if (str_mode == S_EMPTY || (!(str_mode & S_CONT) && (str_ptr - str_buf) < d->df_size)) return; if (!(str_mode & S_CONT)) put_addr(str_addr, str_label, ' '); while (p < str_ptr) fputs(scvt(*p++, d), stdout); if (end) putchar('\n'); } /* * integer to ascii conversion * * This code has been rearranged to produce optimized runtime code. */ #define MAXINTLENGTH 32 static char _digit[] = "0123456789abcdef"; static char _icv_buf[MAXINTLENGTH+1]; static long _mask = 0x7fffffff; char * icvt (value, radix, signed, ndigits) long value; int radix; int signed; int ndigits; { register long val = value; register long rad = radix; register char *b = &_icv_buf[MAXINTLENGTH]; register char *d = _digit; register long tmp1; register long tmp2; long rem; long kludge; int sign; if (val == 0) { *--b = '0'; sign = 0; goto done; /*return(b);*/ } if (signed && (sign = (val < 0))) /* signed conversion */ { /* * It is necessary to do the first divide * before the absolute value, for the case -2^31 * * This is actually what is being done... * tmp1 = (int)(val % rad); * val /= rad; * val = -val * *--b = d[-tmp1]; */ tmp1 = val / rad; *--b = d[(tmp1 * rad) - val]; val = -tmp1; } else /* unsigned conversion */ { sign = 0; if (val < 0) { /* ALL THIS IS TO SIMULATE UNSIGNED LONG MOD & DIV */ kludge = _mask - (rad - 1); val &= _mask; /* * This is really what's being done... * rem = (kludge % rad) + (val % rad); * val = (kludge / rad) + (val / rad) + (rem / rad) + 1; * *--b = d[rem % rad]; */ tmp1 = kludge / rad; tmp2 = val / rad; rem = (kludge - (tmp1 * rad)) + (val - (tmp2 * rad)); val = ++tmp1 + tmp2; tmp1 = rem / rad; val += tmp1; *--b = d[rem - (tmp1 * rad)]; } } while (val) { /* * This is really what's being done ... * *--b = d[val % rad]; * val /= rad; */ tmp1 = val / rad; *--b = d[val - (tmp1 * rad)]; val = tmp1; } done: if (sign) *--b = '-'; tmp1 = ndigits - (&_icv_buf[MAXINTLENGTH] - b); tmp2 = signed? ' ':'0'; while (tmp1 > 0) { *--b = tmp2; tmp1--; } return(b); } long get_addr(s) register char *s; { register char *p; register long a; register int d; if (*s=='+') s++; if (*s=='x') { s++; addr_base = 16; } else if (*s=='0' && s[1]=='x') { s += 2; addr_base = 16; } else if (*s == '0') addr_base = 8; p = s; while(*p) { if (*p++=='.') addr_base = 10; } for (a=0; *s; s++) { d = *s; if(isdigit(d)) a = a*addr_base + d - '0'; else if (ishex(d) && addr_base==16) a = a*addr_base + d + 10 - 'a'; else break; } if (*s == '.') s++; if(*s=='b') a *= 512; if(*s=='B') a *= 1024; return(a); } offset(a) long a; { if (canseek(stdin)) { /* * in case we're accessing a raw disk, * we have to seek in multiples of a physical block. */ fseek(stdin, a & 0xfffffe00L, 0); a &= 0x1ffL; } dumbseek(stdin, a); } dumbseek(s, offset) FILE *s; long offset; { char buf[BUFSIZ]; int n; int nr; while (offset > 0) { nr = (offset > BUFSIZ) ? BUFSIZ : (int)offset; if ((n = fread(buf, 1, nr, s)) != nr) { fprintf(stderr, "EOF\n"); exit(1); } offset -= n; } } #include #include canseek(f) FILE *f; { struct stat statb; return( (fstat(fileno(f),&statb)==0) && (statb.st_nlink > 0) && /*!pipe*/ (!isatty(fileno(f))) ); }