busybox/util-linux/hexdump.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * hexdump implementation for busybox
   4 * Based on code from util-linux v 2.11l
   5 *
   6 * Copyright (c) 1989
   7 * The Regents of the University of California.  All rights reserved.
   8 *
   9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10 */
  11//config:config HEXDUMP
  12//config:       bool "hexdump (8.6 kb)"
  13//config:       default y
  14//config:       help
  15//config:       The hexdump utility is used to display binary data in a readable
  16//config:       way that is comparable to the output from most hex editors.
  17//config:
  18//config:config FEATURE_HEXDUMP_REVERSE
  19//config:       bool "Support -R, reverse of 'hexdump -Cv'"
  20//config:       default y
  21//config:       depends on HEXDUMP
  22//config:       help
  23//config:       The hexdump utility is used to display binary data in an ascii
  24//config:       readable way. This option creates binary data from an ascii input.
  25//config:       NB: this option is non-standard. It's unwise to use it in scripts
  26//config:       aimed to be portable.
  27//config:
  28//config:config HD
  29//config:       bool "hd (7.8 kb)"
  30//config:       default y
  31//config:       help
  32//config:       hd is an alias to hexdump -C.
  33
  34//applet:IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hexdump))
  35//applet:IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd))
  36
  37//kbuild:lib-$(CONFIG_HEXDUMP) += hexdump.o
  38//kbuild:lib-$(CONFIG_HD) += hexdump.o
  39
  40//usage:#define hexdump_trivial_usage
  41//usage:       "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] [FILE]..."
  42//usage:#define hexdump_full_usage "\n\n"
  43//usage:       "Display FILEs (or stdin) in a user specified format\n"
  44//usage:     "\n        -b              1-byte octal display"
  45//usage:     "\n        -c              1-byte character display"
  46//usage:     "\n        -d              2-byte decimal display"
  47//usage:     "\n        -o              2-byte octal display"
  48//usage:     "\n        -x              2-byte hex display"
  49//usage:     "\n        -C              hex+ASCII 16 bytes per line"
  50//usage:     "\n        -v              Show all (no dup folding)"
  51//usage:     "\n        -e FORMAT_STR   Example: '16/1 \"%02x|\"\"\\n\"'"
  52//usage:     "\n        -f FORMAT_FILE"
  53// exactly the same help text lines in hexdump and xxd:
  54//usage:     "\n        -n LENGTH       Show only first LENGTH bytes"
  55//usage:     "\n        -s OFFSET       Skip OFFSET bytes"
  56//usage:        IF_FEATURE_HEXDUMP_REVERSE(
  57//usage:     "\n        -R              Reverse of 'hexdump -Cv'")
  58// TODO: NONCOMPAT!!! move -R to xxd -r
  59//usage:
  60//usage:#define hd_trivial_usage
  61//usage:       "FILE..."
  62//usage:#define hd_full_usage "\n\n"
  63//usage:       "hd is an alias for hexdump -C"
  64
  65#include "libbb.h"
  66#include "dump.h"
  67
  68/* This is a NOEXEC applet. Be very careful! */
  69
  70static void bb_dump_addfile(dumper_t *dumper, char *name)
  71{
  72        char *p;
  73        FILE *fp;
  74        char *buf;
  75
  76        fp = xfopen_for_read(name);
  77        while ((buf = xmalloc_fgetline(fp)) != NULL) {
  78                p = skip_whitespace(buf);
  79                if (*p && (*p != '#')) {
  80                        bb_dump_add(dumper, p);
  81                }
  82                free(buf);
  83        }
  84        fclose(fp);
  85}
  86
  87static const char *const add_strings[] = {
  88        "\"%07.7_ax \"16/1 \"%03o \"\"\n\"",   /* b */
  89        "\"%07.7_ax \"16/1 \"%3_c \"\"\n\"",   /* c */
  90        "\"%07.7_ax \"8/2 \"  %05u \"\"\n\"",  /* d */
  91        "\"%07.7_ax \"8/2 \" %06o \"\"\n\"",   /* o */
  92        "\"%07.7_ax \"8/2 \"   %04x \"\"\n\"", /* x */
  93};
  94
  95static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
  96
  97static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R");
  98
  99int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 100int hexdump_main(int argc, char **argv)
 101{
 102        dumper_t *dumper = alloc_dumper();
 103        const char *p;
 104        int ch;
 105#if ENABLE_FEATURE_HEXDUMP_REVERSE
 106        FILE *fp;
 107        smallint rdump = 0;
 108#endif
 109
 110        if (ENABLE_HD
 111         && (!ENABLE_HEXDUMP || !applet_name[2])
 112        ) { /* we are "hd" */
 113                ch = 'C';
 114                goto hd_applet;
 115        }
 116
 117        /* We cannot use getopt32: in hexdump options are cumulative.
 118         * E.g. "hexdump -C -C file" should dump each line twice */
 119        while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
 120                p = strchr(hexdump_opts, ch);
 121                if (!p)
 122                        bb_show_usage();
 123                if ((p - hexdump_opts) < 5) {
 124                        bb_dump_add(dumper, add_first);
 125                        bb_dump_add(dumper, add_strings[(int)(p - hexdump_opts)]);
 126                }
 127                /* Save a little bit of space below by omitting the 'else's. */
 128                if (ch == 'C') {
 129 hd_applet:
 130                        bb_dump_add(dumper, "\"%08.8_Ax\n\""); // final address line after dump
 131                        //------------------- "address  "   8 * "xx "    "  "  8 * "xx "
 132                        bb_dump_add(dumper, "\"%08.8_ax  \"8/1 \"%02x \"\"  \"8/1 \"%02x \"");
 133                        //------------------- "  |ASCII...........|\n"
 134                        bb_dump_add(dumper, "\"  |\"16/1 \"%_p\"\"|\n\"");
 135                }
 136                if (ch == 'e') {
 137                        bb_dump_add(dumper, optarg);
 138                } /* else */
 139                if (ch == 'f') {
 140                        bb_dump_addfile(dumper, optarg);
 141                } /* else */
 142                if (ch == 'n') {
 143                        dumper->dump_length = xatoi_positive(optarg);
 144                } /* else */
 145                if (ch == 's') { /* compat: -s accepts hex numbers too */
 146                        dumper->dump_skip = xstrtoull_range_sfx(
 147                                optarg,
 148                                /*base:*/ 0,
 149                                /*lo:*/ 0, /*hi:*/ OFF_T_MAX,
 150                                bkm_suffixes
 151                        );
 152                } /* else */
 153                if (ch == 'v') {
 154                        dumper->dump_vflag = ALL;
 155                }
 156#if ENABLE_FEATURE_HEXDUMP_REVERSE
 157                if (ch == 'R') {
 158                        rdump = 1;
 159                }
 160#endif
 161        }
 162
 163        if (!dumper->fshead) {
 164                bb_dump_add(dumper, add_first);
 165                bb_dump_add(dumper, "\"%07.7_ax \"8/2 \"%04x \"\"\n\"");
 166        }
 167
 168        argv += optind;
 169
 170#if !ENABLE_FEATURE_HEXDUMP_REVERSE
 171        return bb_dump_dump(dumper, argv);
 172#else
 173        if (!rdump) {
 174                return bb_dump_dump(dumper, argv);
 175        }
 176
 177        /* -R: reverse of 'hexdump -Cv' */
 178        fp = stdin;
 179        if (!*argv) {
 180                argv--;
 181                goto jump_in;
 182        }
 183
 184        do {
 185                char *buf;
 186                fp = xfopen_for_read(*argv);
 187 jump_in:
 188                while ((buf = xmalloc_fgetline(fp)) != NULL) {
 189                        p = buf;
 190                        while (1) {
 191                                /* skip address or previous byte */
 192                                while (isxdigit(*p)) p++;
 193                                while (*p == ' ') p++;
 194                                /* '|' char will break the line */
 195                                if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1)
 196                                        break;
 197                                putchar(ch);
 198                        }
 199                        free(buf);
 200                }
 201                fclose(fp);
 202        } while (*++argv);
 203
 204        fflush_stdout_and_exit(EXIT_SUCCESS);
 205#endif
 206}
 207