/* Dump files, similar to OD, but in a different format * Files are displayed sixteen bytes to a line, offset from the beginning * of the file on the right, hex values in the middle, * ascii values on the right. * -c option displays char value above hex value * 13 May 1985 David Elins */ /* modifications * 3-28-86 uses different formats depending on how bytes are ordered * on the machine * little-endian (e.g. vax) * hex ..... hex addr ascii * big endian (e.g. 68000) * addr hex ascii * * idea came from an article by Mike Higgins * in "Computer Language" April, 1986 * * 3-30-86 -x option reverses natural display format * * 4-14-86 Amiga port for both Lattice and Manx (under 32 bit) * * screen width needs to be a define * fputs not documented to return valid value except on error * printf return value cannot be relied on under Lattice * modify isprint semantics to limit to "normal" ascii * */ #include #include extern char *strrchr(); extern void exit(); #define EQS(str1,str2) (strcmp((str1),(str2))==0) /* * On the Amiga, the normal CLI window is only 77 characters wide. * I decided to trim the line length by recovering 3 characters from * the offset field. Fred Fish 14-Apr-86 */ #ifdef AMIGA #define OFFSETFMT "%05lx" #define OFFSETSIZ (5) /* Should match length in OFFSETFMT */ #define WIDTH (77) /* Screen width in char positions */ #define BLANKS " " #define ISPRINT(x) (((x) < 0200) && isprint(x)) /* Limit to 000-177 */ extern int Enable_Abort; #else #define OFFSETFMT "%08lx" #define OFFSETSIZ (8) #define WIDTH (80) #define BLANKS " " #define ISPRINT(x) isprint(x) #endif static int showchar=0; static int manyfile; main(argc, argv) int argc; char *argv[]; { #ifdef MSDOS char *pgmname="hd"; /* Microsoft C may not support argv[0] */ #else extern char *basename(); /* pathnames allowed on commands */ char *pgmname=basename(argv[0]); #endif int lowfirst(),highfirst(); /* dump formatting routines */ static int reverse = 0; /* reverse natural display format */ register char *cp, c; #ifdef AMIGA Enable_Abort = 1; /* Stupid Lattice default is 0 */ #endif /* parse options */ for (; argc > 1 && (*argv[1] == '-'); argv++, argc--) { cp = &argv[1][1]; /* - alone is standard input */ while ((c = *cp++) && argc) { switch (c) { case 'c': /* like od -c option */ showchar = 1; break; case 'x': /* reverse natural display format */ reverse = 1; break; default: argc=0; /* modify argument to indicate error */ break; } } } if (argc < 1) { (void)fprintf(stderr,"Usage: %s [-cx] [files]\n", pgmname); exit(1); } manyfile = (argc > 2); /* more than one file to display? */ /* loop through filename arguments if reverse == 1, exclusive or'ing with it will reverse the return value of bytorder() */ if (bytorder() ^ reverse) /* display in natural or reversed order */ exit(filter(argc,argv,lowfirst)); else exit(filter(argc,argv,highfirst)); } /* format and display contents of stdin */ /* low addr byte of multibyte values is MOST significant */ static int highfirst(filename) /* format and display contents of stdin */ char *filename; { unsigned char /* is unsigned char portable ? */ buf[16], /* portion of file read */ *bufptr, /* pointer into that portion */ ascstr[17], /* ascii equivalents of digits */ *pascstr; /* pointer into above string */ int ctr, /* general counter */ col, /* current column printed */ rlen; /* length read */ long offset=0L; /* offset from beginning of file */ static char sep[]="::::::::::::::"; /* separates filenames */ if (manyfile) (void)printf("%s\n%s\n%s\n", sep, filename, sep); /* read a display line's worth at a time, format and display it */ while ((rlen = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) { col = 1; bufptr = buf; /* point to beginning of bytes read */ if (showchar) { /* print equivalent characters above hex values? */ (void)fputs(BLANKS, stdout); /* for offset into file; */ for (ctr = 0; ctr < rlen; ctr++) { if (ctr % 4 == 0) (void)fputs(" ",stdout); /* separate each four bytes */ (void)fputs(" ",stdout); if (*bufptr == '\b') (void)fputs("\\b",stdout); else if (*bufptr == '\t') (void)fputs("\\t",stdout); else if (*bufptr == '\n') (void)fputs("\\n",stdout); else if (*bufptr == '\f') (void)fputs("\\f",stdout); else if (*bufptr == '\r') (void)fputs("\\r",stdout); else if (ISPRINT(*bufptr)) (void)printf(" %c", *bufptr); else (void)fputs(" ",stdout); bufptr++; } (void)putc('\n',stdout); } bufptr = buf; /* point to beginning of bytes read */ pascstr = ascstr; /* point to beginning of ascii equivalents */ (void) printf(OFFSETFMT, offset); /* count and print offset into file; */ col += OFFSETSIZ; for (ctr = 0; ctr < rlen; ctr++) { if (ctr % 4 == 0) { col++; /* fputs value defined only on error */ (void)fputs(" ",stdout); /* separate each four bytes */ } *pascstr++ = ISPRINT(*bufptr) ? *bufptr : '.'; /* save ascii val */ (void) printf(" %02x", *bufptr++); /* display hex value of byte */ col += 3; } *pascstr = '\0'; /* terminate ascii string */ do { (void)fputs(" ",stdout); /* fputs value defined only on error */ } while (col++ < (WIDTH-18)); /* align ascii values */ (void)printf("|%s|\n",ascstr); /* display ascii values */ offset += rlen; /* bump offset into file */; } return (1); } /* format and display contents of stdin */ /* low addr byte of multibyte values is LEAST significant */ static int lowfirst(filename) /* format and display contents of stdin */ char *filename; { unsigned char /* is unsigned char portable ? */ buf[16], /* portion of file read */ *bufptr, /* pointer into that portion */ *rbufptr, /* backward pointer into that portion */ ascstr[17], /* ascii equivalents of digits */ *pascstr; /* pointer into above string */ int ctr, /* general counter */ col, /* current column printed */ rlen; /* length read */ long offset=0L; /* offset from beginning of file */ static char sep[]="::::::::::::::"; /* separates filenames */ if (manyfile) (void)printf("%s\n%s\n%s\n", sep, filename, sep); /* read a display line's worth at a time, format and display it */ while ((rlen = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) { col = 1; /* current printed column */ rbufptr = buf + rlen - 1; /* point to end of bytes read */ if (showchar) { /* print equivalent characters above hex values? */ for (ctr = 0; ctr < sizeof(buf); ctr++) { if ((ctr + rlen) < sizeof(buf)) (void)fputs(" ",stdout); else if (*rbufptr == '\b') (void)fputs("\\b",stdout); else if (*rbufptr == '\t') (void)fputs("\\t",stdout); else if (*rbufptr == '\n') (void)fputs("\\n",stdout); else if (*rbufptr == '\f') (void)fputs("\\f",stdout); else if (*rbufptr == '\r') (void)fputs("\\r",stdout); else if (ISPRINT(*rbufptr)) (void)printf(" %c", *rbufptr); else (void)fputs(" ",stdout); if (ctr % 4 == 3) (void)fputs(" ",stdout); /* separate each four bytes */ (void)fputs(" ",stdout); if ((ctr + rlen) >= sizeof(buf)) rbufptr--; } (void)putc('\n',stdout); } bufptr = buf; /* point to beginning of bytes read */ rbufptr = buf + rlen - 1; /* point to end of bytes read */ pascstr = ascstr; /* point to beginning of ascii equivalents */ for (ctr = 0; ctr < sizeof(buf); ctr++) { if ((ctr + rlen) < sizeof(buf)) { /* display hex value of byte */ (void) fputs(" ",stdout); /* no value */ } else { (void) printf("%02x ", *rbufptr); } col += 3; if (ctr % 4 == 3) { col++; (void) fputs(" ",stdout); /* separate each four bytes */ } if ((ctr + rlen) >= sizeof(buf)) { /* save ascii value */ *pascstr++ = ISPRINT(*bufptr) ? *bufptr : '.'; bufptr++; /* advance, */ rbufptr--; /* decrement pointers */ } } *pascstr = '\0'; /* terminate ascii string */ (void) printf(OFFSETFMT,offset); /* count and print offset into file; */ col += OFFSETSIZ; do { (void)fputs(" ",stdout); /* fputs value defined only on error */ } while (col++ < (WIDTH-18)); /* align ascii values */ (void)printf("|%s|\n",ascstr); /* display ascii values */ offset += rlen; /* bump offset into file */; } return (1); } /* is low addr byte of multi-byte values the least significant ? */ static int bytorder() { static union { /* used to determine byte order */ int x; char c[2]; } test; test.x=1; /* find out how bytes are ordered */ return(test.c[0] == test.x); } /* * perform the basename(1) function from a C program */ static char * basename(name) /* return pointer to filename portion of name */ char name[]; { char *cp=strrchr(name,'/'); return(cp==NULL ? name : (cp+1)); } /* * loop through filenames on a command line * reopening each as standard input */ extern int errno; /* system error variable */ extern void perror(); static int filter(argc,argv,process) int argc; /* how many command line arguments */ char *argv[]; /* command line arguments */ int (*process)();/* function that processes each file, called at least once */ /* the only argument is the filename (NULL if orig stdin) */ { #ifdef unix register int fd = dup(0); /* initial standard input */ #endif register int inorig; /* 0=from stdin, else from file */ register int firstime; /* make sure *process is called once */ register int retval=0; /* return value */ for (firstime = 1; firstime || (argc > 1); argc--,argv++,firstime=0) { /* arguments are filenames to filter, "-" means standard input */ inorig = ((argc == 1) || EQS(argv[1],"-")); if (inorig) { #ifdef unix (void)close(0); /* reset to initial standard input */ (void)dup(fd); #endif } /* set filename as standard input */ else if (freopen(argv[1],"r",stdin) == NULL) { char string[48]; retval = errno; /* return if error */ (void)sprintf(string,"cannot open %s", argv[1]); perror(string); break; } (*process)(inorig?(char *)NULL:argv[1]); /* process this file */ } if (!inorig) { /* leave stdin the same file as at entry */ #ifdef unix (void)close(0); (void)dup(fd); #endif } return(retval); } #ifdef MANX char *strrchr (s, c) char *s; char c; { register char *scan; scan = s; while (*scan++ != '\000') {;} while (--scan > s && *scan != c) {;} return (*scan == c ? scan : NULL); } #endif /* MANX */ #ifdef AMIGA /* Neither Lattice or Manx has perror */ void perror (sp) char *sp; { if (sp && *sp) { fprintf (stderr, "%s: ", sp); } fprintf (stderr, "\n"); } #endif /* AMIGA */