sbase

suckless unix tools
git clone git://git.2f30.org/sbase
Log | Files | Refs | README | LICENSE

commit fd0d1e4567c18c7314f2ccc0202b59431318ec31
parent 521c3734af06ce74e9535a542bdae7832c5c595a
Author: Greg Reagle <greg.reagle@umbc.edu>
Date:   Mon, 28 Sep 2015 21:02:17 -0400

Created od, with improvements suggested by FRIGN

Diffstat:
MLICENSE | 2+-
MMakefile | 1+
MREADME | 1+
MTODO | 1-
Aod.1 | 30++++++++++++++++++++++++++++++
Aod.c | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 210 insertions(+), 2 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -54,7 +54,7 @@ Authors/contributors include: © 2014 Ari Malinen <ari.malinen@gmail.com> © 2014 Brandon Mulcahy <brandon@jangler.info> © 2014 Adria Garriga <rhaps0dy@installgentoo.com> -© 2014 Greg Reagle <greg.reagle@umbc.edu> +© 2014-2015 Greg Reagle <greg.reagle@umbc.edu> © 2015 Tai Chi Minh Ralph Eastwood <tcmreastwood@gmail.com> © 2015 Quentin Rameau <quinq@quinq.eu.org> © 2015 Dionysis Grigoropoulos <info@erethon.com> diff --git a/Makefile b/Makefile @@ -115,6 +115,7 @@ BIN =\ nice\ nl\ nohup\ + od\ paste\ printenv\ printf\ diff --git a/README b/README @@ -54,6 +54,7 @@ The following tools are implemented: =*|o nice . #*|o nl . =*|o nohup . + od a lot #*|o paste . =*|x printenv . #*|o printf . diff --git a/TODO b/TODO @@ -10,7 +10,6 @@ diff ed getconf install -od patch pathchk stty diff --git a/od.1 b/od.1 @@ -0,0 +1,30 @@ +.Dd September 28, 2015 +.Dt OD 1 +.Os sbase +.Sh NAME +.Nm od +.Nd octal dump +.Sh SYNOPSIS +.Nm +.Op Fl A Ar d|o|x|n +.Op Fl t Ar a|c|d|o|u|x +.Op Ar file... +.Sh DESCRIPTION +.Nm +writes an octal dump of each +.Ar file +to stdout. If no +.Ar file +is given, then +.Nm +reads from stdin. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl A Ar d|o|x|n +Display the address in base \fId\fRecimal | \fIo\fRctal | +he\fIx\fRadecimal | \fIn\fRone. If unspecified, the default is octal. +.It Fl t Ar a|c|d|o|u|x +Display the content as n\fIa\fRmed character, \fIc\fRharacter, signed +\fId\fRecimal, \fIo\fRctal, \fIu\fRnsigned decimal, or +he\fIx\fRadecimal. If unspecified, the default is octal. +.El diff --git a/od.c b/od.c @@ -0,0 +1,177 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdlib.h> +#include <string.h> + +#include "util.h" + +static char addr_radix = 'o'; +static char *type = "o"; + +static void +usage(void) +{ + eprintf("usage: %s [-A d|o|x|n] [-t a|c|d|o|u|x] [file ...]\n", argv0); +} + +static void +print_address(FILE *f, size_t addr) +{ + switch (addr_radix) { + case 'x': + fprintf(f, "%06zx ", addr); + break; + case 'd': + fprintf(f, "%06zd ", addr); + break; + case 'n': + fprintf(f, "%s", " "); + break; + case 'o': + default: + fprintf(f, "%06zo ", addr); + break; + } +} + +static char char_string[2]; + +static const char * +escaped_char(unsigned char c) +{ + switch (c) { + case '\0': + return "\\0"; + case '\a': + return "\\a"; + case '\b': + return "\\b"; + case '\t': + return "\\t"; + case '\n': + return "\\n"; + case '\v': + return "\\v"; + case '\f': + return "\\f"; + case '\r': + return "\\r"; + default: + char_string[0] = c; + char_string[1] = '\0'; + return char_string; + } +} + +static const char * +named_char(unsigned char c) +{ + static const int table_size = 33; + static const char * named_chars[] = {"nul", "soh", "stx", "etx", "eot", + "enq", "ack", "bel", "bs", "ht", "nl", "vt", "ff", "cr", "so", "si", + "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", "can", "em", + "sub", "esc", "fs", "gs", "rs", "us", "sp"}; + + c &= ~128; /* clear high bit of byte, as required by standard */ + if (c < table_size) { + return named_chars[c]; + } else if (c == 127) { + return "del"; + } else { + char_string[0] = c; + char_string[1] = '\0'; + return char_string; + } +} + +static void +print_content(FILE *f, char type, unsigned char cont) +{ + switch (type) { + case 'a': + fprintf(f, "%3s ", named_char(cont)); + break; + case 'c': + fprintf(f, "%3s ", escaped_char(cont)); + break; + case 'd': + fprintf(f, "%4hhd ", cont); + break; + case 'o': + fprintf(f, "%03hho ", cont); + break; + case 'u': + fprintf(f, "%3hhu ", cont); + break; + case 'x': + fprintf(f, "%02hhx ", cont); + break; + } +} + +static void +od(FILE *fp_in, const char *name_in, FILE *fp_out, const char *name_out) +{ + unsigned char buf[BUFSIZ]; + size_t addr, buf_size, i; + const size_t bytes_per_line = 16; + + addr = 0; + for (; (buf_size = fread(buf, 1, BUFSIZ, fp_in)); ) { + for (i = 0; i < buf_size; ++i, ++addr) { + if ((addr % bytes_per_line) == 0) { + if (addr != 0) fprintf(fp_out, "%s", "\n"); + print_address(fp_out, addr); + } + print_content(fp_out, type[0], buf[i]); + } + if (feof(fp_in) || ferror(fp_in) || ferror(fp_out)) + break; + } + fprintf(fp_out, "\n%.7zx \n", addr); +} + +int +main(int argc, char *argv[]) +{ + FILE *fp; + int ret = 0; + char *s; + + ARGBEGIN { + case 'A': + s = EARGF(usage()); + if (strlen(s) > 1 || !strchr("doxn", s[0])) + usage(); + addr_radix = s[0]; + break; + case 't': + type = EARGF(usage()); + if (strlen(type) > 1 || !strchr("acdoux", type[0])) + usage(); + break; + default: + usage(); + } ARGEND; + + if (!argc) { + od(stdin, "<stdin>", stdout, "<stdout>"); + } else { + for (; *argv; argc--, argv++) { + if (!strcmp(*argv, "-")) { + *argv = "<stdin>"; + fp = stdin; + } else if (!(fp = fopen(*argv, "r"))) { + weprintf("fopen %s:", *argv); + ret = 1; + continue; + } + od(fp, *argv, stdout, "<stdout>"); + if (fp != stdin && fshut(fp, *argv)) + ret = 1; + } + } + + ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); + + return ret; +}