inetd,mount: add comment with example of flags to build with libtirpc
[oweals/busybox.git] / util-linux / hexdump.c
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.8 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 (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
70 static 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
87 static 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
95 static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
96
97 static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R");
98
99 int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
100 int 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 }