Overhaul hexdump's od syntax code to handle the -s -A -j -N -t options that
SUSv3 requires and give od a proper manual page. PR: 36783
This commit is contained in:
parent
fded097c79
commit
0b8ca07233
@ -57,8 +57,6 @@ conv_c(pr, p)
|
||||
goto strpr;
|
||||
/* case '\a': */
|
||||
case '\007':
|
||||
if (odmode) /* od didn't know about \a */
|
||||
break;
|
||||
str = "\\a";
|
||||
goto strpr;
|
||||
case '\b':
|
||||
@ -77,8 +75,6 @@ conv_c(pr, p)
|
||||
str = "\\t";
|
||||
goto strpr;
|
||||
case '\v':
|
||||
if (odmode)
|
||||
break;
|
||||
str = "\\v";
|
||||
goto strpr;
|
||||
default:
|
||||
|
@ -150,9 +150,11 @@ print(pr, bp)
|
||||
bcopy(bp, &f8, sizeof(f8));
|
||||
(void)printf(pr->fmt, f8);
|
||||
break;
|
||||
case sizeof(long double):
|
||||
bcopy(bp, &ldbl, sizeof(ldbl));
|
||||
(void)printf(pr->fmt, ldbl);
|
||||
default:
|
||||
if (pr->bcnt == sizeof(long double)) {
|
||||
bcopy(bp, &ldbl, sizeof(ldbl));
|
||||
(void)printf(pr->fmt, ldbl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -259,6 +261,8 @@ get()
|
||||
* block and set the end flag.
|
||||
*/
|
||||
if (!length || (ateof && !next((char **)NULL))) {
|
||||
if (odmode && address < skip)
|
||||
errx(1, "cannot skip past end of input");
|
||||
if (need == blocksize)
|
||||
return((u_char *)NULL);
|
||||
if (vflag != ALL &&
|
||||
|
@ -32,7 +32,7 @@
|
||||
.\" @(#)od.1 8.1 (Berkeley) 6/6/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 27, 1994
|
||||
.Dd April 17, 2002
|
||||
.Os
|
||||
.Dt OD 1
|
||||
.Sh NAME
|
||||
@ -40,7 +40,11 @@
|
||||
.Nd octal, decimal, hex, ASCII dump
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl aBbcDdeFfHhIiLlOovXx
|
||||
.Op Fl aBbcDdeFfHhIiLlOosvXx
|
||||
.Op Fl A Ar base
|
||||
.Op Fl j Ar skip
|
||||
.Op Fl N Ar length
|
||||
.Op Fl t Ar type
|
||||
.Sm off
|
||||
.Oo
|
||||
.Op Cm \&+
|
||||
@ -49,32 +53,183 @@
|
||||
.Op Cm Bb
|
||||
.Oc
|
||||
.Sm on
|
||||
.Ar file
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm hexdump
|
||||
utility, if called as
|
||||
.Nm ,
|
||||
provides compatibility for the options listed above.
|
||||
.Nm
|
||||
utility is a filter which displays the specified files, or standard
|
||||
input if no files are specified, in a user specified format.
|
||||
.Pp
|
||||
It does not provide compatibility for the
|
||||
.Fl s
|
||||
option (see
|
||||
.Xr strings 1 )
|
||||
or the
|
||||
.Fl P ,
|
||||
.Fl p ,
|
||||
The options are as follows:
|
||||
.Bl -tag -width Fl
|
||||
.It Fl A Ar base
|
||||
Specify the input address base.
|
||||
.Ar base
|
||||
may be one of
|
||||
.Ql d ,
|
||||
.Ql o ,
|
||||
.Ql x
|
||||
or
|
||||
.Fl w
|
||||
options, nor is compatibility provided for the ``label'' component
|
||||
of the offset syntax.
|
||||
.Ql n ,
|
||||
which specify decimal, octal, hexadecimal
|
||||
addresses or no address, respectively.
|
||||
.It Fl a
|
||||
Output named characters.
|
||||
Equivalent to
|
||||
.Fl t Ar a .
|
||||
.It Fl B , Fl o
|
||||
Output octal shorts.
|
||||
Equivalent to
|
||||
.Fl t Ar o2 .
|
||||
.It Fl b
|
||||
Output octal bytes.
|
||||
Equivalent to
|
||||
.Fl t Ar o1 .
|
||||
.It Fl c
|
||||
Output C-style escaped characters.
|
||||
Equivalent to
|
||||
.Fl t Ar c .
|
||||
.It Fl D
|
||||
Output unsigned decimal ints.
|
||||
Equivalent to
|
||||
.Fl t Ar u4 .
|
||||
.It Fl e , Fl F
|
||||
Output double-precision floating point numbers.
|
||||
Equivalent to
|
||||
.Fl t Ar fD .
|
||||
.It Fl f
|
||||
Output single-precision floating point numbers.
|
||||
Equivalent to
|
||||
.Fl t Ar fF .
|
||||
.It Fl H , Fl X
|
||||
Output hexadecimal ints.
|
||||
Equivalent to
|
||||
.Fl t Ar x4 .
|
||||
.It Fl h , Fl x
|
||||
Output hexadecimal shorts.
|
||||
Equivalent to
|
||||
.Fl t Ar x2 .
|
||||
.It Fl I , Fl L , Fl l
|
||||
Output signed decimal longs.
|
||||
Equivalent to
|
||||
.Fl t Ar dL .
|
||||
.It Fl i
|
||||
Output signed decimal ints.
|
||||
Equivalent to
|
||||
.Fl t Ar dI .
|
||||
.It Fl j Ar skip
|
||||
Skip
|
||||
.Ar skip
|
||||
bytes of the combined input before dumping. The number may be followed by one
|
||||
of
|
||||
.Ql b ,
|
||||
.Ql k
|
||||
or
|
||||
.Ql m
|
||||
which specify the units of the number as blocks (512 bytes), kilobytes and
|
||||
megabytes, respectively.
|
||||
.It Fl N Ar length
|
||||
Dump at most
|
||||
.Ar length
|
||||
bytes of input.
|
||||
.It Fl O
|
||||
Output octal ints.
|
||||
Equivalent to
|
||||
.Fl t Ar o4 .
|
||||
.It Fl s
|
||||
Output signed decimal shorts.
|
||||
Equivalent to
|
||||
.Fl t Ar d2 .
|
||||
.It Fl t Ar type
|
||||
Specify the output format.
|
||||
.Ar type
|
||||
is a string containing one or more of the following kinds of type specifiers:
|
||||
.Bl -tag -width indent
|
||||
.It Cm a
|
||||
Named characters
|
||||
.Pq Sq ASCII .
|
||||
Control characters are displayed using the following names:
|
||||
.Bl -column \&000_nu \&001_so \&002_st \&003_et \&004_eo
|
||||
.It "\&000\ nul\t001\ soh\t002\ stx\t003\ etx\t004\ eot\t005\ enq
|
||||
.It "\&006\ ack\t007\ bel\t008\ bs\t009\ ht\t00A\ nl\t00B\ vt
|
||||
.It "\&00C\ ff\t00D\ cr\t00E\ so\t00F\ si\t010\ dle\t011\ dc1
|
||||
.It "\&012\ dc2\t013\ dc3\t014\ dc4\t015\ nak\t016\ syn\t017\ etb
|
||||
.It "\&018\ can\t019\ em\t01A\ sub\t01B\ esc\t01C\ fs\t01D\ gs
|
||||
.It "\&01E\ rs\t01F\ us\t020\ sp\t0FF\ del
|
||||
.El
|
||||
.It Cm c
|
||||
Characters in the default character set. Non-printing characters are
|
||||
represented as 3-digit octal character codes, except the following
|
||||
characters, which are represented as C escapes:
|
||||
.Bl -column carriage-return \er
|
||||
.It NUL Ta \e0
|
||||
.It alert Ta \ea
|
||||
.It backspace Ta \eb
|
||||
.It newline Ta \en
|
||||
.It carriage-return Ta \er
|
||||
.It tab Ta \et
|
||||
.It vertical tab Ta \ev
|
||||
.El
|
||||
.It Cm [d|o|u|x][C|S|I|L| Ns Ar n Ns ]
|
||||
Signed decimal
|
||||
.Pq Ql d ,
|
||||
octal
|
||||
.Pq Ql o ,
|
||||
unsigned decimal
|
||||
.Pq Ql u
|
||||
or
|
||||
hexadecimal
|
||||
.Pq Ql x .
|
||||
Followed by an optional size specifier, which may be either
|
||||
.Ql C
|
||||
.Pq "char" ,
|
||||
.Ql S
|
||||
.Pq "short" ,
|
||||
.Ql I
|
||||
.Pq "int" ,
|
||||
.Ql L
|
||||
.Pq "long" ,
|
||||
or a byte count as a decimal integer.
|
||||
.It Cm f[F|D|L| Ns Ar n Ns ]
|
||||
Floating-point number.
|
||||
Followed by an optional size specifier, which may be either
|
||||
.Ql F
|
||||
.Pq "float" ,
|
||||
.Ql D
|
||||
.Pq "double"
|
||||
or
|
||||
.Ql L
|
||||
.Pq "long double" .
|
||||
.El
|
||||
.It Fl v
|
||||
Write all input data, instead of replacing lines of duplicate values with a
|
||||
.Ql * .
|
||||
.El
|
||||
.Pp
|
||||
Multiple options that specify output format may be used; the output will
|
||||
contain one line for each format.
|
||||
.Pp
|
||||
If no output format is specified,
|
||||
.Fl t Ar oS
|
||||
is assumed.
|
||||
.Sh DIAGNOSTICS
|
||||
.Ex -std
|
||||
.Sh COMPATIBILITY
|
||||
The traditional
|
||||
.Fl s
|
||||
option to extract string constants is not supported; consider using
|
||||
.Xr strings 1
|
||||
instead.
|
||||
.Sh SEE ALSO
|
||||
.Xr hexdump 1 ,
|
||||
.Xr strings 1
|
||||
.Sh BUGS
|
||||
Quite a few.
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility conforms to
|
||||
.St -p1003.1-2001 .
|
||||
.Sh HISTORY
|
||||
A
|
||||
An
|
||||
.Nm
|
||||
command appeared in
|
||||
.At v1 .
|
||||
|
@ -43,107 +43,136 @@ static const char rcsid[] =
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hexdump.h"
|
||||
|
||||
#define PADDING " "
|
||||
|
||||
int odmode;
|
||||
|
||||
static void odadd(const char *);
|
||||
static void odformat(const char *);
|
||||
static const char *odformatfp(char, const char *);
|
||||
static const char *odformatint(char, const char *);
|
||||
static void odoffset(int, char ***);
|
||||
static void odprecede(void);
|
||||
static void odusage(void);
|
||||
|
||||
void
|
||||
oldsyntax(argc, argvp)
|
||||
int argc;
|
||||
char ***argvp;
|
||||
{
|
||||
static char empty[] = "", padding[] = PADDING;
|
||||
int ch;
|
||||
char **argv;
|
||||
char **argv, *end;
|
||||
|
||||
/* Add initial (default) address format. -A may change it later. */
|
||||
#define TYPE_OFFSET 7
|
||||
add("\"%07.7_Ao\n\"");
|
||||
add("\"%07.7_ao \"");
|
||||
|
||||
odmode = 1;
|
||||
argv = *argvp;
|
||||
while ((ch = getopt(argc, argv, "aBbcDdeFfHhIiLlOoPpswvXx")) != -1)
|
||||
while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1)
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
switch (*optarg) {
|
||||
case 'd': case 'o': case 'x':
|
||||
fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
|
||||
fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
|
||||
*optarg;
|
||||
break;
|
||||
case 'n':
|
||||
fshead->nextfu->fmt = empty;
|
||||
fshead->nextfs->nextfu->fmt = padding;
|
||||
break;
|
||||
default:
|
||||
errx(1, "%s: invalid address base", optarg);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
odprecede();
|
||||
add("16/1 \"%3_u \" \"\\n\"");
|
||||
odformat("a");
|
||||
break;
|
||||
case 'B':
|
||||
case 'o':
|
||||
odprecede();
|
||||
add("8/2 \" %06o \" \"\\n\"");
|
||||
odformat("o2");
|
||||
break;
|
||||
case 'b':
|
||||
odprecede();
|
||||
add("16/1 \"%03o \" \"\\n\"");
|
||||
odformat("o1");
|
||||
break;
|
||||
case 'c':
|
||||
odprecede();
|
||||
add("16/1 \"%3_c \" \"\\n\"");
|
||||
odformat("c");
|
||||
break;
|
||||
case 'd':
|
||||
odprecede();
|
||||
add("8/2 \" %05u \" \"\\n\"");
|
||||
odformat("u2");
|
||||
break;
|
||||
case 'D':
|
||||
odprecede();
|
||||
add("4/4 \" %010u \" \"\\n\"");
|
||||
odformat("u4");
|
||||
break;
|
||||
case 'e': /* undocumented in od */
|
||||
case 'F':
|
||||
odprecede();
|
||||
add("2/8 \" %21.14e \" \"\\n\"");
|
||||
odformat("fD");
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
odprecede();
|
||||
add("4/4 \" %14.7e \" \"\\n\"");
|
||||
odformat("fF");
|
||||
break;
|
||||
case 'H':
|
||||
case 'X':
|
||||
odprecede();
|
||||
add("4/4 \" %08x \" \"\\n\"");
|
||||
odformat("x4");
|
||||
break;
|
||||
case 'h':
|
||||
case 'x':
|
||||
odprecede();
|
||||
add("8/2 \" %04x \" \"\\n\"");
|
||||
odformat("x2");
|
||||
break;
|
||||
case 'I':
|
||||
case 'L':
|
||||
case 'l':
|
||||
odprecede();
|
||||
add("4/4 \" %11d \" \"\\n\"");
|
||||
odformat("dL");
|
||||
break;
|
||||
case 'i':
|
||||
odprecede();
|
||||
add("8/2 \" %6d \" \"\\n\"");
|
||||
odformat("dI");
|
||||
break;
|
||||
case 'j':
|
||||
errno = 0;
|
||||
skip = strtoll(optarg, &end, 0);
|
||||
if (*end == 'b')
|
||||
skip *= 512;
|
||||
else if (*end == 'k')
|
||||
skip *= 1024;
|
||||
else if (*end == 'm')
|
||||
skip *= 1048576L;
|
||||
if (errno != 0 || skip < 0 || strlen(end) > 1)
|
||||
errx(1, "%s: invalid skip amount", optarg);
|
||||
break;
|
||||
case 'N':
|
||||
if ((length = atoi(optarg)) <= 0)
|
||||
errx(1, "%s: invalid length", optarg);
|
||||
break;
|
||||
case 'O':
|
||||
odprecede();
|
||||
add("4/4 \" %011o \" \"\\n\"");
|
||||
odformat("o4");
|
||||
break;
|
||||
case 's':
|
||||
odformat("d2");
|
||||
break;
|
||||
case 't':
|
||||
odformat(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
vflag = ALL;
|
||||
break;
|
||||
case 'P':
|
||||
case 'p':
|
||||
case 's':
|
||||
case 'w':
|
||||
case '?':
|
||||
default:
|
||||
if (ch != '?')
|
||||
warnx("hexdump(1) compatibility doesn't support the -%c option%s",
|
||||
ch, ch == 's' ? "; see strings(1)" : "");
|
||||
usage();
|
||||
odusage();
|
||||
}
|
||||
|
||||
if (!fshead) {
|
||||
add("\"%07.7_Ao\n\"");
|
||||
add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\"");
|
||||
}
|
||||
if (fshead->nextfs->nextfs == NULL)
|
||||
odformat("oS");
|
||||
|
||||
argc -= optind;
|
||||
*argvp += optind;
|
||||
@ -152,6 +181,17 @@ oldsyntax(argc, argvp)
|
||||
odoffset(argc, argvp);
|
||||
}
|
||||
|
||||
static void
|
||||
odusage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr,
|
||||
"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n");
|
||||
fprintf(stderr,
|
||||
" [[+]offset[.][Bb]] [file ...]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
odoffset(argc, argvp)
|
||||
int argc;
|
||||
@ -237,7 +277,6 @@ odoffset(argc, argvp)
|
||||
* If the offset uses a non-octal base, the base of the offset
|
||||
* is changed as well. This isn't pretty, but it's easy.
|
||||
*/
|
||||
#define TYPE_OFFSET 7
|
||||
if (base == 16) {
|
||||
fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
|
||||
fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
|
||||
@ -251,14 +290,157 @@ odoffset(argc, argvp)
|
||||
}
|
||||
|
||||
static void
|
||||
odprecede()
|
||||
odformat(const char *fmt)
|
||||
{
|
||||
static int first = 1;
|
||||
char fchar;
|
||||
|
||||
if (first) {
|
||||
first = 0;
|
||||
add("\"%07.7_Ao\n\"");
|
||||
add("\"%07.7_ao \"");
|
||||
} else
|
||||
add("\" \"");
|
||||
while (*fmt != '\0') {
|
||||
switch ((fchar = *fmt++)) {
|
||||
case 'a':
|
||||
odadd("16/1 \"%3_u \" \"\\n\"");
|
||||
break;
|
||||
case 'c':
|
||||
odadd("16/1 \"%3_c \" \"\\n\"");
|
||||
break;
|
||||
case 'o': case 'u': case 'd': case 'x':
|
||||
fmt = odformatint(fchar, fmt);
|
||||
break;
|
||||
case 'f':
|
||||
fmt = odformatfp(fchar, fmt);
|
||||
break;
|
||||
default:
|
||||
errx(1, "%c: unrecognised format character", fchar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
odformatfp(char fchar __unused, const char *fmt)
|
||||
{
|
||||
size_t isize;
|
||||
int digits;
|
||||
char *end, *hdfmt;
|
||||
|
||||
isize = sizeof(double);
|
||||
switch (*fmt) {
|
||||
case 'F':
|
||||
isize = sizeof(float);
|
||||
fmt++;
|
||||
break;
|
||||
case 'D':
|
||||
isize = sizeof(double);
|
||||
fmt++;
|
||||
break;
|
||||
case 'L':
|
||||
isize = sizeof(long double);
|
||||
fmt++;
|
||||
break;
|
||||
default:
|
||||
if (isdigit((unsigned char)*fmt)) {
|
||||
errno = 0;
|
||||
isize = (size_t)strtoul(fmt, &end, 10);
|
||||
if (errno != 0 || isize == 0)
|
||||
errx(1, "%s: invalid size", fmt);
|
||||
fmt = (const char *)end;
|
||||
}
|
||||
}
|
||||
switch (isize) {
|
||||
case sizeof(float):
|
||||
digits = FLT_DIG;
|
||||
break;
|
||||
case sizeof(double):
|
||||
digits = DBL_DIG;
|
||||
break;
|
||||
default:
|
||||
if (isize == sizeof(long double))
|
||||
digits = LDBL_DIG;
|
||||
else
|
||||
errx(1, "unsupported floating point size %lu",
|
||||
(u_long)isize);
|
||||
}
|
||||
|
||||
asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"",
|
||||
16UL / (u_long)isize, (u_long)isize, digits + 8, digits);
|
||||
if (hdfmt == NULL)
|
||||
err(1, NULL);
|
||||
odadd(hdfmt);
|
||||
free(hdfmt);
|
||||
|
||||
return (fmt);
|
||||
}
|
||||
|
||||
static const char *
|
||||
odformatint(char fchar, const char *fmt)
|
||||
{
|
||||
unsigned long long n;
|
||||
size_t isize;
|
||||
int digits;
|
||||
char *end, *hdfmt;
|
||||
|
||||
isize = sizeof(int);
|
||||
switch (*fmt) {
|
||||
case 'C':
|
||||
isize = sizeof(char);
|
||||
fmt++;
|
||||
break;
|
||||
case 'I':
|
||||
isize = sizeof(int);
|
||||
fmt++;
|
||||
break;
|
||||
case 'L':
|
||||
isize = sizeof(long);
|
||||
fmt++;
|
||||
break;
|
||||
case 'S':
|
||||
isize = sizeof(short);
|
||||
fmt++;
|
||||
break;
|
||||
default:
|
||||
if (isdigit((unsigned char)*fmt)) {
|
||||
errno = 0;
|
||||
isize = (size_t)strtoul(fmt, &end, 10);
|
||||
if (errno != 0 || isize == 0)
|
||||
errx(1, "%s: invalid size", fmt);
|
||||
if (isize != sizeof(char) && isize != sizeof(short) &&
|
||||
isize != sizeof(int) && isize != sizeof(long))
|
||||
errx(1, "unsupported int size %lu",
|
||||
(u_long)isize);
|
||||
fmt = (const char *)end;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the maximum number of digits we need to
|
||||
* fit the number. Overestimate for decimal with log
|
||||
* base 8. We need one extra space for signed numbers
|
||||
* to store the sign.
|
||||
*/
|
||||
n = (1ULL << (8 * isize)) - 1;
|
||||
digits = 0;
|
||||
while (n != 0) {
|
||||
digits++;
|
||||
n >>= (fchar == 'x') ? 4 : 3;
|
||||
}
|
||||
if (fchar == 'd')
|
||||
digits++;
|
||||
asprintf(&hdfmt, "%lu/%lu \"%%%s%d%c \" \"\\n\"",
|
||||
16UL / (u_long)isize, (u_long)isize,
|
||||
(fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar);
|
||||
if (hdfmt == NULL)
|
||||
err(1, NULL);
|
||||
odadd(hdfmt);
|
||||
free(hdfmt);
|
||||
|
||||
return (fmt);
|
||||
}
|
||||
|
||||
static void
|
||||
odadd(const char *fmt)
|
||||
{
|
||||
static int needpad;
|
||||
|
||||
if (needpad)
|
||||
add("\""PADDING"\"");
|
||||
add(fmt);
|
||||
needpad = 1;
|
||||
}
|
||||
|
@ -313,15 +313,16 @@ isint: cs[2] = '\0';
|
||||
case 4:
|
||||
pr->bcnt = 4;
|
||||
break;
|
||||
case sizeof(long double):
|
||||
cs[2] = '\0';
|
||||
cs[1] = cs[0];
|
||||
cs[0] = 'L';
|
||||
pr->bcnt = sizeof(long double);
|
||||
break;
|
||||
default:
|
||||
p1[1] = '\0';
|
||||
badcnt(p1);
|
||||
if (fu->bcnt == sizeof(long double)) {
|
||||
cs[2] = '\0';
|
||||
cs[1] = cs[0];
|
||||
cs[0] = 'L';
|
||||
pr->bcnt = sizeof(long double);
|
||||
} else {
|
||||
p1[1] = '\0';
|
||||
badcnt(p1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
|
Loading…
Reference in New Issue
Block a user