From c9d500e9fdae9c4d8537385dc0d1de54a90b34a3 Mon Sep 17 00:00:00 2001 From: Arun Thomas Date: Sat, 21 Aug 2010 13:24:09 +0000 Subject: [PATCH] Import hexdump(1) from NetBSD --- commands/Makefile | 5 + commands/hexdump/Makefile | 15 + commands/hexdump/conv.c | 134 +++++++++ commands/hexdump/display.c | 362 +++++++++++++++++++++++ commands/hexdump/hexdump.1 | 325 +++++++++++++++++++++ commands/hexdump/hexdump.c | 92 ++++++ commands/hexdump/hexdump.h | 101 +++++++ commands/hexdump/hexsyntax.c | 140 +++++++++ commands/hexdump/od.1 | 303 +++++++++++++++++++ commands/hexdump/odsyntax.c | 400 +++++++++++++++++++++++++ commands/hexdump/parse.c | 545 +++++++++++++++++++++++++++++++++++ 11 files changed, 2422 insertions(+) create mode 100644 commands/hexdump/Makefile create mode 100644 commands/hexdump/conv.c create mode 100644 commands/hexdump/display.c create mode 100644 commands/hexdump/hexdump.1 create mode 100644 commands/hexdump/hexdump.c create mode 100644 commands/hexdump/hexdump.h create mode 100644 commands/hexdump/hexsyntax.c create mode 100644 commands/hexdump/od.1 create mode 100644 commands/hexdump/odsyntax.c create mode 100644 commands/hexdump/parse.c diff --git a/commands/Makefile b/commands/Makefile index 883dbe8c4..4030cd652 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -41,4 +41,9 @@ SUBDIR+= atnormalize dosread fdisk loadfont \ SUBDIR+= acd asmconv gas2ack .endif +# Build only with clang and GCC +.if ${COMPILER_TYPE} == "gnu" +SUBDIR+= hexdump +.endif + .include diff --git a/commands/hexdump/Makefile b/commands/hexdump/Makefile new file mode 100644 index 000000000..2eec76245 --- /dev/null +++ b/commands/hexdump/Makefile @@ -0,0 +1,15 @@ +# $NetBSD: Makefile,v 1.13 2009/04/14 22:15:21 lukem Exp $ +# from: @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= hexdump +SRCS= conv.c display.c hexdump.c hexsyntax.c odsyntax.c parse.c +MAN= hexdump.1 #od.1 + +.ifndef HOSTPROG +LDADD+=-lutil +DPADD+=${LIBUTIL} + +#LINKS= ${BINDIR}/hexdump ${BINDIR}/od +.endif + +.include diff --git a/commands/hexdump/conv.c b/commands/hexdump/conv.c new file mode 100644 index 000000000..8376c0dfc --- /dev/null +++ b/commands/hexdump/conv.c @@ -0,0 +1,134 @@ +/* $NetBSD: conv.c,v 1.13 2010/02/09 14:06:37 drochner Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if 0 +#if !defined(lint) +#if 0 +static char sccsid[] = "@(#)conv.c 8.1 (Berkeley) 6/6/93"; +#else +__RCSID("$NetBSD: conv.c,v 1.13 2010/02/09 14:06:37 drochner Exp $"); +#endif +#endif /* not lint */ +#endif + +#include + +#include +#include + +#include "hexdump.h" + +void +conv_c(PR *pr, u_char *p) +{ + char buf[10]; + char const *str; + + switch(*p) { + case '\0': + str = "\\0"; + goto strpr; + /* case '\a': */ + case '\007': + if (odmode) /* od doesn't know about \a */ + break; + str = "\\a"; + goto strpr; + case '\b': + str = "\\b"; + goto strpr; + case '\f': + str = "\\f"; + goto strpr; + case '\n': + str = "\\n"; + goto strpr; + case '\r': + str = "\\r"; + goto strpr; + case '\t': + str = "\\t"; + goto strpr; + case '\v': + if (odmode) + break; + str = "\\v"; + goto strpr; + default: + break; + } + if (isprint(*p)) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, *p); + } else { + (void)sprintf(buf, "%03o", (int)*p); + str = buf; +strpr: *pr->cchar = 's'; + (void)printf(pr->fmt, str); + } +} + +void +conv_u(PR *pr, u_char *p) +{ + static const char *list[] = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs", "ht", "lf", "vt", "ff", "cr", "so", "si", + "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us", + }; + + /* od used nl, not lf */ + if (*p <= 0x1f) { + *pr->cchar = 's'; + 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 (odmode && *p == 0x20) { /* od replaces space with sp */ + *pr->cchar = 's'; + (void)printf(pr->fmt, " sp"); + } else if (isprint(*p)) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, *p); + } else { + *pr->cchar = 'x'; + (void)printf(pr->fmt, (int)*p); + } +} diff --git a/commands/hexdump/display.c b/commands/hexdump/display.c new file mode 100644 index 000000000..54832f89b --- /dev/null +++ b/commands/hexdump/display.c @@ -0,0 +1,362 @@ +/* $NetBSD: display.c,v 1.21 2009/01/18 21:34:32 apb Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if 0 +#if !defined(lint) +#if 0 +static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93"; +#else +__RCSID("$NetBSD: display.c,v 1.21 2009/01/18 21:34:32 apb Exp $"); +#endif +#endif /* not lint */ +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hexdump.h" + +enum _vflag vflag = FIRST; + +static off_t address; /* address/offset in stream */ +static off_t eaddress; /* end address */ + +static inline void print(PR *, u_char *); + +void +display(void) +{ + FS *fs; + FU *fu; + PR *pr; + int cnt; + u_char *bp; + off_t saveaddress; + u_char savech, *savebp; + + savech = 0; + while ((bp = get()) != NULL) + for (fs = fshead, savebp = bp, saveaddress = address; fs; + fs = fs->nextfs, bp = savebp, address = saveaddress) + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->flags&F_IGNORE) + break; + for (cnt = fu->reps; cnt; --cnt) + for (pr = fu->nextpr; pr; address += pr->bcnt, + bp += pr->bcnt, pr = pr->nextpr) { + if (eaddress && address >= eaddress && + !(pr->flags & (F_TEXT|F_BPAD))) + bpad(pr); + if (cnt == 1 && pr->nospace) { + savech = *pr->nospace; + *pr->nospace = '\0'; + } + print(pr, bp); + if (cnt == 1 && pr->nospace) + *pr->nospace = savech; + } + } + if (endfu) { + /* + * If eaddress not set, error or file size was multiple of + * blocksize, and no partial block ever found. + */ + if (!eaddress) { + if (!address) + return; + eaddress = address; + } + for (pr = endfu->nextpr; pr; pr = pr->nextpr) + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (int64_t)eaddress); + break; + case F_TEXT: + (void)printf("%s", pr->fmt); + break; + } + } +} + +static inline void +print(PR *pr, u_char *bp) +{ + double f8; + float f4; + int16_t s2; + int32_t s4; + int64_t s8; + uint16_t u2; + uint32_t u4; + uint64_t u8; + + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (int64_t)address); + break; + case F_BPAD: + (void)printf(pr->fmt, ""); + break; + case F_C: + conv_c(pr, bp); + break; + case F_CHAR: + (void)printf(pr->fmt, *bp); + break; + case F_DBL: + switch(pr->bcnt) { + case 4: + memmove(&f4, bp, sizeof(f4)); + (void)printf(pr->fmt, f4); + break; + case 8: + memmove(&f8, bp, sizeof(f8)); + (void)printf(pr->fmt, f8); + break; + } + break; + case F_INT: + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (int64_t)*bp); + break; + case 2: + memmove(&s2, bp, sizeof(s2)); + (void)printf(pr->fmt, (int64_t)s2); + break; + case 4: + memmove(&s4, bp, sizeof(s4)); + (void)printf(pr->fmt, (int64_t)s4); + break; + case 8: + memmove(&s8, bp, sizeof(s8)); + (void)printf(pr->fmt, (int64_t)s8); + break; + } + break; + case F_P: + (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); + break; + case F_STR: + (void)printf(pr->fmt, (char *)bp); + break; + case F_TEXT: + (void)printf("%s", pr->fmt); + break; + case F_U: + conv_u(pr, bp); + break; + case F_UINT: + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (uint64_t)*bp); + break; + case 2: + memmove(&u2, bp, sizeof(u2)); + (void)printf(pr->fmt, (uint64_t)u2); + break; + case 4: + memmove(&u4, bp, sizeof(u4)); + (void)printf(pr->fmt, (uint64_t)u4); + break; + case 8: + memmove(&u8, bp, sizeof(u8)); + (void)printf(pr->fmt, (uint64_t)u8); + break; + } + break; + } +} + +void +bpad(PR *pr) +{ + static const char *spec = " -0+#"; + char *p1, *p2; + + /* + * Remove all conversion flags; '-' is the only one valid + * with %s, and it's not useful here. + */ + pr->flags = F_BPAD; + pr->cchar[0] = 's'; + pr->cchar[1] = '\0'; + for (p1 = pr->fmt; *p1 != '%'; ++p1); + for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1); + while ((*p2++ = *p1++) != '\0'); +} + +static char **_argv; + +u_char * +get(void) +{ + static int ateof = 1; + static u_char *curp, *savp; + int n; + int need, nread; + u_char *tmpp; + + if (!curp) { + curp = ecalloc(blocksize, 1); + savp = ecalloc(blocksize, 1); + } else { + tmpp = curp; + curp = savp; + savp = tmpp; + address += blocksize; + } + for (need = blocksize, nread = 0;;) { + /* + * if read the right number of bytes, or at EOF for one file, + * and no other files are available, zero-pad the rest of the + * block and set the end flag. + */ + if (!length || (ateof && !next(NULL))) { + if (need == blocksize) + return(NULL); + if (!need && vflag != ALL && + !memcmp(curp, savp, nread)) { + if (vflag != DUP) + (void)printf("*\n"); + return(NULL); + } + memset((char *)curp + nread, 0, need); + eaddress = address + nread; + return(curp); + } + n = fread((char *)curp + nread, sizeof(u_char), + length == -1 ? need : MIN(length, need), stdin); + if (!n) { + if (ferror(stdin)) + warn("%s", _argv[-1]); + ateof = 1; + continue; + } + ateof = 0; + if (length != -1) + length -= n; + if (!(need -= n)) { + if (vflag == ALL || vflag == FIRST || + memcmp(curp, savp, blocksize)) { + if (vflag == DUP || vflag == FIRST) + vflag = WAIT; + return(curp); + } + if (vflag == WAIT) + (void)printf("*\n"); + vflag = DUP; + address += blocksize; + need = blocksize; + nread = 0; + } + else + nread += n; + } +} + +int +next(char **argv) +{ + static int done; + int statok; + + if (argv) { + _argv = argv; + return(1); + } + for (;;) { + if (*_argv) { + if (!(freopen(*_argv, "r", stdin))) { + warn("%s", *_argv); + exitval = 1; + ++_argv; + continue; + } + statok = done = 1; + } else { + if (done++) + return(0); + statok = 0; + } + if (skip) + doskip(statok ? *_argv : "stdin", statok); + if (*_argv) + ++_argv; + if (!skip) + return(1); + } + /* NOTREACHED */ +} + +void +doskip(const char *fname, int statok) +{ + int cnt; + struct stat sb; + + if (statok) { + if (fstat(fileno(stdin), &sb)) + err(1, "fstat %s", fname); + if (S_ISREG(sb.st_mode) && skip >= sb.st_size) { + address += sb.st_size; + skip -= sb.st_size; + return; + } + } + if (S_ISREG(sb.st_mode)) { + if (fseek(stdin, skip, SEEK_SET)) + err(1, "fseek %s", fname); + address += skip; + skip = 0; + } else { + for (cnt = 0; cnt < skip; ++cnt) + if (getchar() == EOF) + break; + address += cnt; + skip -= cnt; + } +} diff --git a/commands/hexdump/hexdump.1 b/commands/hexdump/hexdump.1 new file mode 100644 index 000000000..b415bddf2 --- /dev/null +++ b/commands/hexdump/hexdump.1 @@ -0,0 +1,325 @@ +.\" $NetBSD: hexdump.1,v 1.20 2010/02/27 10:45:23 mbalmer Exp $ +.\" +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)hexdump.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd February 27, 2010 +.Dt HEXDUMP 1 +.Os +.Sh NAME +.Nm hexdump +.Nd ascii, decimal, hexadecimal, octal dump +.Sh SYNOPSIS +.Nm +.Op Fl bcCdovx +.Bk -words +.Op Fl e Ar format_string +.Ek +.Bk -words +.Op Fl f Ar format_file +.Ek +.Bk -words +.Op Fl n Ar length +.Ek +.Bk -words +.Op Fl s Ar skip +.Ek +.Ar file ... +.Sh DESCRIPTION +The hexdump utility is a filter which displays the specified files, or +the standard input, if no files are specified, in a user specified +format. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl b +.Em One-byte octal display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, three column, zero-filled, bytes of input data, +in octal, per line. +.It Fl c +.Em One-byte character display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, three column, space-filled, characters of input +data per line. +.It Fl C +.Em Canonical hex+ASCII display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, two column, hexadecimal bytes, followed by the +same sixteen bytes in %_p format enclosed in ``|'' characters. +.It Fl d +.Em Two-byte decimal display . +Display the input offset in hexadecimal, followed by eight +space-separated, five column, zero-filled, two-byte units +of input data, in unsigned decimal, per line. +.It Fl e Ar format_string +Specify a format string to be used for displaying data. +.It Fl f Ar format_file +Specify a file that contains one or more newline separated format strings. +Empty lines and lines whose first non-blank character is a hash mark +.Pf ( Cm \&# ) +are ignored. +.It Fl n Ar length +Interpret only +.Ar length +bytes of input. +.It Fl o +.Em Two-byte octal display . +Display the input offset in hexadecimal, followed by eight +space-separated, six column, zero-filled, two byte quantities of +input data, in octal, per line. +.It Fl s Ar offset +Skip +.Ar offset +bytes from the beginning of the input. +By default, +.Ar offset +is interpreted as a decimal number. +With a leading +.Cm 0x +or +.Cm 0X , +.Ar offset +is interpreted as a hexadecimal number, +otherwise, with a leading +.Cm 0 , +.Ar offset +is interpreted as an octal number. +Appending the character +.Cm b , +.Cm k , +or +.Cm m +to +.Ar offset +causes it to be interpreted as a multiple of +.Li 512 , +.Li 1024 , +or +.Li 1048576 , +respectively. +.It Fl v +The +.Fl v +option causes hexdump to display all input data. +Without the +.Fl v +option, any number of groups of output lines, which would be +identical to the immediately preceding group of output lines (except +for the input offsets), are replaced with a line containing a +single asterisk. +.It Fl x +.Em Two-byte hexadecimal display . +Display the input offset in hexadecimal, followed by eight, space +separated, four column, zero-filled, two-byte quantities of input +data, in hexadecimal, per line. +.El +.Pp +For each input file, +.Nm +sequentially copies the input to standard output, transforming the +data according to the format strings specified by the +.Fl e +and +.Fl f +options, in the order that they were specified. +.Ss Formats +A format string contains any number of format units, separated by +whitespace. +A format unit contains up to three items: an iteration count, a byte +count, and a format. +.Pp +The iteration count is an optional positive integer, which defaults to +one. +Each format is applied iteration count times. +.Pp +The byte count is an optional positive integer. +If specified it defines the number of bytes to be interpreted by +each iteration of the format. +.Pp +If an iteration count and/or a byte count is specified, a single slash +must be placed after the iteration count and/or before the byte count +to disambiguate them. +Any whitespace before or after the slash is ignored. +.Pp +The format is required and must be surrounded by double quote +(" ") marks. +It is interpreted as a fprintf-style format string (see +.Xr fprintf 3 ) , +with the +following exceptions: +.Bl -bullet -offset indent +.It +An asterisk (*) may not be used as a field width or precision. +.It +A byte count or field precision +.Em is +required for each ``s'' conversion +character (unlike the +.Xr fprintf 3 +default which prints the entire string if the precision is unspecified). +.It +The conversion characters ``h'', ``l'', ``n'', ``p'' and ``q'' are +not supported. +.It +The single character escape sequences +described in the C standard are supported: +.Bd -ragged -offset indent -compact +.Bl -column \*[Lt]alert_character\*[Gt] +.It NUL \e0 +.It \*[Lt]alert character\*[Gt] \ea +.It \*[Lt]backspace\*[Gt] \eb +.It \*[Lt]form-feed\*[Gt] \ef +.It \*[Lt]newline\*[Gt] \en +.It \*[Lt]carriage return\*[Gt] \er +.It \*[Lt]tab\*[Gt] \et +.It \*[Lt]vertical tab\*[Gt] \ev +.El +.Ed +.El +.Pp +Hexdump also supports the following additional conversion strings: +.Bl -tag -width Fl +.It Cm \&_a Ns Op Cm dox +Display the input offset, cumulative across input files, of the +next byte to be displayed. +The appended characters +.Cm d , +.Cm o , +and +.Cm x +specify the display base +as decimal, octal or hexadecimal respectively. +.It Cm \&_A Ns Op Cm dox +Identical to the +.Cm \&_a +conversion string except that it is only performed +once, when all of the input data has been processed. +.It Cm \&_c +Output characters in the default character set. +Nonprinting characters are displayed in three character, zero-padded +octal, except for those representable by standard escape notation +(see above), +which are displayed as two character strings. +.It Cm _p +Output characters in the default character set. +Nonprinting characters are displayed as a single +.Dq Cm \&. . +.It Cm _u +Output US ASCII characters, with the exception that control characters are +displayed using the following, lower-case, names. +Characters greater than 0xff, hexadecimal, are displayed as hexadecimal +strings. +.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\ lf\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\t07F\ del +.El +.El +.Pp +The default and supported byte counts for the conversion characters +are as follows: +.Bl -tag -width "Xc,_Xc,_Xc,_Xc,_Xc,_Xc" -offset indent +.It Li \&%_c , \&%_p , \&%_u , \&%c +One byte counts only. +.It Li \&%d , \&%i , \&%o , \&%u , \&%X , \&%x +Four byte default, one, two, four and eight byte counts supported. +.It Li \&%E , \&%e , \&%f , \&%G , \&%g +Eight byte default, four byte counts supported. +.El +.Pp +The amount of data interpreted by each format string is the sum of the +data required by each format unit, which is the iteration count times the +byte count, or the iteration count times the number of bytes required by +the format if the byte count is not specified. +.Pp +The input is manipulated in ``blocks'', where a block is defined as the +largest amount of data specified by any format string. +Format strings interpreting less than an input block's worth of data, +whose last format unit both interprets some number of bytes and does +not have a specified iteration count, have the iteration count +incremented until the entire input block has been processed or there +is not enough data remaining in the block to satisfy the format string. +.Pp +If, either as a result of user specification or hexdump modifying +the iteration count as described above, an iteration count is +greater than one, no trailing whitespace characters are output +during the last iteration. +.Pp +It is an error to specify a byte count as well as multiple conversion +characters or strings unless all but one of the conversion characters +or strings is +.Cm \&_a +or +.Cm \&_A . +.Pp +If, as a result of the specification of the +.Fl n +option or end-of-file being reached, input data only partially +satisfies a format string, the input block is zero-padded sufficiently +to display all available data (i.e. any format units overlapping the +end of data will display some number of the zero bytes). +.Pp +Further output by such format strings is replaced by an equivalent +number of spaces. +An equivalent number of spaces is defined as the number of spaces +output by an +.Cm s +conversion character with the same field width +and precision as the original conversion character or conversion +string but with any +.Dq Li \&+ , +.Dq \&\ \& , +.Dq Li \&# +conversion flag characters +removed, and referencing a NULL string. +.Pp +If no format strings are specified, the default display is equivalent +to specifying the +.Fl x +option. +.Pp +.Nm +exits 0 on success and \*[Gt]0 if an error occurred. +.Sh EXAMPLES +Display the input in perusal format: +.Bd -literal -offset indent +"%06.6_ao " 12/1 "%3_u " +"\et\et" "%_p " +"\en" +.Ed +.Pp +Implement the \-x option: +.Bd -literal -offset indent +"%07.7_Ax\en" +"%07.7_ax " 8/2 "%04x " "\en" +.Ed diff --git a/commands/hexdump/hexdump.c b/commands/hexdump/hexdump.c new file mode 100644 index 000000000..8cbb274bb --- /dev/null +++ b/commands/hexdump/hexdump.c @@ -0,0 +1,92 @@ +/* $NetBSD: hexdump.c,v 1.15 2010/02/09 14:06:37 drochner Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if 0 +#if !defined(lint) +__COPYRIGHT("@(#) Copyright (c) 1989, 1993\ + The Regents of the University of California. All rights reserved."); +#if 0 +static char sccsid[] = "@(#)hexdump.c 8.1 (Berkeley) 6/6/93"; +#else +__RCSID("$NetBSD: hexdump.c,v 1.15 2010/02/09 14:06:37 drochner Exp $"); +#endif +#endif /* not lint */ +#endif + +#include + +#include +#include +#include +#include +#include + +#include "hexdump.h" + +FS *fshead; /* head of format strings */ +int blocksize; /* data block size */ +int exitval; /* final exit value */ +int length = -1; /* max bytes to read */ + +int main(int, char **); + +int +main(int argc, char *argv[]) +{ + FS *tfs; + char *p; + + setlocale(LC_ALL, ""); + + if (!(p = strrchr(argv[0], 'o')) || strcmp(p, "od")) + newsyntax(argc, &argv); + else + odsyntax(argc, &argv); + + /* figure out the data block size */ + for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) { + tfs->bcnt = size(tfs); + if (blocksize < tfs->bcnt) + blocksize = tfs->bcnt; + } + /* rewrite the rules, do syntax checking */ + for (tfs = fshead; tfs; tfs = tfs->nextfs) + rewrite(tfs); + + (void)next(argv); + display(); + exit(exitval); +} diff --git a/commands/hexdump/hexdump.h b/commands/hexdump/hexdump.h new file mode 100644 index 000000000..e3a086d97 --- /dev/null +++ b/commands/hexdump/hexdump.h @@ -0,0 +1,101 @@ +/* $NetBSD: hexdump.h,v 1.11 2010/02/09 14:06:37 drochner Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)hexdump.h 8.1 (Berkeley) 6/6/93 + */ + +typedef struct _pr { + struct _pr *nextpr; /* next print unit */ +#define F_ADDRESS 0x001 /* print offset */ +#define F_BPAD 0x002 /* blank pad */ +#define F_C 0x004 /* %_c */ +#define F_CHAR 0x008 /* %c */ +#define F_DBL 0x010 /* %[EefGf] */ +#define F_INT 0x020 /* %[di] */ +#define F_P 0x040 /* %_p */ +#define F_STR 0x080 /* %s */ +#define F_U 0x100 /* %_u */ +#define F_UINT 0x200 /* %[ouXx] */ +#define F_TEXT 0x400 /* no conversions */ + u_int flags; /* flag values */ + int bcnt; /* byte count */ + char *cchar; /* conversion character */ + char *fmt; /* printf format */ + char *nospace; /* no whitespace version */ +} PR; + +typedef struct _fu { + struct _fu *nextfu; /* next format unit */ + struct _pr *nextpr; /* next print unit */ +#define F_IGNORE 0x01 /* %_A */ +#define F_SETREP 0x02 /* rep count set, not default */ + u_int flags; /* flag values */ + int reps; /* repetition count */ + int bcnt; /* byte count */ + char *fmt; /* format string */ +} FU; + +typedef struct _fs { /* format strings */ + struct _fs *nextfs; /* linked list of format strings */ + struct _fu *nextfu; /* linked list of format units */ + int bcnt; +} FS; + +enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */ + +extern int blocksize; /* data block size */ +extern int odmode; /* od compatibility */ +extern FU *endfu; /* format at end-of-data */ +extern int exitval; /* final exit value */ +extern FS *fshead; /* head of format strings list */ +extern int length; /* max bytes to read */ +extern off_t skip; /* bytes to skip */ +extern enum _vflag vflag; + +void add(const char *); +void addfile(char *); +void badcnt(char *); +void badconv(char *); +void badfmt(const char *); +void badsfmt(void); +void bpad(PR *); +void conv_c(PR *, u_char *); +void conv_u(PR *, u_char *); +void display(void); +void doskip(const char *, int); +/*void err(const char *, ...);*/ +void escape(char *); +u_char *get(void); +void newsyntax(int, char ***); +int next(char **); +void odsyntax(int, char ***); +void rewrite(FS *); +int size(FS *); +void usage(void); diff --git a/commands/hexdump/hexsyntax.c b/commands/hexdump/hexsyntax.c new file mode 100644 index 000000000..7364f5d97 --- /dev/null +++ b/commands/hexdump/hexsyntax.c @@ -0,0 +1,140 @@ +/* $NetBSD: hexsyntax.c,v 1.13 2006/01/04 01:30:21 perry Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if 0 +#if !defined(lint) +#if 0 +static char sccsid[] = "@(#)hexsyntax.c 8.2 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: hexsyntax.c,v 1.13 2006/01/04 01:30:21 perry Exp $"); +#endif +#endif /* not lint */ +#endif + +#include + +#include +#include +#include +#include +#include + +#include "hexdump.h" + +off_t skip; /* bytes to skip */ + +void +newsyntax(int argc, char ***argvp) +{ + int ch; + char *p, **argv; + + argv = *argvp; + while ((ch = getopt(argc, argv, "bcCde:f:n:os:vx")) != -1) + switch (ch) { + case 'b': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 16/1 \"%03o \" \"\\n\""); + break; + case 'c': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\""); + break; + case 'C': + add("\"%08.8_Ax\n\""); + add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" "); + add("\" |\" 16/1 \"%_p\" \"|\\n\""); + break; + case 'd': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %05u \" \"\\n\""); + break; + case 'e': + add(optarg); + break; + case 'f': + addfile(optarg); + break; + case 'n': + if ((length = atoi(optarg)) < 0) + errx(1, "%s: bad length value", optarg); + break; + case 'o': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %06o \" \"\\n\""); + break; + case 's': + if ((skip = strtol(optarg, &p, 0)) < 0) + errx(1, "%s: bad skip value", optarg); + switch(*p) { + case 'b': + skip *= 512; + break; + case 'k': + skip *= 1024; + break; + case 'm': + skip *= 1048576; + break; + } + break; + case 'v': + vflag = ALL; + break; + case 'x': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %04x \" \"\\n\""); + break; + case '?': + usage(); + } + + if (!fshead) { + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\""); + } + + *argvp += optind; +} + +void +usage(void) +{ + (void)fprintf(stderr, +"hexdump: [-bcCdovx] [-e fmt] [-f fmt_file] [-n length] [-s skip] [file ...]\n" + ); + exit(1); +} diff --git a/commands/hexdump/od.1 b/commands/hexdump/od.1 new file mode 100644 index 000000000..a0fe654df --- /dev/null +++ b/commands/hexdump/od.1 @@ -0,0 +1,303 @@ +.\" $NetBSD: od.1,v 1.25 2010/02/09 14:25:39 wiz Exp $ +.\" +.\" Copyright (c) 2001 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Andrew Brown. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\"/ +.Dd February 9, 2010 +.Dt OD 1 +.Os +.Sh NAME +.Nm od +.Nd octal, decimal, hex, ascii dump +.Sh SYNOPSIS +.Nm +.Op Fl aBbcDdeFfHhIiLlOovXx +.Bk -words +.Op Fl A Ar base +.Op Fl j Ar skip +.Ek +.Bk -words +.Op Fl N Ar length +.Ek +.Bk -words +.Op Fl t Ar type_string +.Ek +.Sm off +.Oo +.Op Cm \&+ +.Li offset +.Op Cm \&. +.Op Cm Bb +.Sm on +.Oc +.Ar file ... +.Sh DESCRIPTION +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 +.Em One-byte character display . +Display the input offset in octal, followed by sixteen +space-separated, three column, space-filled, characters of input data +per line. +Control characters are printed as their names instead of as +C-style escapes. +.It Fl B +Same as +.Fl o . +.It Fl b +.Em One-byte octal display . +Display the input offset in octal, followed by sixteen +space-separated, three column, zero-filled, bytes of input data, in +octal, per line. +This is the default output style if no other is +selected. +.It Fl c +.Em One-byte character display . +Display the input offset in octal, followed by sixteen +space-separated, three column, space-filled, characters of input data +per line. +Control characters are printed at C-style escapes, or as +three octal digits, if no C escape exists for the character. +.It Fl d +.Em Two-byte decimal display . +Display the input offset in octal, followed by eight +space-separated, five column, zero-filled, two-byte units +of input data, in unsigned decimal, per line. +.It Fl e +.Em Eight-byte floating point display . +Display the input offset in octal, followed by two space-separated, +twenty-one column, space filled, eight byte units of input data, in +floating point, per line. +.It Fl F +Same as +.Fl e . +.It Fl f +.Em Four-byte floating point display . +Display the input offset in octal, followed by four space-separated, +14 column, space filled, four byte units of input data, in floating +point, per line. +.It Fl H +.Em Four-byte hex display . +Display the input offset in octal, followed by four space-separated, +eight column, zero filled, four byte units of input data, in hex, +per line. +.It Fl h +.Em Two-byte hex display . +Display the input offset in octal, followed by eight space-separated, +four column, zero filled, two byte units of input data, in hex, +per line. +.It Fl I +.Em Four-byte decimal display . +Display the input offset in octal, followed by four space-separated, +eleven column, space filled, four byte units of input data, in +decimal, per line. +.It Fl i +.Em Two-byte decimal display . +Display the input offset in octal, followed by eight space-separated, +six column, space filled, two-byte units of input data, in decimal, +per line. +.It Fl j Ar offset +Skip +.Ar offset +bytes from the beginning of the input. +By default, +.Ar offset +is interpreted as a decimal number. +With a leading +.Cm 0x +or +.Cm 0X , +.Ar offset +is interpreted as a hexadecimal number, +otherwise, with a leading +.Cm 0 , +.Ar offset +is interpreted as an octal number. +Appending the character +.Cm b , +.Cm k , +or +.Cm m +to +.Ar offset +causes it to be interpreted as a multiple of +.Li 512 , +.Li 1024 , +or +.Li 1048576 , +respectively. +.It Fl L +Same as +.Fl I . +.It Fl l +Same as +.Fl I . +.It Fl N Ar length +Interpret only +.Ar length +bytes of input. +.It Fl O +.Em Four-byte octal display . +Display the input offset in octal, followed by four +space-separated, eleven column, zero-filled, four-byte units +of input data, in octal, per line. +.It Fl o +.Em Two-byte octal display . +Display the input offset in octal, followed by eight +space-separated, six column, zero-filled, two-byte units +of input data, in octal, per line. +.It Fl t Ar type_string +Specify one or more output types. +The +.Em type_string +option-argument must be a string specifying the types to be used when +writing the input data. +The string must consist of the type specification characters: +.Pp +.Cm a +selects US-ASCII output, with control characters replaced with their +names instead of as C escape sequences. +See also the +.Cm _u +conversion provided by hexdump(1). +.Pp +.Cm c +selects a standard character based conversion. +See also the +.Cm _c +conversion provided by hexdump(1). +.Pp +.Cm f +selects the floating point output format. +This type character can be optionally followed by the characters +.Cm 4 +or +.Cm F +to specify four byte floating point output, or +.Cm 8 +or +.Cm L +to specify eight byte floating point output. +The default output format is eight byte floats. +See also the +.Cm e +conversion provided by hexdump(1). +.Pp +.Cm d , +.Cm o , +.Cm u , +or +.Cm x +select decimal, octal, unsigned decimal, or hex output respectively. +These types can optionally be followed by +.Cm C +to specify +.Em char Ns -sized +output, +.Cm S +to specify +.Em short Ns -sized +output, +.Cm I +to specify +.Em int Ns -sized +output, +.Cm L +to specify +.Em long Ns -sized +output, +.Cm 1 +to specify one-byte output, +.Cm 2 +to specify two-byte output, +.Cm 4 +to specify four-byte output, or +.Cm 8 +to specify eight-byte output. +The default output format is in four-byte quantities. +See also the +.Cm d , +.Cm o , +.Cm u , +and +.Cm x +conversions provided by hexdump(1). +.\"(a|c|f[FLD]?|[doux][C1S2I4L8]?)* +.It Fl v +The +.Fl v +option causes +.Nm +to display all input data. +Without the +.Fl v +option, any number of groups of output lines, which would be +identical to the immediately preceding group of output lines (except +for the input offsets), are replaced with a line comprised of a +single asterisk. +.It Fl X +Same as +.Fl H . +.It Fl x +Same as +.Fl h . +.El +.Pp +For each input file, +.Nm +sequentially copies the input to standard output, transforming the +data according to the options given. +If no options are specified, the +default display is equivalent to specifying the +.Fl o +option. +.Pp +.Nm +exits 0 on success and \*[Gt]0 if an error occurred. +.Sh SEE ALSO +.Xr hexdump 1 , +.Xr strings 1 +.Sh HISTORY +A +.Nm +command appears in +.At v1 . +.Pp +This man page was written in February 2001 by Andrew Brown, shortly +after he augmented the deprecated od syntax to include things he felt +had been missing for a long time. diff --git a/commands/hexdump/odsyntax.c b/commands/hexdump/odsyntax.c new file mode 100644 index 000000000..5ca9769e3 --- /dev/null +++ b/commands/hexdump/odsyntax.c @@ -0,0 +1,400 @@ +/* $NetBSD: odsyntax.c,v 1.26 2010/02/09 14:06:37 drochner Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if 0 +#if !defined(lint) +#if 0 +static char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: odsyntax.c,v 1.26 2010/02/09 14:06:37 drochner Exp $"); +#endif +#endif /* not lint */ +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include "hexdump.h" + +#define PADDING " " + +struct odformat { + char type; + int nbytes; + char const *format; + int minwidth; +}; + +struct odaddrformat { + char type; + char const *format1; + char const *format2; +}; + +int odmode; + +static void odoffset(int, char ***); +static void posixtypes(char const *); + +void +odsyntax(int argc, char ***argvp) +{ + static char empty[] = "", padding[] = PADDING; + int ch; + char *p, **argv; + +#define TYPE_OFFSET 7 + add("\"%07.7_Ao\n\""); + add("\"%07.7_ao \""); + + odmode = 1; + argv = *argvp; + while ((ch = getopt(argc, argv, + "A:aBbcDdeFfHhIij:LlN:Oot: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': + posixtypes("a"); + break; + case 'B': + case 'o': + posixtypes("o2"); + break; + case 'b': + posixtypes("o1"); + break; + case 'c': + posixtypes("c"); + break; + case 'd': + posixtypes("u2"); + break; + case 'D': + posixtypes("u4"); + break; + case 'e': /* undocumented in od */ + case 'F': + posixtypes("f8"); + break; + case 'f': + posixtypes("f4"); + break; + case 'H': + case 'X': + posixtypes("x4"); + break; + case 'h': + case 'x': + posixtypes("x2"); + break; + case 'I': + case 'L': + case 'l': + posixtypes("d4"); + break; + case 'i': + posixtypes("d2"); + break; + case 'j': + if ((skip = strtol(optarg, &p, 0)) < 0) + errx(1, "%s: bad skip value", optarg); + switch(*p) { + case 'b': + skip *= 512; + break; + case 'k': + skip *= 1024; + break; + case 'm': + skip *= 1048576; + break; + } + break; + case 'N': + if ((length = atoi(optarg)) < 0) + errx(1, "%s: bad length value", optarg); + break; + case 'O': + posixtypes("o4"); + break; + case 't': + posixtypes(optarg); + break; + case 'v': + vflag = ALL; + break; + case '?': + default: + usage(); + } + + if (fshead->nextfs->nextfs == NULL) + posixtypes("oS"); + + argc -= optind; + *argvp += optind; + + if (argc) + odoffset(argc, argvp); +} + +/* formats used for -t */ + +static const struct odformat odftab[] = { + { 'a', 1, "%3_u", 4 }, + { 'c', 1, "%3_c", 4 }, + { 'd', 1, "%4d", 5 }, + { 'd', 2, "%6d", 6 }, + { 'd', 4, "%11d", 11 }, + { 'd', 8, "%20d", 20 }, + { 'o', 1, "%03o", 4 }, + { 'o', 2, "%06o", 7 }, + { 'o', 4, "%011o", 12 }, + { 'o', 8, "%022o", 23 }, + { 'u', 1, "%03u" , 4 }, + { 'u', 2, "%05u" , 6 }, + { 'u', 4, "%010u", 11 }, + { 'u', 8, "%020u", 21 }, + { 'x', 1, "%02x", 3 }, + { 'x', 2, "%04x", 5 }, + { 'x', 4, "%08x", 9 }, + { 'x', 8, "%016x", 17 }, + { 'f', 4, "%14.7e", 15 }, + { 'f', 8, "%21.14e", 22 }, + { 0, 0, NULL, 0 } +}; + +/* + * Interpret a POSIX-style -t argument. + */ +static void +posixtypes(char const *type_string) +{ + int nbytes = 0; + char *fmt, type, *tmp; + struct odformat const *odf; + + while (*type_string) { + switch ((type = *type_string++)) { + case 'a': + case 'c': + nbytes = 1; + break; + case 'f': + if (isupper((unsigned char)*type_string)) { + switch(*type_string) { + case 'F': + nbytes = sizeof(float); + break; + case 'D': + nbytes = sizeof(double); + break; + case 'L': + nbytes = sizeof(long double); + break; + default: + warnx("Bad type-size qualifier '%c'", + *type_string); + usage(); + } + type_string++; + } else if (isdigit((unsigned char)*type_string)) { + nbytes = strtol(type_string, &tmp, 10); + type_string = tmp; + } else + nbytes = 8; + break; + case 'd': + case 'o': + case 'u': + case 'x': + if (isupper((unsigned char)*type_string)) { + switch(*type_string) { + case 'C': + nbytes = sizeof(char); + break; + case 'S': + nbytes = sizeof(short); + break; + case 'I': + nbytes = sizeof(int); + break; + case 'L': + nbytes = sizeof(long); + break; + default: + warnx("Bad type-size qualifier '%c'", + *type_string); + usage(); + } + type_string++; + } else if (isdigit((unsigned char)*type_string)) { + nbytes = strtol(type_string, &tmp, 10); + type_string = tmp; + } else + nbytes = 4; + break; + default: + usage(); + } + for (odf = odftab; odf->type != 0; odf++) + if (odf->type == type && odf->nbytes == nbytes) + break; + if (odf->type == 0) + errx(1, "%c%d: format not supported", type, nbytes); + (void)easprintf(&fmt, "%d/%d \"%*s%s \" \"\\n\"", + 16 / nbytes, nbytes, + 4 * nbytes - odf->minwidth, "", odf->format); + add(fmt); + } +} + +static void +odoffset(int argc, char ***argvp) +{ + char *num, *p; + int base; + char *end; + + /* + * The offset syntax of od(1) was genuinely bizarre. First, if + * it started with a plus it had to be an offset. Otherwise, if + * there were at least two arguments, a number or lower-case 'x' + * followed by a number makes it an offset. By default it was + * octal; if it started with 'x' or '0x' it was hex. If it ended + * in a '.', it was decimal. If a 'b' or 'B' was appended, it + * multiplied the number by 512 or 1024 byte units. There was + * no way to assign a block count to a hex offset. + * + * We assume it's a file if the offset is bad. + */ + p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; + if (!p) + return; + + if (*p != '+' && (argc < 2 || + (!isdigit((unsigned char)p[0]) && + (p[0] != 'x' || !isxdigit((unsigned char)p[1]))))) + return; + + base = 0; + /* + * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and + * set base. + */ + if (p[0] == '+') + ++p; + if (p[0] == 'x' && isxdigit((unsigned char)p[1])) { + ++p; + base = 16; + } else if (p[0] == '0' && p[1] == 'x') { + p += 2; + base = 16; + } + + /* skip over the number */ + if (base == 16) + for (num = p; isxdigit((unsigned char)*p); ++p); + else + for (num = p; isdigit((unsigned char)*p); ++p); + + /* check for no number */ + if (num == p) + return; + + /* if terminates with a '.', base is decimal */ + if (*p == '.') { + if (base) + return; + base = 10; + } + + skip = strtol(num, &end, base ? base : 8); + + /* if end isn't the same as p, we got a non-octal digit */ + if (end != p) { + skip = 0; + return; + } + + if (*p) { + if (*p == 'B') { + skip *= 1024; + ++p; + } else if (*p == 'b') { + skip *= 512; + ++p; + } + } + if (*p) { + skip = 0; + return; + } + /* + * 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. + */ + if (base == 16) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; + } else if (base == 10) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; + } + + /* Terminate file list. */ + (*argvp)[1] = NULL; +} diff --git a/commands/hexdump/parse.c b/commands/hexdump/parse.c new file mode 100644 index 000000000..cc786f909 --- /dev/null +++ b/commands/hexdump/parse.c @@ -0,0 +1,545 @@ +/* $NetBSD: parse.c,v 1.26 2009/01/18 21:34:32 apb Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if 0 +#if !defined(lint) +#if 0 +static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; +#else +__RCSID("$NetBSD: parse.c,v 1.26 2009/01/18 21:34:32 apb Exp $"); +#endif +#endif /* not lint */ +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hexdump.h" + +FU *endfu; /* format at end-of-data */ + +void +addfile(char *name) +{ + char *p; + FILE *fp; + int ch; + char buf[2048 + 1]; + + if ((fp = fopen(name, "r")) == NULL) + err(1, "fopen %s", name); + while (fgets(buf, sizeof(buf), fp)) { + if (!(p = strchr(buf, '\n'))) { + warnx("line too long."); + while ((ch = getchar()) != '\n' && ch != EOF); + continue; + } + *p = '\0'; + for (p = buf; *p && isspace((unsigned char)*p); ++p); + if (!*p || *p == '#') + continue; + add(p); + } + (void)fclose(fp); +} + +void +add(const char *fmt) +{ + const char *p; + static FS **nextfs; + FS *tfs; + FU *tfu, **nextfu; + const char *savep; + + /* start new linked list of format units */ + tfs = ecalloc(1, sizeof(FS)); + if (!fshead) + fshead = tfs; + else + *nextfs = tfs; + nextfs = &tfs->nextfs; + nextfu = &tfs->nextfu; + + /* take the format string and break it up into format units */ + for (p = fmt;;) { + /* skip leading white space */ + for (; isspace((unsigned char)*p); ++p); + if (!*p) + break; + + /* allocate a new format unit and link it in */ + tfu = ecalloc(1, sizeof(FU)); + *nextfu = tfu; + nextfu = &tfu->nextfu; + tfu->reps = 1; + + /* if leading digit, repetition count */ + if (isdigit((unsigned char)*p)) { + for (savep = p; isdigit((unsigned char)*p); ++p); + if (!isspace((unsigned char)*p) && *p != '/') + badfmt(fmt); + /* may overwrite either white space or slash */ + tfu->reps = atoi(savep); + tfu->flags = F_SETREP; + /* skip trailing white space */ + for (++p; isspace((unsigned char)*p); ++p); + } + + /* skip slash and trailing white space */ + if (*p == '/') + while (isspace((unsigned char)*++p)); + + /* byte count */ + if (isdigit((unsigned char)*p)) { + for (savep = p; isdigit((unsigned char)*p); ++p); + if (!isspace((unsigned char)*p)) + badfmt(fmt); + tfu->bcnt = atoi(savep); + /* skip trailing white space */ + for (++p; isspace((unsigned char)*p); ++p); + } + + /* format */ + if (*p != '"') + badfmt(fmt); + for (savep = ++p; *p != '"';) + if (*p++ == 0) + badfmt(fmt); + tfu->fmt = emalloc(p - savep + 1); + (void) strncpy(tfu->fmt, savep, p - savep); + tfu->fmt[p - savep] = '\0'; + escape(tfu->fmt); + p++; + } +} + +static const char *spec = ".#-+ 0123456789"; + +int +size(FS *fs) +{ + FU *fu; + int bcnt, cursize; + char *fmt; + int prec; + + /* figure out the data block size needed for each format unit */ + for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->bcnt) { + cursize += fu->bcnt * fu->reps; + continue; + } + for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { + if (*fmt != '%') + continue; + /* + * skip any special chars -- save precision in + * case it's a %s format. + */ + while (strchr(spec + 1, *++fmt)); + if (*fmt == '.' && isdigit((unsigned char)*++fmt)) { + prec = atoi(fmt); + while (isdigit((unsigned char)*++fmt)); + } + switch(*fmt) { + case 'c': + bcnt += 1; + break; + case 'd': case 'i': case 'o': case 'u': + case 'x': case 'X': + bcnt += 4; + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + bcnt += 8; + break; + case 's': + bcnt += prec; + break; + case '_': + switch(*++fmt) { + case 'c': case 'p': case 'u': + bcnt += 1; + break; + } + } + } + cursize += bcnt * fu->reps; + } + return (cursize); +} + +void +rewrite(FS *fs) +{ + enum { NOTOKAY, USEBCNT, USEPREC } sokay; + PR *pr, **nextpr; + FU *fu; + char *p1, *p2; + char savech, *fmtp, cs[sizeof(PRId64)]; + int nconv, prec; + + prec = 0; + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + /* + * Break each format unit into print units; each conversion + * character gets its own. + */ + nextpr = &fu->nextpr; + for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { + pr = ecalloc(1, sizeof(*pr)); + *nextpr = pr; + + /* Skip preceding text and up to the next % sign. */ + for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); + + /* Only text in the string. */ + if (!*p1) { + pr->fmt = fmtp; + pr->flags = F_TEXT; + break; + } + + /* + * Get precision for %s -- if have a byte count, don't + * need it. + */ + if (fu->bcnt) { + sokay = USEBCNT; + /* Skip to conversion character. */ + for (++p1; *p1 && strchr(spec, *p1); ++p1); + } else { + /* Skip any special chars, field width. */ + while (*++p1 && strchr(spec + 1, *p1)); + if (*p1 == '.' && + isdigit((unsigned char)*++p1)) { + sokay = USEPREC; + prec = atoi(p1); + while (isdigit((unsigned char)*++p1)) + continue; + } else + sokay = NOTOKAY; + } + + p2 = *p1 ? p1 + 1 : p1; /* Set end pointer. */ + cs[0] = *p1; /* Set conversion string. */ + cs[1] = '\0'; + + /* + * Figure out the byte count for each conversion; + * rewrite the format as necessary, set up blank- + * padding for end of data. + */ + switch(cs[0]) { + case 'c': + pr->flags = F_CHAR; + switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 'd': case 'i': + pr->flags = F_INT; + goto isint; + case 'o': case 'u': case 'x': case 'X': + pr->flags = F_UINT; +isint: + /* + * Regardless of pr->bcnt, all integer + * values are cast to [u]int64_t before + * being printed by display(). We + * therefore need to use PRI?64 as the + * format, where '?' could actually + * be any of [diouxX]. We make the + * assumption (not guaranteed by the + * C99 standard) that we can derive + * all the other PRI?64 values from + * PRId64 simply by changing the last + * character. For example, if PRId64 is + * "lld" or "qd", and cs[0] is 'o', then + * we end up with "llo" or "qo". + */ + savech = cs[0]; + strncpy(cs, PRId64, sizeof(PRId64) - 2); + cs[sizeof(PRId64) - 2] = savech; + cs[sizeof(PRId64) - 1] = '\0'; + switch(fu->bcnt) { + case 0: case 4: + pr->bcnt = 4; + break; + case 1: + pr->bcnt = 1; + break; + case 2: + pr->bcnt = 2; + break; + case 8: + pr->bcnt = 8; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + pr->flags = F_DBL; + switch(fu->bcnt) { + case 0: case 8: + pr->bcnt = 8; + break; + case 4: + pr->bcnt = 4; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 's': + pr->flags = F_STR; + switch(sokay) { + case NOTOKAY: + badsfmt(); + case USEBCNT: + pr->bcnt = fu->bcnt; + break; + case USEPREC: + pr->bcnt = prec; + break; + } + break; + case '_': + ++p2; + switch(p1[1]) { + case 'A': + endfu = fu; + fu->flags |= F_IGNORE; + /* FALLTHROUGH */ + case 'a': + pr->flags = F_ADDRESS; + ++p2; + switch(p1[2]) { + case 'd': case 'o': case'x': + /* + * See comments above for + * the way we use PRId64. + */ + strncpy(cs, PRId64, + sizeof(PRId64) - 2); + cs[sizeof(PRId64) - 2] = p1[2]; + cs[sizeof(PRId64) - 1] = '\0'; + break; + default: + p1[3] = '\0'; + badconv(p1); + } + break; + case 'c': + pr->flags = F_C; + /* cs[0] = 'c'; set in conv_c */ + goto isint2; + case 'p': + pr->flags = F_P; + cs[0] = 'c'; + goto isint2; + case 'u': + pr->flags = F_U; + /* cs[0] = 'c'; set in conv_u */ +isint2: switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[2] = '\0'; + badcnt(p1); + } + break; + default: + p1[2] = '\0'; + badconv(p1); + } + break; + default: + p1[1] = '\0'; + badconv(p1); + } + + /* + * Copy to PR format string, set conversion character + * pointer, update original. + */ + savech = *p2; + p1[0] = '\0'; + pr->fmt = emalloc(strlen(fmtp) + strlen(cs) + 1); + (void)strcpy(pr->fmt, fmtp); + (void)strcat(pr->fmt, cs); + *p2 = savech; + pr->cchar = pr->fmt + (p1 - fmtp); + fmtp = p2; + + /* Only one conversion character if byte count. */ + if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) + errx(1, + "byte count with multiple conversion characters"); + } + /* + * If format unit byte count not specified, figure it out + * so can adjust rep count later. + */ + if (!fu->bcnt) + for (pr = fu->nextpr; pr; pr = pr->nextpr) + fu->bcnt += pr->bcnt; + } + /* + * If the format string interprets any data at all, and it's + * not the same as the blocksize, and its last format unit + * interprets any data at all, and has no iteration count, + * repeat it as necessary. + * + * If, rep count is greater than 1, no trailing whitespace + * gets output from the last iteration of the format unit. + */ + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + if (!fu->nextfu && fs->bcnt < blocksize && + !(fu->flags&F_SETREP) && fu->bcnt) + fu->reps += (blocksize - fs->bcnt) / fu->bcnt; + if (fu->reps > 1) { + if (!fu->nextpr) + break; + for (pr = fu->nextpr;; pr = pr->nextpr) + if (!pr->nextpr) + break; + for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) + p2 = isspace((unsigned char)*p1) ? p1 : NULL; + if (p2) + pr->nospace = p2; + } + } +#ifdef DEBUG + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + (void)printf("fmt:"); + for (pr = fu->nextpr; pr; pr = pr->nextpr) + (void)printf(" {%s}", pr->fmt); + (void)printf("\n"); + } +#endif +} + +void +escape(char *p1) +{ + char *p2; + + /* alphabetic escape sequences have to be done in place */ + for (p2 = p1;; ++p1, ++p2) { + if (!*p1) { + *p2 = *p1; + break; + } + if (*p1 == '\\') + switch(*++p1) { + case '\0': + *p2 = '\\'; + *++p2 = '\0'; + return; /* incomplete escape sequence */ + case 'a': + /* *p2 = '\a'; */ + *p2 = '\007'; + break; + case 'b': + *p2 = '\b'; + break; + case 'f': + *p2 = '\f'; + break; + case 'n': + *p2 = '\n'; + break; + case 'r': + *p2 = '\r'; + break; + case 't': + *p2 = '\t'; + break; + case 'v': + *p2 = '\v'; + break; + default: + *p2 = *p1; + break; + } + else + *p2 = *p1; + } +} + +void +badcnt(char *s) +{ + errx(1, "%s: bad byte count", s); +} + +void +badsfmt(void) +{ + errx(1, "%%s: requires a precision or a byte count"); +} + +void +badfmt(const char *fmt) +{ + errx(1, "\"%s\": bad format", fmt); +} + +void +badconv(char *ch) +{ + errx(1, "%%%s: bad conversion character", ch); +}