aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile56
-rw-r--r--utils/Makefile.cygwin33
-rw-r--r--utils/Makefile.freebsd52
-rw-r--r--utils/Makefile.mingw33
-rw-r--r--utils/Makefile.solaris51
-rw-r--r--utils/README20
-rw-r--r--utils/hxascdmp.1111
-rw-r--r--utils/hxascdmp.c521
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;
+}