summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2002-05-17 07:14:55 +0000
committertjr <tjr@FreeBSD.org>2002-05-17 07:14:55 +0000
commit98e1f63634ab9b117258a176e0727c23126bb762 (patch)
tree49576657a735280445ea47b1b64d5fd64338a7a9 /usr.bin
parente303f729c675ac851fc3efc31e1df4f0c9bbc71c (diff)
downloadFreeBSD-src-98e1f63634ab9b117258a176e0727c23126bb762.zip
FreeBSD-src-98e1f63634ab9b117258a176e0727c23126bb762.tar.gz
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
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/hexdump/conv.c4
-rw-r--r--usr.bin/hexdump/display.c10
-rw-r--r--usr.bin/hexdump/od.1195
-rw-r--r--usr.bin/hexdump/odsyntax.c286
-rw-r--r--usr.bin/hexdump/parse.c17
5 files changed, 425 insertions, 87 deletions
diff --git a/usr.bin/hexdump/conv.c b/usr.bin/hexdump/conv.c
index 9cf3e87..eea03be 100644
--- a/usr.bin/hexdump/conv.c
+++ b/usr.bin/hexdump/conv.c
@@ -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:
diff --git a/usr.bin/hexdump/display.c b/usr.bin/hexdump/display.c
index ec957b7..d2e32fc 100644
--- a/usr.bin/hexdump/display.c
+++ b/usr.bin/hexdump/display.c
@@ -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 &&
diff --git a/usr.bin/hexdump/od.1 b/usr.bin/hexdump/od.1
index ac46aab..f135469 100644
--- a/usr.bin/hexdump/od.1
+++ b/usr.bin/hexdump/od.1
@@ -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
+.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
-.Fl w
-options, nor is compatibility provided for the ``label'' component
-of the offset syntax.
+.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 .
diff --git a/usr.bin/hexdump/odsyntax.c b/usr.bin/hexdump/odsyntax.c
index 214b949..082a0a0 100644
--- a/usr.bin/hexdump/odsyntax.c
+++ b/usr.bin/hexdump/odsyntax.c
@@ -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;
@@ -153,6 +182,17 @@ oldsyntax(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;
char ***argvp;
@@ -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)
+{
+ char fchar;
+
+ 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 first = 1;
-
- if (first) {
- first = 0;
- add("\"%07.7_Ao\n\"");
- add("\"%07.7_ao \"");
- } else
- add("\" \"");
+ static int needpad;
+
+ if (needpad)
+ add("\""PADDING"\"");
+ add(fmt);
+ needpad = 1;
}
diff --git a/usr.bin/hexdump/parse.c b/usr.bin/hexdump/parse.c
index da93e7b..85e035e 100644
--- a/usr.bin/hexdump/parse.c
+++ b/usr.bin/hexdump/parse.c
@@ -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':
OpenPOWER on IntegriCloud