toybox/toys/pending/hexdump.c
<<
>>
Prefs
   1/* hexdump.c - Dump file content in hexadecimal format to stdout
   2 *
   3 * Copyright 2021 Moritz Röhrich <moritz@ildefons.de>
   4 *
   5 * No standard
   6 *
   7 * TODO:
   8 *  - Implement format strings (see man (1) hexdump)
   9
  10USE_HEXDUMP(NEWTOY(hexdump, "bcCdn#<0os#<0vx[!bcCdox]", TOYFLAG_USR|TOYFLAG_BIN))
  11USE_HD(OLDTOY(hd, hexdump, TOYFLAG_USR|TOYFLAG_BIN))
  12
  13config HEXDUMP
  14  bool "hexdump"
  15  default n
  16  help
  17    usage: hexdump [-bcCdovx] [-n LEN] [-s SKIP] [FILE...]
  18
  19    Dump file(s) in hexadecimal format.
  20
  21    -n LEN      Show LEN bytes of output
  22    -s SKIP     Skip bytes of input
  23    -v  Verbose (don't combine identical lines)
  24
  25    Display type:
  26    -b One byte octal   -c One byte character -C Canonical (hex + ASCII)
  27    -d Two byte decimal -o Two byte octal     -x Two byte hexadecimal (default)
  28
  29config HD
  30  bool "hd"
  31  default HEXDUMP
  32  help
  33    usage: hd [FILE...]
  34
  35    Display file(s) in cannonical hex+ASCII format.
  36*/
  37
  38#define FOR_hexdump
  39#include "toys.h"
  40
  41GLOBALS(
  42    long s, n;
  43
  44    long long len, pos, ppos;
  45    const char *fmt;
  46    unsigned int fn, bc;  // file number and byte count
  47    char linebuf[16];  // line buffer - serves double duty for sqeezing repeat
  48                       // lines and for accumulating full lines accross file
  49                       // boundaries if necessesary.
  50)
  51
  52const char *make_printable(unsigned char byte) {
  53  switch (byte) {
  54    case '\0': return "\\0";
  55    case '\a': return "\\a";
  56    case '\b': return "\\b";
  57    case '\t': return "\\t";
  58    case '\n': return "\\n";
  59    case '\v': return "\\v";
  60    case '\f': return "\\f";
  61    default: return "??";  // for all unprintable bytes
  62  }
  63}
  64
  65void do_hexdump(int fd, char *name)
  66{
  67  unsigned short block, adv, i;
  68  int sl, fs;  // skip line, file size
  69
  70  TT.fn++;  // keep track of how many files have been printed.
  71  // skipp ahead, if necessary skip entire files:
  72  if (FLAG(s) && (TT.s-TT.pos>0)) {
  73    fs = xlseek(fd, 0L, SEEK_END);
  74
  75    if (fs < TT.s) {
  76      TT.pos += fs;
  77      TT.ppos += fs;
  78    } else {
  79      xlseek(fd, TT.s-TT.pos, SEEK_SET);
  80      TT.ppos = TT.s;
  81      TT.pos = TT.s;
  82    }
  83  }
  84
  85  for (sl = 0;
  86       0 < (TT.len = readall(fd, toybuf,
  87                             (TT.n && TT.s+TT.n-TT.pos<16-(TT.bc%16))
  88                                ? TT.s+TT.n-TT.pos : 16-(TT.bc%16)));
  89       TT.pos += TT.len) {
  90    // This block compares the data read from file to the last line printed.
  91    // If they don't match a new line is printed, else the line is skipped.
  92    // If a * has already been printed to indicate a skipped line, printing the
  93    // * is also skipped.
  94    for (i = 0; i < 16 && i < TT.len; i++){
  95      if (FLAG(v) || TT.len < 16 || toybuf[i] != TT.linebuf[i]) goto newline;
  96    }
  97    if (sl == 0) {
  98      printf("*\n");
  99      sl = 1;
 100    }
 101    TT.ppos += TT.len;
 102    continue;
 103
 104newline:
 105    strncpy(TT.linebuf+(TT.bc%16), toybuf, TT.len);
 106    TT.bc = TT.bc % 16 + TT.len;
 107    sl = 0;
 108    if (TT.pos + TT.bc == TT.s+TT.n || TT.fn == toys.optc || TT.bc == 16) {
 109      if (!FLAG(C) && !FLAG(c)) {
 110        printf("%07llx", TT.ppos);
 111        adv = FLAG(b) ? 1 : 2;
 112        for (i = 0; i < TT.bc; i += adv) {
 113          block = (FLAG(b) || i == TT.bc-1)
 114            ? TT.linebuf[i] : (TT.linebuf[i] | TT.linebuf[i+1] << 8);
 115          printf(TT.fmt, block);
 116        }
 117      } else if (FLAG(C)) {
 118        printf("%08llx", TT.ppos);
 119        for (i = 0; i < 16; i++) {
 120          if (!(i % 8)) putchar(' ');
 121          if (i < TT.bc) printf(" %02x", TT.linebuf[i]);
 122          else printf("   ");
 123        }
 124        printf("  |");
 125        for (i = 0; i < TT.bc; i++) {
 126          if (TT.linebuf[i] < ' ' || TT.linebuf[i] > '~') putchar('.');
 127          else putchar(TT.linebuf[i]);
 128        }
 129        putchar('|');
 130      } else {
 131        printf("%07llx", TT.ppos);
 132        for (i = 0; i < TT.bc; i++) {
 133          if (TT.linebuf[i] >= ' ' && TT.linebuf[i] <= '~')
 134            printf("%4c", TT.linebuf[i]);
 135          else printf("%4s", make_printable(TT.linebuf[i]));
 136        }
 137      }
 138      putchar('\n');
 139      TT.ppos += TT.bc;
 140    }
 141  }
 142
 143  if (TT.len < 0) perror_exit("read");
 144}
 145
 146void hexdump_main(void)
 147{
 148  if FLAG(b) TT.fmt = " %03o";
 149  else if FLAG(d) TT.fmt = " %05d";
 150  else if FLAG(o) TT.fmt = " %06o";
 151  else TT.fmt = " %04x";
 152
 153  loopfiles(toys.optargs, do_hexdump);
 154  FLAG(C) ? printf("%08llx\n", TT.pos) : printf("%07llx\n", TT.pos);
 155}
 156