/******************************************************************************* * hdump.c * Dump the contents of a file in hexadecimal format. * * Notes * Define 'EBCDIC' when compiling on a system that uses EBCDIC as its * native character set (e.g., IBM OS/390). * * Define 'FSEARCH' if the fsearch libraries are available. * * Define 'NO_FSEEK_ON_STDIN' to true (non-zero) if fseek() does not * return a failure code when attempting to seek on stdin when it is a * pipe. I.e., the command 'dir |hdump -' should cause the fseek() call * on stdin to return a negative value; if this is not the case (as on * Win32), define this macro to true. Note that this is already assumed * if _WIN32 is defined, but it may also be true for other systems. * * Ported to * MS-DOS 2.x+, Microsoft C 4.0. * MS/Windows, Win32, Microsoft C 5.0+. * HP-UX. * IBM AIX. * IBM OS/390. * Sun Solaris. * * Notice * Copyright ©1985,2009 by David R. Tribble, all rights reserved. * Permission is granted to any person or entity except those designated * by the United States Department of State as a terrorist or terrorist * government or agency, to use and distribute this source code provided * that the original copyright notice remains present and unaltered. * *------------------------------------------------------------------------------- * @(#)drt/src/cmd/hdump.c $Revision: 3.6 $ $Date: 2009/03/15 00:08:39 $ *******************************************************************************/ /* Identification */ #define PROG "hdump" #define SRCFILE "drt/src/cmd/" __FILE__ #define VERSION "$Revision: 3.6 $ $Date: 2009/03/15 00:08:39 $" static const char * prog = PROG; static const char notice[] = "@(#)" SRCFILE " " VERSION; static const char revno[] = "$Revision: 3.6 $"; static const char revdate[] = "$Date: 2009/03/15 00:08:39 $"; static const char built[] = "@(#)" "Built: " __DATE__ " " __TIME__; static const char auth[] = "@(#)" "Copyright \2511985,2009 by David R. Tribble, all rights reserved."; /* System includes */ #define NO_EXT_KEYS #define LINT_ARGS #include #include #include #include #include #include #include #include #if defined(__MSDOS__) or defined(_WIN32) #include #endif #include #include #ifndef NO_FSEEK_ON_STDIN #ifdef _WIN32 #define NO_FSEEK_ON_STDIN 1 #else #define NO_FSEEK_ON_STDIN 0 #endif #endif /* Local includes */ #ifdef FSEARCH #include "fsearch.h" #endif /* Local constants */ #define FBUFSZ (32*1024) /* Input file buffer size */ #define PAGESZ 32 /* Lines per output page */ #define TRUE 1 #define FALSE 0 /* Local types */ typedef int bool; struct option { bool o_loc; /* Print location */ bool o_chars; /* Character output only */ bool o_bit7; /* Treat bit 7 as zero */ bool o_ebcdic; /* EBCDIC characters */ bool o_ascii; /* ASCII characters */ bool o_ctrl; /* Output control code as is */ bool o_contents; /* Print file contents */ bool o_rev; /* Reverse right to left data */ bool o_intel; /* Intel format */ bool o_eolbreak; /* Break output on newlines */ bool o_formfeeds; /* Separate dumps with FFs */ int o_radix; /* Data radix */ int o_word; /* Word or byte data */ unsigned long o_start; /* Start address */ unsigned long o_end; /* End address */ const char * o_fname; /* Source filename */ }; /* ASCII constants */ #define CH_BEL 0x07 #define CH_LF 0x0A #define CH_CR 0x0D #define CH_FF 0x0C #define CH_SP 0x20 #define CH_DEL 0x7F #define CH_NEL 0x85 /* Radix codes */ #define RADIX_OCT 'o' #define RADIX_DEC 'd' #define RADIX_HEX 'h' /* Word type codes */ #define WORD_NONE 0 #define WORD_BE 1 #define WORD_LE 2 /* Local function macros */ #define itoc(d) ((d) + '0') #define odd(i) ((i) & 1) /* Local variables */ static char fbuf[FBUFSZ]; /* Input file buffer */ /******************************************************************************* * atoe_1047[] * ASCII to EBCDIC character translation table. * This table is based on ISO 8859-1 (Latin-1) and IBM CP-1047 code pages. */ static const unsigned char atoe_1047[0x100] = { /* 0x00-0x07 */ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, /* 0x08-0x0F */ 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x10-0x17 */ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, /* 0x18-0x1F */ 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x20-0x27 */ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 0x28-0x2F */ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, /* 0x30-0x37 */ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 0x38-0x3F */ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, /* 0x40-0x47 */ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 0x48-0x4F */ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, /* 0x50-0x57 */ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, /* 0x58-0x5F */ 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, /* 0x60-0x67 */ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x68-0x6F */ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 0x70-0x77 */ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, /* 0x78-0x7F */ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, /* 0x80-0x87 */ 0x04, 0x06, 0x08, 0x09, 0x0A, 0x15, 0x14, 0x17, /* 0x88-0x8F */ 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x28, /* 0x90-0x97 */ 0x29, 0x2A, 0x2B, 0x2C, 0x30, 0x31, 0x33, 0x34, /* 0x98-0x9F */ 0x35, 0x36, 0x38, 0x39, 0x3A, 0x3B, 0x3E, 0xFF, /* 0xA0-0xA7 */ 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, /* 0xA8-0xAF */ 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, /* 0xB0-0xB7 */ 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, /* 0xB8-0xBF */ 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, /* 0xC0-0xC7 */ 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, /* 0xC8-0xCF */ 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* 0xD0-0xD7 */ 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, /* 0xD8-0xDF */ 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59, /* 0xE0-0xE7 */ 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, /* 0xE8-0xEF */ 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* 0xF0-0xF7 */ 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, /* 0xF8-0xFF */ 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF, }; /******************************************************************************* * etoa_1047[] * EBCDIC to ASCII character translation table. * This table is based on ISO 8859-1 (Latin-1) and IBM CP-1047 code pages. */ static const unsigned char etoa_1047[0x100] = { /* 0x00-0x07 */ 0x00, 0x01, 0x02, 0x03, 0x80, 0x09, 0x81, 0x7F, /* 0x08-0x0F */ 0x82, 0x83, 0x84, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x10-0x17 */ 0x10, 0x11, 0x12, 0x13, 0x86, 0x85, 0x08, 0x87, /* 0x18-0x1F */ 0x18, 0x19, 0x88, 0x89, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x20-0x27 */ 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x0A, 0x17, 0x1B, /* 0x28-0x2F */ 0x8F, 0x90, 0x91, 0x92, 0x93, 0x05, 0x06, 0x07, /* 0x30-0x37 */ 0x94, 0x95, 0x16, 0x96, 0x97, 0x98, 0x99, 0x04, /* 0x38-0x3F */ 0x9A, 0x9B, 0x9C, 0x9D, 0x14, 0x15, 0x9E, 0x1A, /* 0x40-0x47 */ 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, /* 0x48-0x4F */ 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, /* 0x50-0x57 */ 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, /* 0x58-0x5F */ 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, /* 0x60-0x67 */ 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, /* 0x68-0x6F */ 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, /* 0x70-0x77 */ 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, /* 0x78-0x7F */ 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, /* 0x80-0x87 */ 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x88-0x8F */ 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, /* 0x90-0x97 */ 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, /* 0x98-0x9F */ 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, /* 0xA0-0xA7 */ 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* 0xA8-0xAF */ 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, /* 0xB0-0xB7 */ 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, /* 0xB8-0xBF */ 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, /* 0xC0-0xC7 */ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0xC8-0xCF */ 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, /* 0xD0-0xD7 */ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, /* 0xD8-0xDF */ 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, /* 0xE0-0xE7 */ 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* 0xE8-0xEF */ 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, /* 0xF0-0xF7 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0xF8-0xFF */ 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F, }; /******************************************************************************* * printline() * Print data line. * Print 'size' bytes in numeric and ASCII representation to stream 'out'. * * Param out * Output stream. * * Param buf * Data bytes to format and write to the output stream. * * Param linesz * Width of the output text line. * * Param size * Number of data bytes in 'buf[]'. * * Param byteno * Address (location) of the first data byte in 'buf[]'. * * Param opt * Program options. * * Returns * The number of bytes formatted and written from 'buf[]'. */ static int printline(FILE *out, const unsigned char buf[], int linesz, int size, unsigned long byteno, const struct option *opt) { int i; /* Print line location */ if (opt->o_loc) { printf("%04X.%04X ", (unsigned int)((byteno >> 16) & 0xFFFF), (unsigned int)(byteno & 0xFFFF)); } /* Print the data representation of the line */ if (not opt->o_chars) { const char * rad; const char * rsp; int half; switch (opt->o_radix) { case RADIX_OCT: rad = (opt->o_word == WORD_NONE ? "%03o " : "%06o "); rsp = (opt->o_word == WORD_NONE ? "... " : "...... "); break; case RADIX_DEC: rad = (opt->o_word == WORD_NONE ? "%3u " : "%5u "); rsp = (opt->o_word == WORD_NONE ? "... " : "..... "); break; case RADIX_HEX: rad = (opt->o_word == WORD_NONE ? "%02X " : "%04X "); rsp = (opt->o_word == WORD_NONE ? ".. " : ".... "); break; } /* Write spaces (first line) */ half = 8-1; i = 0; if (byteno < opt->o_start) { for (; i < opt->o_start - byteno; i++) { if (opt->o_word != WORD_NONE) i++; fprintf(out, rsp); if ((i & half) == half) putc(' ', out); } if (i > opt->o_start - byteno) i--; } /* Write data bytes */ for (; i < size; i++) { unsigned int v; v = buf[i]; if (opt->o_word == WORD_BE) { i++; if (i < size) v = (v << 8) + buf[i]; } else if (opt->o_word == WORD_LE) { i++; if (i < size) v = v + (buf[i] << 8); } fprintf(out, rad, v); if ((i & half) == half) putc(' ', out); } /* Write spaces (last line) */ for (; i < linesz; i++) { if (opt->o_word != WORD_NONE) i++; fprintf(out, rsp); if ((i & half) == half) putc(' ', out); } } /* Write the character representation of the line */ putc('|', out); i = 0; if (byteno < opt->o_start) { for (; i < opt->o_start - byteno; i++) putc(' ', out); } for (; i < size; i++) { int c; c = buf[i]; if (opt->o_ebcdic) c = etoa_1047[c]; else if (opt->o_ascii) c = atoe_1047[c]; if (opt->o_bit7) c &= 0x7F; #ifndef EBCDIC if (c == CH_DEL) c = '.'; else if (opt->o_ctrl) { if (c >= CH_BEL and c <= CH_CR) c = '.'; } else #endif if (c < 0x20 or c >= 0x7F and c < 0xA0) c = '.'; putc(c, out); } /* Write trailing spaces */ if (not opt->o_eolbreak) { for (; i < linesz; i++) putc(' ', out); putc('|', out); } putc('\n', out); return size; } /******************************************************************************* * readline() * Read a line of data bytes from the input file. * Read 'count' bytes from file 'in', returning number of bytes actually * read, or zero on end of file. * * Param in * Input stream. * * Param buf * Buffer to received the data bytes read from 'in'. * * Param count * Number of data bytes to read into 'buf[]'. * * Param opt * Program options. * * Returns * Number of actual bytes read from stream 'in'. */ static int readline(FILE *in, unsigned char *buf, int count, const struct option *opt) { int size; int c; /* Read a line of data from the input file */ if (opt->o_eolbreak) { bool eoln; int prevc; /* Read data up to 'count' bytes or an end-of-line char */ size = 0; eoln = FALSE; prevc = 0x00; while (size < count) { int c; unsigned c2; c = getc(in); if (c == EOF) break; buf[size++] = c; c2 = c; if (opt->o_ebcdic) c2 = etoa_1047[c2]; else if (opt->o_ascii) c2 = atoe_1047[c2]; if (opt->o_bit7) c2 &= 0x7F; /* Check for an end-of-line char */ if (opt->o_word == WORD_NONE) { if (c2 == CH_CR or c2 == CH_LF or c2 == CH_FF or c2 == CH_NEL) eoln = TRUE; else if (eoln) { ungetc(c, in); size--; break; } } else if (not odd(size)) { switch (opt->o_word) { case WORD_LE: c2 = prevc + (c2 << 8); break; case WORD_BE: c2 = (prevc << 8) + c2; break; } if (c2 == CH_CR or c2 == CH_LF or c2 == CH_FF or c2 == CH_NEL) eoln = TRUE; else if (eoln) { /* ISO C guarantees ungetc() for only one char, but two * calls should work because the file buffer (fbuf[]) size * is a multiple of two. */ ungetc(c, in); ungetc(prevc, in); size -= 2; break; } } prevc = c2; } } else { /* Read a line of data from input file */ size = fread(buf, 1, count, in); } return size; } /******************************************************************************* * printn() * Print a number. * Print number 'n' into string 's', in the format: * "Z,ZZZ,ZZZ,ZZ9" * * Param s * A string buffer to receive the formatted number in printable form. * * Param n * A number to format. * * Param lev * Recursion count. * * Returns * Pointer to the last (NUL) character in 's' that is modified. */ static char * prn(char *s, unsigned long n, int lev) { int d; d = n % 10; /* Low order digit of n */ n /= 10; /* n sans low digit */ if (n != 0) { s = prn(s, n, lev+1); /* Recursive */ if (lev % 3 == 2) *s++ = ','; } *s++ = itoc(d); *s = '\0'; return s; } static void printn(char *s, unsigned long n) { *s = '\0'; prn(s, n, 0); } /******************************************************************************* * ptime() * Print a time value. * Print time_t value 'timeval' to stream 'out', in the format: * "Sun 16 Sep 1978 13:23:55" * * Param out * Output stream. * * Param timeval * A time value to format and write to stream 'out'. */ static void ptime(FILE *out, const time_t *timeval) { struct tm tm; const char * at; int hr; char buf[40+1]; /* Printed: "Sun 16 Sep 1978 13:23:55" */ /* -0123456789.123456789.12345- */ tm = *localtime(timeval); strftime(buf, sizeof(buf), "%a %d %b %Y %H:%M:%S", &tm); fprintf(out, "%s", buf); } /******************************************************************************* * header() * Print a header. * Print file header info for input file 'in' to output stream 'out'. * * Param out * Output stream. * * Param in * Input stream. * * Param name * Name of the input filename for stream 'in'. */ static void header(FILE *out, FILE *in, const char *name) { struct stat info; /* File inode info */ int rc; time_t t; int i; char buf[80+1]; /* Print info about the file */ if (name != NULL) rc = stat(name, &info); else rc = fstat(fileno(in), &info); if (rc == 0) { bool pr = FALSE; /* Print the modification date of the file */ if (info.st_mtime > 0) { ptime(out, &info.st_mtime); fprintf(out, " "); pr = TRUE; } #ifdef IS_DISABLED_ if ((info.st_mode & S_IFMT) == S_IFDIR) fprintf(out, "Directory "); #endif /* Print the full name of the file */ if (name != NULL) { fprintf(out, "%53s", name); pr = TRUE; } if (pr) fprintf(out, "\n"); } /* Print the current time and date */ time(&t); ptime(out, &t); if (rc == 0) { /* Print the file size */ fprintf(out, " "); buf[0] = '\0'; printn(buf, info.st_size); sprintf(buf+strlen(buf), (info.st_size < 0x10000 ? " (%04lX) bytes" : " (%08lX) bytes"), info.st_size); fputs(buf, out); } fprintf(out, "\n\n"); } /******************************************************************************* * dump() * Dump the contents of a data file. * Print a data/ASCII dump of stream 'in' to stream 'out'. * * Param in * Input stream to dump. * * Param out * Output stream. * * Param opt * Program options. */ void dump(FILE *in, FILE *out, const struct option *opt) { unsigned char buf[128+1]; /* Input line buffer */ int linesz; /* Line buffer length */ int size; /* Actual line size */ unsigned long byteno; /* Current file byte number */ int lineno; /* Line counter */ /* Print file header info */ header(out, in, opt->o_fname); if (not opt->o_contents) return; /* Set output line size */ if (opt->o_radix == RADIX_OCT and not opt->o_loc and opt->o_word != WORD_NONE) linesz = 16; else if (opt->o_radix == RADIX_DEC and opt->o_word != WORD_NONE) linesz = 16; else if (opt->o_radix == RADIX_DEC and opt->o_word == WORD_NONE) linesz = 8; else if (opt->o_radix == RADIX_OCT) linesz = 8; else linesz = 16; if (opt->o_chars) linesz = 64; /* Seek to the start address in the input file */ if (opt->o_start > opt->o_end) return; byteno = (opt->o_start / linesz) * linesz; /* To nearest line */ if (byteno > 0) { if (opt->o_fname != NULL) { /* Start reading input file at the specified start address */ fseek(in, byteno, SEEK_SET); } #if NO_FSEEK_ON_STDIN else #else else if (fseek(in, byteno, SEEK_SET) < 0) #endif { int bufsz; unsigned long pos; /* Skip input from redirect stdin up to the start address */ /* Note: fseek() and ftell() are wrong on Win32/MSC */ bufsz = sizeof(buf)-1; pos = 0; while (pos+bufsz < opt->o_start) { size = fread(buf, 1, bufsz, in); if (size < 0) break; pos += size; if (size < bufsz) break; } if (size >= bufsz) { while (pos < opt->o_start) { if (getc(in) == EOF) break; pos++; } } } } /* Dump file contents */ lineno = 0; while (byteno < opt->o_end) { size = readline(in, buf, linesz, opt); if (size == 0) break; if (byteno+size > opt->o_end) size = opt->o_end - byteno + 1; lineno++; if (lineno > PAGESZ) { lineno = 1; #ifdef IS_DISABLED_ putc('\n', out); #endif } printline(out, buf, linesz, size, byteno, opt); byteno += size; } } /******************************************************************************* * locspec() * Location specifier. * Convert '-s' or '-e' location specification 'arg' into numeric value * 'val'. If an error occurs, 'val' is left unchanged. * * Param val * Is filled with the resulting numeric value of 'arg'. * * Param arg * A string specifying a numeric file address (location), as an octal, * decimal, or hexadecimal value. */ static void locspec(unsigned long *val, char *arg) { char * radix; /* Radix scanf string */ unsigned long unit; /* Unit size */ char c; /* Suffix char */ int len; /* Arg string length */ /* Interpret unit suffix */ len = strlen(arg); c = arg[--len]; arg[len] = '\0'; switch (tolower(c)) { case 'b': /* 512-byte block */ unit = 512; break; case 'k': /* Kilobyte */ unit = 1024; break; case 'm': /* Megabyte */ unit = 1024*1024; break; case 's': /* 128-byte sector */ unit = 128; break; default: /* No unit suffix, byte units */ unit = 1; arg[len++] = c; break; } /* Interpret radix suffix */ c = arg[--len]; arg[len] = '\0'; switch (tolower(c)) { case 'h': /* Hex address */ case 'x': radix = "%lx"; break; case 'o': /* Octal address */ radix = "%lo"; break; default: /* No radix suffix, decimal address */ radix = "%lu"; arg[len++] = c; break; } /* Convert the location arg to a file offset */ sscanf(arg, radix, val); *val *= unit; } /******************************************************************************* * usage[] * Program usage message text. * * See * usage() */ static const char *const usage_m[] = { "Options:", " - Read from standard input", " -7 Treat high bit (bit 7) as zero", " -a Show characters only", " -A Convert EBCDIC (IBM CP-1047) characters to ASCII (ISO 8859-1)", " -c Echo control codes as is", " -d Decimal format", " -eA End address", " -E Convert ASCII (ISO 8859-1) characters to EBCDIC (IBM CP-1047)", " -f Separate file dumps with formfeeds", " -h File header only", #ifdef INCOMPLETE " -I Intel standard output", #endif " -l Suppress line addresses", " -n Break output lines at end-of-line characters", " -o Octal format", #ifdef INCOMPLETE " -p Printer format", #endif #ifdef INCOMPLETE " -r Reverse data right to left", #endif " -sA Start address", " -w Data words (16-bit, little-endian), not bytes", " -W Data words (16-bit, big-endian), not bytes", "", "'A' is a location number with an optional radix suffix:", " h Hexadecimal number", " o Octal number", "and an optional unit suffix:", " b 512-byte block", " k Kilobyte (1,024 bytes)", " m Megabyte (1,048,576 bytes)", " s 128-byte sector", NULL }; /******************************************************************************* * main() * * Param argc * Number of command line args, i.e., the number of elements in 'argv[]'. * * Param argv * Command line args. * * Returns * 'EXIT_SUCCESS' (zero) on success, otherwise 'EXIT_FAILURE' if an error * occurs. */ int main(int argc, char **argv) { int i; /* Arg counter */ struct option opt; /* Options flags */ int fcount; /* File counter */ /* Initialize options */ opt.o_start = 0L; opt.o_end = -1L; opt.o_radix = RADIX_HEX; opt.o_word = WORD_NONE; opt.o_loc = TRUE; opt.o_chars = FALSE; opt.o_bit7 = FALSE; opt.o_ebcdic = FALSE; opt.o_ascii = FALSE; opt.o_ctrl = FALSE; opt.o_contents = TRUE; opt.o_rev = FALSE; opt.o_intel = FALSE; opt.o_eolbreak = FALSE; opt.o_formfeeds = FALSE; opt.o_fname = NULL; /* Parse command line options */ for (i = 1; i < argc and argv[i][0] == '-'; i++) { char * cp; /* Process the next command line option */ cp = argv[i]; if (cp[1] == '\0') break; if (cp[1] == '-' and cp[2] == '\0') { argv++, argc--; break; } if (cp[1] != '\0') cp++; for ( ; cp[0] != '\0'; cp++) { /* Process the next option */ switch (cp[0]) { case '7': /* Don't treat bit 7 as zero */ opt.o_bit7 = TRUE; break; case 'a': /* Print only char values */ opt.o_chars = TRUE; break; case 'A': /* Print ASCII chars */ opt.o_ascii = TRUE; break; case 'c': /* Echo control chars as is */ opt.o_ctrl = TRUE; break; case 'd': /* Decimal radix */ case 'o': /* Octal radix */ opt.o_radix = *cp; break; case 'e': /* End location */ case 's': /* Start location */ if (cp[1] == '\0') goto usage; locspec((cp[0] == 's' ? &opt.o_start : &opt.o_end), cp+1); goto nextarg; case 'E': /* Print EBCDIC chars */ opt.o_ebcdic = TRUE; break; case 'f': /* Separate file dumps with formfeeds */ opt.o_formfeeds = TRUE; break; case 'h': /* File header only */ opt.o_contents = FALSE; break; #ifdef INCOMPLETE case 'I': /* Intel standard output */ opt.o_intel = TRUE; break; #endif case 'l': /* Suppress location output */ opt.o_loc = FALSE; break; case 'n': /* Break output lines at end-of-line chars */ opt.o_eolbreak = TRUE; break; #ifdef INCOMPLETE case 'r': /* Reverse right to left */ opt.o_rev = TRUE; break; #endif case 'w': /* Data words (little-endian), not bytes */ opt.o_word = WORD_LE; break; case 'W': /* Data words (big-endian), not bytes */ opt.o_word = WORD_BE; break; default: goto usage; } } nextarg: ; } /* Adjust some of the command options */ if (opt.o_word != WORD_NONE) { opt.o_start &= ~0x00000001Lu; opt.o_end |= 0x00000001Lu; } /* Check command usage */ if (i >= argc) goto usage; /* Process filename args */ fcount = 0; for ( ; i < argc; i++) { FILE * fp; /* Process the next filename */ opt.o_fname = argv[i]; if (opt.o_fname[0] == '-' and opt.o_fname[1] == '\0') { opt.o_fname = NULL; fp = stdin; /* Read input from stdin */ #ifdef O_BINARY if (setmode(fileno(fp), O_BINARY) >= 0) { setvbuf(fp, fbuf, _IOFBF, FBUFSZ); } else { fprintf(stderr, "%s: Can't set binary mode on standard input, error %d,\n" " %s\n", prog, errno, strerror(errno)); return EXIT_FAILURE; } #endif /* Dump the contents of stdin */ dump(fp, stdout, &opt); fcount++; #ifdef O_BINARY setvbuf(fp, NULL, _IONBF, 0); #endif } else { /* Read input from a named file */ #ifndef FSEARCH fp = fopen(opt.o_fname, "rb"); if (fp != NULL) { /* Dump the file contents */ if (fcount > 0 and opt.o_contents) putchar((opt.o_formfeeds ? '\f' : '\n')); setvbuf(fp, fbuf, _IOFBF, FBUFSZ); dump(fp, stdout, &opt); fclose(fp); fcount++; } else { fprintf(stderr, "%s: Can't read '%s', error %d,\n %s\n", prog, opt.o_fname, errno, strerror(errno)); } #else /* FSEARCH */ /* Process multiple wildcard filenames */ if (not fpstart(opt.o_fname, NULL, _A_NORMAL)) { fprintf(stderr, "%s: Can't find '%s'\n", prog, opt.o_fname); continue; } while (fpnext(NULL, NULL, 1)) { /* Read the next named file */ opt.o_fname = fps_name; fp = fopen(opt.o_name, "rb"); if (fp != NULL) { /* Dump the file contents */ if (fcount > 0 and opt.o_contents) putchar((opt.o_formfeeds ? '\f' : '\n')); setvbuf(fp, fbuf, _IOFBF, FBUFSZ); dump(fp, stdout, &opt); fclose(fp); fcount++; } else { fprintf(stderr, "%s: Can't read '%s',\n %s\n", prog, fps_name, errno, strerror(errno)); } } #endif /* FSEARCH */ } } /* Done */ return EXIT_SUCCESS; usage: /* Display a usage message */ fprintf(stderr, "[%s, %.4s %.10s] (david" "\100" "tribble.com)\n\n", prog, revno+11, revdate+7); fprintf(stderr, "Display (dump) the contents of one or more files as" " hexadecimal.\n\n"); fprintf(stderr, "Usage: %s [-option...] filename...\n", prog); fprintf(stderr, " %s [-option...] -