fatbase

portable OpenBSD tools
git clone git://git.2f30.org/fatbase.git
Log | Files | Refs

commit bf86ecbe9208f5f8b8007fe4e70c2e3777cbe365
parent 39ff613ae2a7e3a9a075035e039cf4b413203f02
Author: sin <sin@2f30.org>
Date:   Tue Nov 18 16:42:59 +0000

Add hexdump/od

Diffstat:
Makefile | 2+-
hexdump/Makefile | 10++++++++++
hexdump/conv.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/display.c | 366+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/fgetln.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/hexdump.1 | 374+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/hexdump.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/hexdump.h | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/hexsyntax.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/od.1 | 336+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/odsyntax.c | 412+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/parse.c | 527+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hexdump/util.h | 4++++
13 files changed, 2536 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile @@ -1,4 +1,4 @@ -TARG = awk sed +TARG = awk hexdump sed all: @echo "CFLAGS = $(CFLAGS)" diff --git a/hexdump/Makefile b/hexdump/Makefile @@ -0,0 +1,10 @@ +OBJ = conv.o display.o fgetln.o hexdump.o hexsyntax.o odsyntax.o parse.o +BIN = hexdump + +all: $(BIN) + +$(BIN): $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) + +clean: + rm -f $(BIN) $(OBJ) diff --git a/hexdump/conv.c b/hexdump/conv.c @@ -0,0 +1,120 @@ +/* $OpenBSD: conv.c,v 1.10 2014/04/19 09:28:20 sobrado Exp $ */ +/* $NetBSD: conv.c,v 1.7 2001/12/07 15:14:29 bjh21 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. + */ + +#include <sys/types.h> + +#include <stdio.h> +#include <ctype.h> + +#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 didn'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)snprintf(buf, sizeof 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", "dc1", "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 replaced 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/hexdump/display.c b/hexdump/display.c @@ -0,0 +1,366 @@ +/* $OpenBSD: display.c,v 1.20 2010/10/22 14:04:24 millert Exp $ */ +/* $NetBSD: display.c,v 1.12 2001/12/07 15:14:29 bjh21 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. + */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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, (quad_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; + u_int16_t u2; + u_int32_t u4; + u_int64_t u8; + + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (quad_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, (quad_t)*bp); + break; + case 2: + memmove(&s2, bp, sizeof(s2)); + (void)printf(pr->fmt, (quad_t)s2); + break; + case 4: + memmove(&s4, bp, sizeof(s4)); + (void)printf(pr->fmt, (quad_t)s4); + break; + case 8: + memmove(&s8, bp, sizeof(s8)); + (void)printf(pr->fmt, 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, (u_quad_t)*bp); + break; + case 2: + memmove(&u2, bp, sizeof(u2)); + (void)printf(pr->fmt, (u_quad_t)u2); + break; + case 4: + memmove(&u4, bp, sizeof(u4)); + (void)printf(pr->fmt, (u_quad_t)u4); + break; + case 8: + memmove(&u8, bp, sizeof(u8)); + (void)printf(pr->fmt, 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 = emalloc(blocksize); + savp = emalloc(blocksize); + } 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 = done = 1; + ++_argv; + continue; + } + statok = done = 1; + } else { + if (done++) + return(0); + statok = 0; + } + if (iobuf != NULL) + setvbuf(stdin, iobuf, _IOFBF, iobufsiz); + if (skip) + doskip(statok ? *_argv : "stdin", statok); + if (*_argv) + ++_argv; + if (!skip) + return(1); + } + /* NOTREACHED */ +} + +void +doskip(const char *fname, int statok) +{ + off_t cnt; + struct stat sb; + + if (statok) { + if (fstat(fileno(stdin), &sb)) + err(1, "fstat %s", fname); + if (S_ISREG(sb.st_mode)) { + if (skip >= sb.st_size) { + address += sb.st_size; + skip -= sb.st_size; + } else { + if (fseeko(stdin, skip, SEEK_SET)) + err(1, "fseeko %s", fname); + address += skip; + skip = 0; + } + return; + } + } + + for (cnt = 0; cnt < skip; ++cnt) + if (getchar() == EOF) + break; + address += cnt; + skip -= cnt; +} + +void * +emalloc(int allocsize) +{ + void *p; + + if ((p = malloc((u_int)allocsize)) == NULL) + nomem(); + memset(p, 0, allocsize); + return(p); +} + +void +nomem(void) +{ + err(1, NULL); +} diff --git a/hexdump/fgetln.c b/hexdump/fgetln.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2005 Hector Garcia Alvarez + * Copyright © 2005, 2008-2012 Guillem Jover <guillem@hadrons.org> + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + */ + +#include <stdio.h> +#include <sys/cdefs.h> +#include <sys/types.h> +#include <string.h> + +struct filebuf { + FILE *fp; + char *buf; + size_t len; +}; + +#define FILEBUF_POOL_ITEMS 32 + +static struct filebuf fb_pool[FILEBUF_POOL_ITEMS]; +static int fb_pool_cur; + +char * +fgetln(FILE *stream, size_t *len) +{ + struct filebuf *fb; + ssize_t nread; + + /* Try to diminish the possibility of several fgetln() calls being + * used on different streams, by using a pool of buffers per file. */ + fb = &fb_pool[fb_pool_cur]; + if (fb->fp != stream && fb->fp != NULL) { + fb_pool_cur++; + fb_pool_cur %= FILEBUF_POOL_ITEMS; + fb = &fb_pool[fb_pool_cur]; + } + fb->fp = stream; + + nread = getline(&fb->buf, &fb->len, stream); + /* Note: the getdelim/getline API ensures nread != 0. */ + if (nread == -1) { + *len = 0; + return NULL; + } else { + *len = (size_t)nread; + return fb->buf; + } +} diff --git a/hexdump/hexdump.1 b/hexdump/hexdump.1 @@ -0,0 +1,374 @@ +.\" $OpenBSD: hexdump.1,v 1.24 2011/05/06 18:11:43 otto Exp $ +.\" $NetBSD: hexdump.1,v 1.14 2001/12/07 14:46:24 bjh21 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 $Mdocdate: May 6 2011 $ +.Dt HEXDUMP 1 +.Os +.Sh NAME +.Nm hexdump +.Nd ascii, decimal, hexadecimal, octal dump +.Sh SYNOPSIS +.Nm hexdump +.Bk -words +.Op Fl bCcdovx +.Op Fl e Ar format_string +.Op Fl f Ar format_file +.Op Fl n Ar length +.Op Fl s Ar offset +.Op Ar +.Ek +.Sh DESCRIPTION +The +.Nm +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 Ds +.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 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 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 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 +.Pq Ql # +are ignored. +.It Fl n Ar length +Interpret only +.Ar length +bytes of input. +By default, +.Ar length +is interpreted as a decimal number. +With a leading +.Cm 0x +or +.Cm 0X , +.Ar length +is interpreted as a hexadecimal number, +otherwise, with a leading +.Cm 0 , +.Ar length +is interpreted as an octal number. +.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 comprised of a +single asterisk +.Pq Ql * . +.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 +.Pq Sq / +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 +.Pq \&"\& \&" +marks +(the quote mark is a special character in many shell programs, +and may have to be escaped from the shell). +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 +.Sq s +conversion character (unlike the +.Xr fprintf 3 +default which prints the entire string if the precision is unspecified). +.It +The conversion characters +.Sq h , +.Sq l , +.Sq n , +.Sq p , +and +.Sq q +are not supported. +.It +The single character escape sequences +described in the C standard are supported: +.Pp +.Bl -tag -width "Xalert characterXXX" -offset indent -compact +.It NUL +\e0 +.It Aq alert character +\ea +.It Aq backspace +\eb +.It Aq form-feed +\ef +.It Aq newline +\en +.It Aq carriage return +\er +.It Aq tab +\et +.It Aq vertical tab +\ev +.El +.El +.Pp +.Nm +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 dot +.Ql \&. . +.It Cm _u +Output US ASCII characters, with the exception that control characters are +displayed using the following, lower-case, names. +Other non-printable characters are displayed as hexadecimal strings. +.Bd -literal -offset 3n +000 nul 001 soh 002 stx 003 etx 004 eot 005 enq +006 ack 007 bel 008 bs 009 ht 00A lf 00B vt +00C ff 00D cr 00E so 00F si 010 dle 011 dc1 +012 dc2 013 dc3 014 dc4 015 nak 016 syn 017 etb +018 can 019 em 01A sub 01B esc 01C fs 01D gs +01E rs 01F us 07F del +.Ed +.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 Xo +.Li \&%d , \&%i , \&%o , +.Li \&%u , \&%X , \&%x +.Xc +Four byte default, one, two, four and eight byte counts supported. +.It Xo +.Li \&%E , \&%e , \&%f , +.Li \&%G , \&%g +.Xc +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 +.Dq 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 +.Ql + , +.Ql \&\ \& , +.Ql # +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. +.Sh EXIT STATUS +.Ex -std hexdump +.Sh EXAMPLES +Display characters using a fieldwidth of 4, +and using special names for control characters: +.Pp +.Dl $ hexdump -e '"%4_u"' file +.Pp +An example file for use with the +.Fl f +option, to display the input in perusal format: +.Bd -literal -offset indent +"%06.6_ao " 12/1 "%3_u " +"\et\et" "%_p " +"\en" +.Ed +.Pp +An example file for use with the +.Fl f +option, which implements the equivalent of the +.Fl x +option: +.Bd -literal -offset indent +"%07.7_Ax\en" +"%07.7_ax " 8/2 " %04x " "\en" +.Ed +.Sh SEE ALSO +.Xr od 1 diff --git a/hexdump/hexdump.c b/hexdump/hexdump.c @@ -0,0 +1,78 @@ +/* $OpenBSD: hexdump.c,v 1.16 2011/09/22 09:09:42 stsp Exp $ */ +/* $NetBSD: hexdump.c,v 1.7 1997/10/19 02:34:06 lukem 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. + */ + +#include <sys/param.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hexdump.h" + +FS *fshead; /* head of format strings */ +int blocksize; /* data block size */ +int exitval; /* final exit value */ +long length = -1; /* max bytes to read */ +char *iobuf; /* stdio I/O buffer */ +size_t iobufsiz; /* size of stdio I/O buffer */ + +int main(int, char **); + +int +main(int argc, char *argv[]) +{ + FS *tfs; + char *p; + + if (!(p = strrchr(argv[0], 'o')) || strcmp(p, "od")) + newsyntax(argc, &argv); + else + oldsyntax(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; + } + if (length != -1) { + iobufsiz = MIN(length, blocksize); + if ((iobuf = malloc(iobufsiz)) == NULL) + err(1, NULL); + } + /* rewrite the rules, do syntax checking */ + for (tfs = fshead; tfs; tfs = tfs->nextfs) + rewrite(tfs); + + (void)next(argv); + display(); + exit(exitval); +} diff --git a/hexdump/hexdump.h b/hexdump/hexdump.h @@ -0,0 +1,107 @@ +/* $OpenBSD: hexdump.h,v 1.10 2014/04/19 09:28:20 sobrado Exp $ */ +/* $NetBSD: hexdump.h,v 1.7 2001/12/07 15:14:29 bjh21 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 long length; /* max bytes to read */ +extern off_t skip; /* bytes to skip */ +extern char *iobuf; /* stdio I/O buffer */ +extern size_t iobufsiz; /* size of stdio I/O buffer */ +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 *emalloc(int); +void escape(char *); +u_char *get(void); +void newsyntax(int, char ***); +int next(char **); +void nomem(void); +void oldsyntax(int, char ***); +void rewrite(FS *); +int size(FS *); +void usage(void); +void oldusage(void); diff --git a/hexdump/hexsyntax.c b/hexdump/hexsyntax.c @@ -0,0 +1,132 @@ +/* $OpenBSD: hexsyntax.c,v 1.12 2011/05/06 15:46:29 otto Exp $ */ +/* $NetBSD: hexsyntax.c,v 1.8 1998/04/08 23:48:57 jeremy 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. + */ + +#include <sys/types.h> + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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': + errno = 0; + if ((length = strtol(optarg, NULL, 0)) < 0 || + errno != 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': + errno = 0; + if ((skip = (off_t)strtoll(optarg, &p, 0)) < 0 || + errno != 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) +{ + extern char *__progname; + fprintf(stderr, "usage: %s [-bCcdovx] [-e format_string] " + "[-f format_file] [-n length]\n" + "\t[-s offset] [file ...]\n", __progname); + exit(1); +} diff --git a/hexdump/od.1 b/hexdump/od.1 @@ -0,0 +1,336 @@ +.\" $OpenBSD: od.1,v 1.30 2014/04/19 09:24:28 sobrado Exp $ +.\" $NetBSD: od.1,v 1.16 2001/12/07 01:23:42 bjh21 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 $Mdocdate: April 19 2014 $ +.Dt OD 1 +.Os +.Sh NAME +.Nm od +.Nd octal, decimal, hex, ascii dump +.Sh SYNOPSIS +.Nm od +.Bk -words +.Op Fl aBbcDdeFfHhIiLlOosvXx +.Op Fl A Ar base +.Op Fl j Ar offset +.Op Fl N Ar length +.Op Fl t Ar type_string +.Sm off +.Oo +.Op Cm \&+ +.Li offset +.Op Cm \&. +.Op Cm Bb +.Sm on +.Oc +.Op Ar +.Ek +.Sh DESCRIPTION +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 +The options are as follows: +.Bl -tag -width Fl +.It Fl A Ar base +Specify the input address base. +The argument +.Ar base +may be one of +.Cm d , +.Cm o , +.Cm x , +or +.Cm 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 as c style escapes, or as three octal digits, +if no c escape exists for the character. +.It Fl D +.Em Four-byte octal display . +Display the input offset in octal, followed by four space-separated, +ten column, space filled, four-byte units of input data, in octal, per line. +.It Fl d +.Em Two-byte unsigned 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 s +.Em Two-byte signed decimal display . +Display the input offset in octal, followed by eight +space-separated, five column, zero-filled, two-byte units +of input data, in signed decimal, 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 +.Xr hexdump 1 . +.Pp +.Cm c +selects a standard character based conversion. +See also the +.Cm _c +conversion provided by +.Xr 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 +.Xr 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 +.Xr 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. +.Sh EXIT STATUS +.Ex -std od +.Sh SEE ALSO +.Xr hexdump 1 +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -p1003.1-2008 +specification. +.Pp +The flags +.Op Fl bcdosx +as well as the +.Ar offset +specifier are marked by +.St -p1003.1-2008 +as being an +X/Open System Interfaces +option. +.Pp +The flags +.Op Fl aBDeFfHhIiLlOX +are extensions to that specification. +.Sh HISTORY +An +.Nm +command appears in +.At v1 . +.Pp +This man page was written in February 2001 by Andrew Brown, shortly +after he augmented the +.Nm +syntax to include things he felt had been missing for a long time. diff --git a/hexdump/odsyntax.c b/hexdump/odsyntax.c @@ -0,0 +1,412 @@ +/* $OpenBSD: odsyntax.c,v 1.25 2014/04/19 09:28:20 sobrado Exp $ */ +/* $NetBSD: odsyntax.c,v 1.15 2001/12/07 15:14:29 bjh21 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. + */ + +#include <sys/types.h> + +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "hexdump.h" + +#define PADDING " " + +int odmode; + +static void odoffset(int, char ***); +static void posixtypes(char *); +static void odadd(const char *); + + +/* + * formats used for -t + */ +static const char *fmt[4][4] = { + { + "16/1 \"%3d \" \"\\n\"", + "8/2 \" %05d \" \"\\n\"", + "4/4 \" %010d \" \"\\n\"", + "2/8 \" %019d \" \"\\n\"" + }, { + "16/1 \"%03o \" \"\\n\"", + "8/2 \" %06o \" \"\\n\"", + "4/4 \" %011o\" \"\\n\"", + "2/8 \" %022o \" \"\\n\"" + }, { + "16/1 \"%03u \" \"\\n\"", + "8/2 \" %05u \" \"\\n\"", + "4/4 \" %010u \" \"\\n\"", + "2/8 \" %020u \" \"\\n\"" + }, { + "16/1 \" %02x \" \"\\n\"", + "8/2 \" %04x \" \"\\n\"", + "4/4 \" %08x \" \"\\n\"", + "2/8 \" %16x \" \"\\n\"" + } +}; + +void +oldsyntax(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: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': + odadd("16/1 \"%3_u \" \"\\n\""); + break; + case 'B': + case 'o': + odadd("8/2 \" %06o \" \"\\n\""); + break; + case 'b': + odadd("16/1 \"%03o \" \"\\n\""); + break; + case 'c': + odadd("16/1 \"%3_c \" \"\\n\""); + break; + case 'd': + odadd("8/2 \" %05u \" \"\\n\""); + break; + case 'D': + odadd("4/4 \" %010u \" \"\\n\""); + break; + case 'e': + case 'F': + odadd("2/8 \" %21.14e \" \"\\n\""); + break; + case 'f': + odadd("4/4 \" %14.7e \" \"\\n\""); + break; + case 'H': + case 'X': + odadd("4/4 \" %08x \" \"\\n\""); + break; + case 'h': + case 'x': + odadd("8/2 \" %04x \" \"\\n\""); + break; + case 'I': + case 'L': + case 'l': + odadd("4/4 \" %11d \" \"\\n\""); + break; + case 'i': + odadd("8/2 \" %6d \" \"\\n\""); + 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': + odadd("4/4 \" %011o \" \"\\n\""); + break; + case 's': + odadd("8/2 \" %05d \" \"\\n\""); + break; + case 't': + posixtypes(optarg); + break; + case 'v': + vflag = ALL; + break; + default: + oldusage(); + } + + if (fshead->nextfs->nextfs == NULL) + odadd(" 8/2 \"%06o \" \"\\n\""); + + argc -= optind; + *argvp += optind; + + if (argc) + odoffset(argc, argvp); +} + +/* + * Interpret a POSIX-style -t argument. + */ +static void +posixtypes(char *type_string) +{ + int x, y, nbytes; + + while (*type_string) { + switch (*type_string) { + case 'a': + type_string++; + odadd("16/1 \"%3_u \" \"\\n\""); + break; + case 'c': + type_string++; + odadd("16/1 \"%3_c \" \"\\n\""); + break; + case 'f': + type_string++; + if (*type_string == 'F' || + *type_string == '4') { + type_string++; + odadd("4/4 \" %14.7e\" \"\\n\""); + } else if (*type_string == 'L' || + *type_string == '8') { + type_string++; + odadd("2/8 \" %16.14e\" \"\\n\""); + } else if (*type_string == 'D') + /* long doubles vary in size */ + oldusage(); + else + odadd("2/8 \" %16.14e\" \"\\n\""); + break; + case 'd': + x = 0; + goto extensions; + case 'o': + x = 1; + goto extensions; + case 'u': + x = 2; + goto extensions; + case 'x': + x = 3; + extensions: + type_string++; + y = 2; + 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); + oldusage(); + } + type_string++; + } else if (isdigit((unsigned char)*type_string)) + nbytes = strtol(type_string, &type_string, 10); + else + nbytes = 4; + + switch (nbytes) { + case 1: + y = 0; + break; + case 2: + y = 1; + break; + case 4: + y = 2; + break; + case 8: + y = 3; + break; + default: + warnx("%d-byte integer formats are not " + "supported", nbytes); + oldusage(); + } + odadd(fmt[x][y]); + break; + default: + oldusage(); + } + } +} + +void +oldusage(void) +{ + extern char *__progname; + fprintf(stderr, "usage: %s [-aBbcDdeFfHhIiLlOosvXx] [-A base] " + "[-j offset] [-N length]\n" + "\t[-t type_string] [[+]offset[.][Bb]] [file ...]\n", __progname); + exit(1); +} + +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; +} + +static void +odadd(const char *fmt) +{ + static int needpad; + + if (needpad) + add("\""PADDING"\""); + add(fmt); + needpad = 1; +} diff --git a/hexdump/parse.c b/hexdump/parse.c @@ -0,0 +1,527 @@ +/* $OpenBSD: parse.c,v 1.17 2009/10/27 23:59:39 deraadt Exp $ */ +/* $NetBSD: parse.c,v 1.12 2001/12/07 13:37:39 bjh21 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. + */ + +#include <sys/types.h> +#include <sys/file.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "hexdump.h" +#include "util.h" + +FU *endfu; /* format at end-of-data */ + +void +addfile(char *name) +{ + FILE *fp; + size_t len; + char *buf, *lbuf, *p; + + if ((fp = fopen(name, "r")) == NULL) + err(1, "fopen %s", name); + + lbuf = NULL; + while ((buf = fgetln(fp, &len))) { + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + else { + /* EOF without EOL, copy and add the NUL */ + if ((lbuf = malloc(len + 1)) == NULL) + err(1, NULL); + memcpy(lbuf, buf, len); + lbuf[len] = '\0'; + buf = lbuf; + } + for (p = buf; isspace((unsigned char)*p); ++p); + if (!*p || *p == '#') + continue; + add(p); + } + free(lbuf); + (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 = emalloc(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 = emalloc(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); + if (!(tfu->fmt = malloc(p - savep + 1))) + nomem(); + (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 (*++fmt && 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[3]; + int nconv, prec; + size_t len; + + nextpr = NULL; + prec = 0; + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + /* + * Break each format unit into print units; each conversion + * character gets its own. + */ + for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { + pr = emalloc(sizeof(PR)); + if (!fu->nextpr) + fu->nextpr = pr; + else + *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': + case 'o': case 'u': case 'x': case 'X': + if (cs[0] == 'd' || cs[0] == 'i') + pr->flags = F_INT; + else + pr->flags = F_UINT; + + cs[2] = '\0'; + cs[1] = cs[0]; + cs[0] = 'q'; + 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': + cs[0] = 'q'; + cs[1] = p1[2]; + cs[2] = '\0'; + break; + default: + if (p1[2]) + p1[3] = '\0'; + badconv(p1); + } + break; + case 'c': + case 'p': + case 'u': + if (p1[1] == 'c') { + pr->flags = F_C; + /* cs[0] = 'c'; set in conv_c */ + } else if (p1[1] == 'p') { + pr->flags = F_P; + cs[0] = 'c'; + } else { + pr->flags = F_U; + /* cs[0] = 'c'; set in conv_u */ + } + + switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[2] = '\0'; + badcnt(p1); + } + break; + default: + if (p1[1]) + p1[2] = '\0'; + badconv(p1); + } + break; + default: + if (cs[0]) + p1[1] = '\0'; + badconv(p1); + } + + /* + * Copy to PR format string, set conversion character + * pointer, update original. + */ + savech = *p2; + p1[0] = '\0'; + len = strlen(fmtp) + strlen(cs) + 1; + pr->fmt = emalloc(len); + snprintf(pr->fmt, len, "%s%s", fmtp, 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); +} diff --git a/hexdump/util.h b/hexdump/util.h @@ -0,0 +1,4 @@ +#include <stdio.h> +#include <stddef.h> + +char *fgetln(FILE *, size_t *);