blob: 077fd93e434fcb414b4d4d3e1e0d11ce2df218c5 [file] [log] [blame]
/*
* Copyright (c) 2004-2014 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.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define DEF_BYTES_PER_LINE 16
static int bytes_per_line = DEF_BYTES_PER_LINE;
static const char * version_str = "1.14 20140213";
#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;
}
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 [-b=<n>] [-h] [-H] [-N] [-V] [-?] "
"[<file>+]\n");
fprintf(stderr, " where:\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, " -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;
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 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 ((len > 1) && ('-' == cp[0]) && ('-' != cp[1])) {
res = 0;
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, '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 (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);
start = 0;
if (! doHex)
printf("ASCII hex dump of file: %s\n", argv[k]);
while ((res = read(inFile, buff, num)) > 0) {
if (doHex)
dStrHexOnly(buff, res, start, noAddr);
else
dStrHex(buff, res, start, noAddr);
start += (long)res;
}
}
close(inFile);
}
} else {
sg_set_binary_mode(inFile);
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;
}