diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/Makefile | 56 | ||||
-rw-r--r-- | utils/Makefile.cygwin | 33 | ||||
-rw-r--r-- | utils/Makefile.freebsd | 52 | ||||
-rw-r--r-- | utils/Makefile.mingw | 33 | ||||
-rw-r--r-- | utils/Makefile.solaris | 51 | ||||
-rw-r--r-- | utils/README | 20 | ||||
-rw-r--r-- | utils/hxascdmp.1 | 111 | ||||
-rw-r--r-- | utils/hxascdmp.c | 521 |
8 files changed, 877 insertions, 0 deletions
diff --git a/utils/Makefile b/utils/Makefile new file mode 100644 index 00000000..9558f9eb --- /dev/null +++ b/utils/Makefile @@ -0,0 +1,56 @@ +SHELL = /bin/sh + +PREFIX=/usr/local +INSTDIR=$(DESTDIR)/$(PREFIX)/bin +MANDIR=$(DESTDIR)/$(PREFIX)/share/man + +CC = gcc +LD = gcc + +EXECS = hxascdmp +EXTRA_EXECS = hxascdmp + +MAN_PGS = hxascdmp.1 +MAN_PREF = man1 + +CFLAGS = -g -O2 -W -Wall -iquote ../include +# CFLAGS = -g -O2 -W -iquote ../include -pedantic -std=c99 + +LDFLAGS = + +all: $(EXECS) + +depend dep: + for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ + done > .depend + +clean: + /bin/rm -f *.o $(EXTRA_EXECS) core .depend + +hxascdmp: hxascdmp.o + $(LD) -o $@ $(LDFLAGS) $^ + + +install: $(EXECS) + install -d $(INSTDIR) + for name in $^; \ + do install -s -o root -g root -m 755 $$name $(INSTDIR); \ + done + install -d $(MANDIR)/$(MAN_PREF) + for mp in $(MAN_PGS); \ + do install -o root -g root -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ + gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ + done + +uninstall: + dists="$(EXECS)"; \ + for name in $$dists; do \ + rm -f $(INSTDIR)/$$name; \ + done + for mp in $(MAN_PGS); do \ + rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ + done + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/utils/Makefile.cygwin b/utils/Makefile.cygwin new file mode 100644 index 00000000..86e9fa34 --- /dev/null +++ b/utils/Makefile.cygwin @@ -0,0 +1,33 @@ +# Assumes Makefile is used in a cygwin shell + +SHELL = /bin/sh + +CC = gcc +LD = gcc + +EXECS = hxascdmp + +EXE_S = hxascdmp.exe + +# OS_FLAGS = -DSG_LIB_WIN32 -DSPTD +OS_FLAGS = -DSG_LIB_WIN32 +LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +EXTRA_FLAGS = $(OS_FLAGS) $(LARGE_FILE_FLAGS) + +# CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS) +CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS) +# CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS) + +LDFLAGS = + +all: $(EXECS) + +clean: + rm *.o $(EXE_S) + +.c.o: + $(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $< + +hxascdmp: hxascdmp.o + $(LD) -o $@ $(LDFLAGS) $@.o + diff --git a/utils/Makefile.freebsd b/utils/Makefile.freebsd new file mode 100644 index 00000000..a43a5695 --- /dev/null +++ b/utils/Makefile.freebsd @@ -0,0 +1,52 @@ +SHELL = /bin/sh + +PREFIX=/usr/local +INSTDIR=$(DESTDIR)/$(PREFIX)/bin +MANDIR=$(DESTDIR)/$(PREFIX)/man + +CC = clang +LD = clang + +EXECS = hxascdmp + +MAN_PGS = +MAN_PREF = man8 + +CFLAGS = -g -O2 -W +# CFLAGS = -g -O2 -W -pedantic -std=c99 + +LDFLAGS = + +all: $(EXECS) + +depend dep: + for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ + done > .depend + +clean: + /bin/rm -f *.o $(EXECS) core .depend + +hxascdmp: hxascdmp.o + $(LD) -o $@ $(LDFLAGS) $@.o + + +install: $(EXECS) + install -d $(INSTDIR) + for name in $(EXECS); \ + do install -s -m 755 $$name $(INSTDIR); \ + done + install -d $(MANDIR)/$(MAN_PREF) + for mp in $(MAN_PGS); \ + do install -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ + gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ + done + +uninstall: + dists="$(EXECS)"; \ + for name in $$dists; do \ + rm -f $(INSTDIR)/$$name; \ + done + for mp in $(MAN_PGS); do \ + rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ + done + diff --git a/utils/Makefile.mingw b/utils/Makefile.mingw new file mode 100644 index 00000000..6fed3484 --- /dev/null +++ b/utils/Makefile.mingw @@ -0,0 +1,33 @@ +# Assumes makefile is used in a MSYS shell with a MinGW compiler available. + +SHELL = /bin/sh + +CC = gcc +LD = gcc + +EXECS = hxascdmp + +EXE_S = hxascdmp.exe + +# OS_FLAGS = -DSG_LIB_WIN32 -DSG_LIB_MINGW -DSPTD +OS_FLAGS = -DSG_LIB_WIN32 -DSG_LIB_MINGW +LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +EXTRA_FLAGS = $(OS_FLAGS) $(LARGE_FILE_FLAGS) + +# CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS) +CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS) +# CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS) + +LDFLAGS = + +all: $(EXECS) + +clean: + rm *.o $(EXE_S) + +.c.o: + $(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $< + +hxascdmp: hxascdmp.o + $(LD) -o $@ $(LDFLAGS) $@.o + diff --git a/utils/Makefile.solaris b/utils/Makefile.solaris new file mode 100644 index 00000000..075d0046 --- /dev/null +++ b/utils/Makefile.solaris @@ -0,0 +1,51 @@ +SHELL = /bin/sh + +PREFIX=/usr/local +INSTDIR=$(DESTDIR)/$(PREFIX)/bin +MANDIR=$(DESTDIR)/$(PREFIX)/man + +CC = gcc +LD = gcc + +EXECS = hxascdmp + +MAN_PGS = +MAN_PREF = man8 + +CFLAGS = -g -O2 -W +# CFLAGS = -g -O2 -W -pedantic -std=c99 + +LDFLAGS = + +all: $(EXECS) + +depend dep: + for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ + done > .depend + +clean: + /bin/rm -f *.o $(EXECS) core .depend + +hxascdmp: hxascdmp.o + $(LD) -o $@ $(LDFLAGS) $@.o + + +install: $(EXECS) + install -d $(INSTDIR) + for name in $(EXECS); \ + do install -s -f $(INSTDIR) $$name; \ + done + install -d $(MANDIR)/$(MAN_PREF) + for mp in $(MAN_PGS); \ + do install -m 644 -f $(MANDIR)/$(MAN_PREF) $$mp; \ + done + +uninstall: + dists="$(EXECS)"; \ + for name in $$dists; do \ + rm -f $(INSTDIR)/$$name; \ + done + for mp in $(MAN_PGS); do \ + rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ + done + diff --git a/utils/README b/utils/README new file mode 100644 index 00000000..c00c22a7 --- /dev/null +++ b/utils/README @@ -0,0 +1,20 @@ +This directory contains these utilities: + - hxascdmp: takes a binary stream and converts it to hexadecimal ASCII + which is sent to stdout. The incoming binary stream can either be + from a file or, in the absence of a file name, from stdin. Similar to + the Unix "od" command. By default, it decodes 16 bytes per line with + an ASCII interpretation to the right of each line. See its + hxascdmp(1) man page. + - sg_chk_asc and tst_sg_lib: are no longer here, they have been moved + to the 'testing' directory (a sibling of this directory). + + +By default, the Makefile only builds the hxascdmp utility. The 'Makefile' +file (i.e. with no suffix) builds for Linux; the 'Makefile.freebsd' file +builds for FreeBSD (e.g. 'make -f Makefile.freebsd'); the +'Makefile.solaris' file builds for Solaris; the 'Makefile.mingw' builds +in the Windows MinGW environment (e.g. msys shell); and 'Makefile.cygwin' +builds in the Windows Cygwin environment. + +Douglas Gilbert +4th November 2017 diff --git a/utils/hxascdmp.1 b/utils/hxascdmp.1 new file mode 100644 index 00000000..22814922 --- /dev/null +++ b/utils/hxascdmp.1 @@ -0,0 +1,111 @@ +.TH HXASCDMP "1" "February 2019" "sg3_utils\-1.45" SG3_UTILS +.SH NAME +hxascdmp \- hexadecimal ASCII dump +.SH SYNOPSIS +.B hxascdmp +[\fI\-b=BPL\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-N\fR] [\fI\-o=OFF\fR] +[\fI\-V\fR] [\fIFILE+\fR] +.SH DESCRIPTION +.\" Add any additional description here +.PP +This utility reads one or more \fIFILE\fR names and dumps them in hexadecimal +and ASCII to stdout. If no \fIFILE\fR is given then stdin is read instead; +reading continues (or stalls) until an EOF is received. +.PP +The default format is to start each line with the hexadecimal address (offset +from the start of file) followed by 16 hexadecimal bytes separated by a +single space (apart from the 8th and 9th bytes which are separated by two +spaces). If the \fI\-H\fR is not given, there is then a string of 16 ASCII +characters corresponding to the hexadecimal bytes earlier in the line; only +bytes in the range 0x20 to 0x7e are printed in ASCII, other bytes values are +printed as '.' . If the \fI\-H\fR is not given, each \fIFILE\fR name that +appears on the command line is printed on a separate line prior to that +file's hexadecimal ASCII dump. +.PP +If the \fI\-N\fR option is given then no address is printed out and each +line starts with the next hexadecimal byte. +.PP +This utility is pretty close to the 'hexdump -C' variant of BSD's +.B hexdump(1) +command. +.SH OPTIONS +.TP +\fB\-b\fR=\fIBPL\fR +where \fIBPL\fR specifies the number of bytes per line. The default value is +16. 16 bytes per line is just enough to allow the address, 16 bytes in +hexadecimal followed by 16 bytes as ASCII to fit on a standard 80 column +wide terminal. +.TP +\fB\-h\fR +output the usage message then exit. +.TP +\fB\-H\fR +output hexadecimal only (i.e. don't place an ASCII representation at the +end of each line). +.TP +\fB\-N\fR +no address; so each line starts with the next hexadecimal byte. +.TP +\fB\-o\fR=\fIOFF\fR +where \fIOFF\fR specifies the byte offset from the beginning of the pipe or +the beginning of each file that the output starts. If the address is being +printed out then it starts at \fIOFF\fR. The default is an \fIOFF\fR of 0 . +.TP +\fB\-V\fR, \fB\-\-version\fR +print the version string and then exit. +.SH NOTES +In Windows the given file (or files) are set to binary mode. +.SH EXIT STATUS +The exit status of hxascdmp is 0 when it is successful. If any of the +given \fIFILE\fR names cannot be opened then the exit status is 1. +.SH EXAMPLES +First we manufacture a short file with a mix of data in it: mostly ASCII with +some control characters and 0xaa (which the echo command only accepts in +octal (0252): +.PP + $ echo -e "three blind mice,\t\r\0252" > 3bm.txt +.PP +Now we use this utility to see exactly what is in the file. To avoid +problems with line wrapping, the bytes per line option is set to 8: +.PP + $ hxascdmp -b=8 3bm.txt +.br +ASCII hex dump of file: 3bm.txt +.br + 00 74 68 72 65 65 20 62 6c three bl +.br + 08 69 6e 64 20 6d 69 63 65 ind mice +.br + 10 2c 09 0d aa 0a ,.... +.PP +Using the same file, use this utility to output only hexadecimal formatted +16 bytes per line. +.PP + $ hxascdmp -H 3bm.txt +.br +hex dump of file: 3bm.txt +.br + 00 74 68 72 65 65 20 62 6c 69 6e 64 20 6d 69 63 65 +.br + 10 2c 09 0d aa 0a +.PP +For comparison the hexdump utility gives similar output: +.PP + $ hexdump -C 3bm.txt +.br +00000000 74 68 72 65 65 20 62 6c 69 6e 64 20 6d 69 63 65 |three blind mice| +.br +00000010 2c 09 0d aa 0a |,....| +.br +00000015 +.SH AUTHORS +Written by Douglas Gilbert. +.SH "REPORTING BUGS" +Report bugs to <dgilbert at interlog dot com>. +.SH COPYRIGHT +Copyright \(co 2004\-2019 Douglas Gilbert +.br +This software is distributed under a FreeBSD license. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +.SH "SEE ALSO" +.B hexdump(1) diff --git a/utils/hxascdmp.c b/utils/hxascdmp.c new file mode 100644 index 00000000..f08d0313 --- /dev/null +++ b/utils/hxascdmp.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2004-2019 Douglas Gilbert. + * All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the BSD_LICENSE file. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#define __STDC_FORMAT_MACROS 1 +#include <inttypes.h> + +#define DEF_BYTES_PER_LINE 16 + +static int bytes_per_line = DEF_BYTES_PER_LINE; + +static const char * version_str = "1.11 20190527"; + +#define CHARS_PER_HEX_BYTE 3 +#define BINARY_START_COL 6 +#define MAX_LINE_LENGTH 257 + + +#ifdef SG_LIB_MINGW +/* Non Unix OSes distinguish between text and binary files. + Set text mode on fd. Does nothing in Unix. Returns negative number on + failure. */ +int +sg_set_text_mode(int fd) +{ + return setmode(fd, O_TEXT); +} + +/* Set binary mode on fd. Does nothing in Unix. Returns negative number on + failure. */ +int +sg_set_binary_mode(int fd) +{ + return setmode(fd, O_BINARY); +} + +#else +/* For Unix the following functions are dummies. */ +int +sg_set_text_mode(int fd) +{ + return fd; /* fd should be >= 0 */ +} + +int +sg_set_binary_mode(int fd) +{ + return fd; +} +#endif + +/* Returns the number of times 'ch' is found in string 's' given the + * string's length. */ +static int +num_chs_in_str(const char * s, int slen, int ch) +{ + int res = 0; + + while (--slen >= 0) { + if (ch == s[slen]) + ++res; + } + return res; +} + +/* If the number in 'buf' can be decoded or the multiplier is unknown + * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal + * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)). + * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces + * and tabs; accept comma, hyphen, space, tab and hash as terminator. */ +int64_t +sg_get_llnum(const char * buf) +{ + int res, len, n; + int64_t num, ll; + uint64_t unum; + char * cp; + const char * b; + char c = 'c'; + char c2 = '\0'; /* keep static checker happy */ + char c3 = '\0'; /* keep static checker happy */ + char lb[32]; + + if ((NULL == buf) || ('\0' == buf[0])) + return -1LL; + len = strlen(buf); + n = strspn(buf, " \t"); + if (n > 0) { + if (n == len) + return -1LL; + buf += n; + len -= n; + } + /* following hack to keep C++ happy */ + cp = strpbrk((char *)buf, " \t,#-"); + if (cp) { + len = cp - buf; + n = (int)sizeof(lb) - 1; + len = (len < n) ? len : n; + memcpy(lb, buf, len); + lb[len] = '\0'; + b = lb; + } else + b = buf; + if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { + res = sscanf(b + 2, "%" SCNx64 , &unum); + num = unum; + } else if ('H' == toupper((int)b[len - 1])) { + res = sscanf(b, "%" SCNx64 , &unum); + num = unum; + } else + res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3); + if (res < 1) + return -1LL; + else if (1 == res) + return num; + else { + if (res > 2) + c2 = toupper((int)c2); + if (res > 3) + c3 = toupper((int)c3); + switch (toupper((int)c)) { + case 'C': + return num; + case 'W': + return num * 2; + case 'B': + return num * 512; + case 'K': + if (2 == res) + return num * 1024; + if (('B' == c2) || ('D' == c2)) + return num * 1000; + if (('I' == c2) && (4 == res) && ('B' == c3)) + return num * 1024; + return -1LL; + case 'M': + if (2 == res) + return num * 1048576; + if (('B' == c2) || ('D' == c2)) + return num * 1000000; + if (('I' == c2) && (4 == res) && ('B' == c3)) + return num * 1048576; + return -1LL; + case 'G': + if (2 == res) + return num * 1073741824; + if (('B' == c2) || ('D' == c2)) + return num * 1000000000; + if (('I' == c2) && (4 == res) && ('B' == c3)) + return num * 1073741824; + return -1LL; + case 'T': + if (2 == res) + return num * 1099511627776LL; + if (('B' == c2) || ('D' == c2)) + return num * 1000000000000LL; + if (('I' == c2) && (4 == res) && ('B' == c3)) + return num * 1099511627776LL; + return -1LL; + case 'P': + if (2 == res) + return num * 1099511627776LL * 1024; + if (('B' == c2) || ('D' == c2)) + return num * 1000000000000LL * 1000; + if (('I' == c2) && (4 == res) && ('B' == c3)) + return num * 1099511627776LL * 1024; + return -1LL; + case 'X': + cp = (char *)strchr(b, 'x'); + if (NULL == cp) + cp = (char *)strchr(b, 'X'); + if (cp) { + ll = sg_get_llnum(cp + 1); + if (-1LL != ll) + return num * ll; + } + return -1LL; + default: + fprintf(stderr, "unrecognized multiplier\n"); + return -1LL; + } + } +} + +static void +dStrHex(const char* str, int len, long start, int noAddr) +{ + const char* p = str; + unsigned char c; + char buff[MAX_LINE_LENGTH]; + long a = start; + int bpstart, cpstart; + int j, k, line_length, nl, cpos, bpos, midline_space; + + if (noAddr) { + bpstart = 0; + cpstart = ((CHARS_PER_HEX_BYTE * bytes_per_line) + 1) + 5; + } else { + bpstart = BINARY_START_COL; + cpstart = BINARY_START_COL + + ((CHARS_PER_HEX_BYTE * bytes_per_line) + 1) + 5; + } + cpos = cpstart; + bpos = bpstart; + midline_space = ((bytes_per_line + 1) / 2); + + if (len <= 0) + return; + line_length = BINARY_START_COL + + (bytes_per_line * (1 + CHARS_PER_HEX_BYTE)) + 7; + if (line_length >= MAX_LINE_LENGTH) { + fprintf(stderr, "bytes_per_line causes maximum line length of %d " + "to be exceeded\n", MAX_LINE_LENGTH); + return; + } + memset(buff, ' ', line_length); + buff[line_length] = '\0'; + if (0 == noAddr) { + k = sprintf(buff + 1, "%.2lx", a); + buff[k + 1] = ' '; + } + + for(j = 0; j < len; j++) { + nl = (0 == (j % bytes_per_line)); + if ((j > 0) && nl) { + printf("%s\n", buff); + bpos = bpstart; + cpos = cpstart; + a += bytes_per_line; + memset(buff,' ', line_length); + if (0 == noAddr) { + k = sprintf(buff + 1, "%.2lx", a); + buff[k + 1] = ' '; + } + } + c = *p++; + bpos += (nl && noAddr) ? 0 : CHARS_PER_HEX_BYTE; + if ((bytes_per_line > 4) && ((j % bytes_per_line) == midline_space)) + bpos++; + sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); + buff[bpos + 2] = ' '; + if ((c < ' ') || (c >= 0x7f)) + c='.'; + buff[cpos++] = c; + } + if (cpos > cpstart) + printf("%s\n", buff); +} + +static void +dStrHexOnly(const char* str, int len, long start, int noAddr) +{ + const char* p = str; + unsigned char c; + char buff[MAX_LINE_LENGTH]; + long a = start; + int bpstart, bpos, nl; + int midline_space = ((bytes_per_line + 1) / 2); + int j, k, line_length; + + if (len <= 0) + return; + bpstart = (noAddr ? 0 : BINARY_START_COL); + bpos = bpstart; + line_length = (noAddr ? 0 : BINARY_START_COL) + + (bytes_per_line * CHARS_PER_HEX_BYTE) + 4; + if (line_length >= MAX_LINE_LENGTH) { + fprintf(stderr, "bytes_per_line causes maximum line length of %d " + "to be exceeded\n", MAX_LINE_LENGTH); + return; + } + memset(buff, ' ', line_length); + buff[line_length] = '\0'; + if (0 == noAddr) { + k = sprintf(buff + 1, "%.2lx", a); + buff[k + 1] = ' '; + } + + for(j = 0; j < len; j++) { + nl = (0 == (j % bytes_per_line)); + if ((j > 0) && nl) { + printf("%s\n", buff); + bpos = bpstart; + a += bytes_per_line; + memset(buff,' ', line_length); + if (0 == noAddr) { + k = sprintf(buff + 1, "%.2lx", a); + buff[k + 1] = ' '; + } + } + c = *p++; + bpos += (nl && noAddr) ? 0 : CHARS_PER_HEX_BYTE; + if ((bytes_per_line > 4) && ((j % bytes_per_line) == midline_space)) + bpos++; + sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); + buff[bpos + 2] = ' '; + } + if (bpos > bpstart) + printf("%s\n", buff); +} + +static void +usage() +{ + fprintf(stderr, "Usage: hxascdmp [-1] [-2] [-b=<n>] [-h] [-H] [-N] " + "[-o=<off>] [-q]\n" + " [-V] [-?] [<file>+]\n"); + fprintf(stderr, " where:\n"); + fprintf(stderr, " -1 print first byte in hex, prepend '0x' " + "if '-H' given\n"); + fprintf(stderr, " -2 like '-1' but print first two bytes\n"); + fprintf(stderr, " -b=<n> bytes per line to display " + "(def: 16)\n"); + fprintf(stderr, " -h print this usage message\n"); + fprintf(stderr, " -H print hex only (i.e. no ASCII " + "to right)\n"); + fprintf(stderr, " -N no address, start in first column\n"); + fprintf(stderr, " -o=<off> start decoding at byte <off>. Suffix " + "multipliers allowed\n"); + fprintf(stderr, " -q quiet: suppress output of header " + "info\n"); + fprintf(stderr, " -V print version string then exits\n"); + fprintf(stderr, " -? print this usage message\n"); + fprintf(stderr, " <file>+ reads file(s) and outputs each " + "as hex ASCII\n"); + fprintf(stderr, " if no <file> then reads stdin\n\n"); + fprintf(stderr, "Sends hex ASCII dump of stdin/file to stdout\n"); +} + +int +main(int argc, const char ** argv) +{ + char buff[8192]; + int num = 8192; + long start = 0; + int64_t offset = 0; + int res, k, u, len, n; + int inFile = STDIN_FILENO; + int doHelp = 0; + int doHex = 0; + int noAddr = 0; + int doVersion = 0; + int hasFilename = 0; + int quiet = 0; + int print1 = 0; + int print2 = 0; + int ret = 0; + const char * cp; + + for (k = 1; k < argc; k++) { + cp = argv[k]; + len = strlen(cp); + if (0 == strncmp("-b=", cp, 3)) { + res = sscanf(cp + 3, "%d", &u); + if ((1 != res) || (u < 1)) { + fprintf(stderr, "Bad value after '-b=' option\n"); + usage(); + return 1; + } + bytes_per_line = u; + } else if (0 == strncmp("-o=", cp, 3)) { + int64_t off = sg_get_llnum(cp + 3); + + if (off == -1) { + fprintf(stderr, "Bad value after '-o=' option\n"); + usage(); + return 1; + } + offset = off; + } else if ((len > 1) && ('-' == cp[0]) && ('-' != cp[1])) { + res = 0; + n = num_chs_in_str(cp + 1, len - 1, '1'); + print1 += n; + res += n; + n = num_chs_in_str(cp + 1, len - 1, '2'); + print2 += n; + res += n; + n = num_chs_in_str(cp + 1, len - 1, 'h'); + doHelp += n; + res += n; + n = num_chs_in_str(cp + 1, len - 1, 'H'); + doHex += n; + res += n; + n = num_chs_in_str(cp + 1, len - 1, 'N'); + noAddr += n; + res += n; + n = num_chs_in_str(cp + 1, len - 1, 'q'); + quiet += n; + res += n; + n = num_chs_in_str(cp + 1, len - 1, 'V'); + doVersion += n; + res += n; + n = num_chs_in_str(cp + 1, len - 1, '?'); + doHelp += n; + res += n; + if (0 == res) { + fprintf(stderr, "No option recognized in str: %s\n", cp); + usage(); + return 1; + } + } else if (0 == strcmp("-?", argv[k])) + ++doHelp; + else if (*argv[k] == '-') { + fprintf(stderr, "unknown switch: %s\n", argv[k]); + usage(); + return 1; + } else { + hasFilename = 1; + break; + } + if (print2) + print1 += print2 + print2; + } + if (doVersion) { + printf("%s\n", version_str); + return 0; + } + if (doHelp) { + usage(); + return 0; + } + + /* Make sure num to fetch is integral multiple of bytes_per_line */ + if (0 != (num % bytes_per_line)) + num = (num / bytes_per_line) * bytes_per_line; + + if (hasFilename) { + for ( ; k < argc; k++) + { + inFile = open(argv[k], O_RDONLY); + if (inFile < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[k]); + ret = 1; + } else { + sg_set_binary_mode(inFile); + if (offset > 0) { + int err; + int64_t off_res; + + off_res = lseek(inFile, offset, SEEK_SET); + if (off_res < 0) { + err = errno; + fprintf(stderr, "failed moving filepos: wanted=%" + PRId64 " [0x%" PRIx64 "]\nlseek error: %s\n", + offset, offset, strerror(err)); + goto fini1; + } + start = offset; + } else + start = 0; + if (! (doHex || quiet || print1)) + printf("ASCII hex dump of file: %s\n", argv[k]); + while ((res = read(inFile, buff, num)) > 0) { + if (print1) { + if (1 == print1) { + if (doHex) + printf("0x%02x\n", (uint8_t)(buff[0])); + else + printf("%02x\n", (uint8_t)(buff[0])); + } else { + uint16_t us; + + memcpy(&us, buff, 2); + if (doHex) + printf("0x%04x\n", us); + else + printf("%04x\n", us); + } + break; + } + if (doHex) + dStrHexOnly(buff, res, start, noAddr); + else + dStrHex(buff, res, start, noAddr); + start += (long)res; + } + } +fini1: + close(inFile); + } + } else { + sg_set_binary_mode(inFile); + if (offset > 0) { + start = offset; + do { /* eat up offset bytes */ + if ((res = read(inFile, buff, + (num > offset ? offset : num))) > 0) + offset -= res; + else { + fprintf(stderr, "offset read() error: %s\n", + strerror(errno)); + break; + } + } while (offset > 0); + } + while ((res = read(inFile, buff, num)) > 0) { + if (doHex) + dStrHexOnly(buff, res, start, noAddr); + else + dStrHex(buff, res, start, noAddr); + start += (long)res; + } + } + return ret; +} |