Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Apr 2002 21:13:39 +1000 (EST)
From:      "Tim J. Robbins" <tim@robbins.dropbear.id.au>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   standards/36783: P1003.1-2001 -s -A -j -N -t options for od(1) (patch)
Message-ID:  <200204051113.g35BDdRZ002185@treetop.robbins.dropbear.id.au>

next in thread | raw e-mail | index | archive | help

>Number:         36783
>Category:       standards
>Synopsis:       P1003.1-2001 -s -A -j -N -t options for od(1) (patch)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-standards
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Apr 05 03:20:03 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Tim J. Robbins
>Release:        FreeBSD 4.5-STABLE i386
>Organization:
>Environment:
System: FreeBSD treetop.robbins.dropbear.id.au 4.5-STABLE FreeBSD 4.5-STABLE #2: Sat Mar 30 20:10:51 EST 2002 tim@treetop.robbins.dropbear.id.au:/usr/obj/usr/src/sys/GENERIC i386


	
>Description:
4.4BSD's (and FreeBSD's) hexdump utility is missing the -s, -A, -j, -N, and -t
options in its od compatibility mode. Here is a patch to add them.

>How-To-Repeat:
od -Ax -tx1 /dev/null
>Fix:

I've renamed the `deprecated' variable to `odmode' and removed everything
to do with deprecation from the program and manual pages, added the -t
option then rewritten all the other output-format options in terms of that.
I've also written a manual page that is much more complete than the old one.

long double output (-t fL) is not supported. This bug is documented in the
new manual page. Adding support for long double would require changes all
over the place, I thought it would be best to get it pretty close, then
add long double support for hexdump, then od.


Index: conv.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/hexdump/conv.c,v
retrieving revision 1.3
diff -u -r1.3 conv.c
--- conv.c	2002/03/07 23:00:27	1.3
+++ conv.c	2002/04/05 11:04:18
@@ -48,7 +48,6 @@
 	PR *pr;
 	u_char *p;
 {
-	extern int deprecated;
 	char buf[10];
 	char const *str;
 
@@ -58,7 +57,7 @@
 		goto strpr;
 	/* case '\a': */
 	case '\007':
-		if (deprecated)		/* od didn't know about \a */
+		if (odmode)		/* od didn't know about \a */
 			break;
 		str = "\\a";
 		goto strpr;
@@ -78,7 +77,7 @@
 		str = "\\t";
 		goto strpr;
 	case '\v':
-		if (deprecated)
+		if (odmode)
 			break;
 		str = "\\v";
 		goto strpr;
@@ -101,7 +100,6 @@
 	PR *pr;
 	u_char *p;
 {
-	extern int deprecated;
 	static char const * list[] = {
 		"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
 		 "bs",  "ht",  "lf",  "vt",  "ff",  "cr",  "so",  "si",
@@ -112,14 +110,14 @@
 						/* od used nl, not lf */
 	if (*p <= 0x1f) {
 		*pr->cchar = 's';
-		if (deprecated && *p == 0x0a)
+		if (odmode && *p == 0x0a)
 			(void)printf(pr->fmt, "nl");
 		else
 			(void)printf(pr->fmt, list[*p]);
 	} else if (*p == 0x7f) {
 		*pr->cchar = 's';
 		(void)printf(pr->fmt, "del");
-	} else if (deprecated && *p == 0x20) {	/* od replaced space with sp */
+	} else if (odmode && *p == 0x20) {	/* od replaced space with sp */
 		*pr->cchar = 's';
 		(void)printf(pr->fmt, " sp");
 	} else if (isprint(*p)) {
Index: display.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/hexdump/display.c,v
retrieving revision 1.11
diff -u -r1.11 display.c
--- display.c	2002/03/22 01:22:45	1.11
+++ display.c	2002/04/05 11:04:18
@@ -228,7 +228,6 @@
 u_char *
 get()
 {
-	extern int length;
 	static int ateof = 1;
 	static u_char *curp, *savp;
 	register int n;
@@ -255,6 +254,8 @@
 		 * 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 && 
@@ -298,8 +299,6 @@
 			nread += n;
 	}
 }
-
-extern off_t skip;			/* bytes to skip */
 
 int
 next(argv)
Index: hexdump.h
===================================================================
RCS file: /home/ncvs/src/usr.bin/hexdump/hexdump.h,v
retrieving revision 1.5
diff -u -r1.5 hexdump.h
--- hexdump.h	2002/03/22 01:22:45	1.5
+++ hexdump.h	2002/04/05 11:04:19
@@ -73,6 +73,9 @@
 
 extern FS *fshead;			/* head of format strings list */
 extern int blocksize;			/* data block size */
+extern int odmode;			/* are we acting as od(1)? */
+extern int length;			/* amount of data to read */
+extern off_t skip;			/* amount of data to skip at start */
 enum _vflag { ALL, DUP, FIRST, WAIT };	/* -v values */
 
 void	 add(const char *);
Index: hexsyntax.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/hexdump/hexsyntax.c,v
retrieving revision 1.9
diff -u -r1.9 hexsyntax.c
--- hexsyntax.c	2001/09/01 22:42:46	1.9
+++ hexsyntax.c	2002/04/05 11:04:19
@@ -58,7 +58,6 @@
 {
 	extern enum _vflag vflag;
 	extern FS *fshead;
-	extern int length;
 	int ch;
 	char *p, **argv;
 
Index: od.1
===================================================================
RCS file: /home/ncvs/src/usr.bin/hexdump/od.1,v
retrieving revision 1.10
diff -u -r1.10 od.1
--- od.1	2000/12/27 16:52:29	1.10
+++ od.1	2002/04/05 11:04:19
@@ -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 \&+
@@ -51,33 +55,141 @@
 .Sm on
 .Ar file
 .Sh DESCRIPTION
-.Nm Od
-has been deprecated in favor of
-.Xr hexdump 1 .
-.Pp
-.Nm Hexdump ,
-if called as
-.Nm ,
-provides compatibility for the options listed above.
+The
+.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
+Equivalent to
+.Fl t Ar a .
+.It Fl B , Fl o
+Equivalent to
+.Fl t Ar o2 .
+.It Fl b
+Equivalent to
+.Fl t Ar o1 .
+.It Fl c
+Equivalent to
+.Fl t Ar c .
+.It Fl D
+Equivalent to
+.Fl t Ar u4 .
+.It Fl e , Fl F
+Equivalent to
+.Fl t Ar fD .
+.It Fl f
+Equivalent to
+.Fl t Ar fF .
+.It Fl H , Fl X
+Equivalent to
+.Fl t Ar x4 .
+.It Fl h , Fl x
+Equivalent to
+.Fl t Ar x2 .
+.It Fl I , Fl L , Fl l
+Equivalent to
+.Fl t Ar dL .
+.It Fl i
+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
+Equivalent to
+.Fl t Ar o4 .
+.It Fl s
+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 .
+.It Cm c
+Characters.
+.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
-.Fl w
-options, nor is compatibility provided for the ``label'' component
-of the offset syntax.
+.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 SEE ALSO
 .Xr hexdump 1 ,
 .Xr strings 1
-.Sh BUGS
-Quite a few.
+.Sh STANDARDS
+The
+.Nm
+utility is expected to conform to
+.St -p1003.1-2001 .
 .Sh HISTORY
 A
 .Nm
 command appeared in
 .At v1 .
+.Sh BUGS
+The
+.Sq "long double"
+data type,
+.Fl t Ar fL ,
+is not supported.
Index: odsyntax.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/hexdump/odsyntax.c,v
retrieving revision 1.10
diff -u -r1.10 odsyntax.c
--- odsyntax.c	2002/03/22 01:22:45	1.10
+++ odsyntax.c	2002/04/05 11:04:20
@@ -43,16 +43,20 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "hexdump.h"
 
-int deprecated;
+#define PADDING	"         "
 
+int odmode;
+
+static void odadd(const char *);
+static void odformat(const char *);
 static void odoffset(int, char ***);
-static void odprecede(void);
 
 void
 oldsyntax(argc, argvp)
@@ -62,91 +66,110 @@
 	extern enum _vflag vflag;
 	extern FS *fshead;
 	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  \"");
 
-	deprecated = 1;
+	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 = "";
+				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 = (off_t)strtoul(optarg, &end, 0);
+			if (*end == 'b')
+				skip *= 512;
+			else if (*end == 'k')
+				skip *= 1024;
+			else if (*end == 'm')
+				skip *= 1048576L;
+			if (errno != 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:
-			warnx("od(1) has been deprecated for hexdump(1)");
-			if (ch != '?')
-				warnx("hexdump(1) compatibility doesn't support the -%c option%s",
-				    ch, ch == 's' ? "; see strings(1)" : "");
 			usage();
 		}
 
-	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;
@@ -160,7 +183,6 @@
 	int argc;
 	char ***argvp;
 {
-	extern off_t skip;
 	unsigned char *p, *num, *end;
 	int base;
 
@@ -241,7 +263,6 @@
 	 * 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';
@@ -254,15 +275,127 @@
 	(*argvp)[1] = NULL;
 }
 
+static void
+odformat(const char *fmt)
+{
+	size_t size;
+	unsigned long long n;
+	int digits;
+	char *hdfmt, fchar, *end;
+
+	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':
+			size = sizeof(int);
+			switch (*fmt) {
+			case 'C':
+				size = sizeof(char);
+				fmt++;
+				break;
+			case 'I':
+				size = sizeof(int);
+				fmt++;
+				break;
+			case 'L':
+				size = sizeof(long);
+				fmt++;
+				break;
+			case 'S':
+				size = sizeof(short);
+				fmt++;
+				break;
+			default:
+				if (isdigit(*fmt)) {
+					errno = 0;
+					size = strtol(fmt, &end, 10);
+					if (errno != 0 || size <= 0)
+						errx(1, "bad size");
+					if (size != sizeof(char) &&
+					    size != sizeof(short) &&
+					    size != sizeof(int) &&
+					    size != sizeof(long))
+						errx(1,
+						    "unsupported int size %ld",
+						    size);
+					fmt = (const char *)end;
+				}
+			}
+			n = (1ULL << (8 * size)) - 1;
+			digits = 0;
+			while (n != 0) {
+				digits++;
+				n >>= (fchar == 'o' || fchar == 'd') ? 3 : 4;
+			}
+			asprintf(&hdfmt, "%d/%d \"%%%s%d%c \" \"\\n\"",
+			    16 / size, size, fchar == 'd' ? "" : "0",
+			    digits, fchar);
+			if (hdfmt == NULL)
+				err(1, NULL);
+			odadd(hdfmt);
+			free(hdfmt);
+			break;
+		case 'f':
+			size = sizeof(double);
+			switch (*fmt) {
+			case 'F':
+				size = sizeof(float);
+				fmt++;
+				break;
+			case 'D':
+				size = sizeof(double);
+				fmt++;
+				break;
+			case 'L':
+				size = sizeof(long double);
+				fmt++;
+				break;
+			default:
+				if (isdigit(*fmt)) {
+					errno = 0;
+					size = strtol(fmt, &end, 10);
+					if (errno != 0 || size <= 0)
+						errx(1, "bad size");
+					fmt = (const char *)end;
+				}
+			}
+			switch (size) {
+			case sizeof(float):
+				odadd("4/4 \" %14.7e \" \"\\n\"");
+				break;
+			case sizeof(double):
+				odadd("2/8 \" %21.14e \" \"\\n\"");
+				break;
+			case sizeof(long double):
+#ifdef notyet
+				odadd("1/16 \" %21.14Le \" \"\\n\"");
+				break;
+#endif
+			default:
+				errx(1, "unsupported FP size %ld", size);
+			}
+			break;
+		default:
+			errx(1, "%s: bad format", fmt);
+		}
+	}
+}
+
 static void
-odprecede()
+odadd(const char *fmt)
 {
-	static int first = 1;
+	static int needpad;
 
-	if (first) {
-		first = 0;
-		add("\"%07.7_Ao\n\"");
-		add("\"%07.7_ao  \"");
-	} else
-		add("\"         \"");
+	if (needpad)
+		add("\""PADDING"\"");
+	add(fmt);
+	needpad = 1;
 }
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-standards" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200204051113.g35BDdRZ002185>