Convert all util-linux/* applets to "new style" applet definitions
[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"
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"
30 //config:       default y
31 //config:       depends on HEXDUMP
32 //config:       help
33 //config:         hd is an alias to hexdump -C.
34
35 //applet:IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hexdump))
36 //applet:IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd))
37
38 //kbuild:lib-$(CONFIG_HEXDUMP) += hexdump.o
39 //kbuild:lib-$(CONFIG_HD) += hexdump.o
40
41 //usage:#define hexdump_trivial_usage
42 //usage:       "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] [FILE]..."
43 //usage:#define hexdump_full_usage "\n\n"
44 //usage:       "Display FILEs (or stdin) in a user specified format\n"
45 //usage:     "\n        -b              One-byte octal display"
46 //usage:     "\n        -c              One-byte character display"
47 //usage:     "\n        -C              Canonical hex+ASCII, 16 bytes per line"
48 //usage:     "\n        -d              Two-byte decimal display"
49 //usage:     "\n        -e FORMAT_STRING"
50 //usage:     "\n        -f FORMAT_FILE"
51 //usage:     "\n        -n LENGTH       Interpret only LENGTH bytes of input"
52 //usage:     "\n        -o              Two-byte octal display"
53 //usage:     "\n        -s OFFSET       Skip OFFSET bytes"
54 //usage:     "\n        -v              Display all input data"
55 //usage:     "\n        -x              Two-byte hexadecimal display"
56 //usage:        IF_FEATURE_HEXDUMP_REVERSE(
57 //usage:     "\n        -R              Reverse of 'hexdump -Cv'")
58 //usage:
59 //usage:#define hd_trivial_usage
60 //usage:       "FILE..."
61 //usage:#define hd_full_usage "\n\n"
62 //usage:       "hd is an alias for hexdump -C"
63
64 #include "libbb.h"
65 #include "dump.h"
66
67 /* This is a NOEXEC applet. Be very careful! */
68
69 static void bb_dump_addfile(dumper_t *dumper, char *name)
70 {
71         char *p;
72         FILE *fp;
73         char *buf;
74
75         fp = xfopen_for_read(name);
76         while ((buf = xmalloc_fgetline(fp)) != NULL) {
77                 p = skip_whitespace(buf);
78                 if (*p && (*p != '#')) {
79                         bb_dump_add(dumper, p);
80                 }
81                 free(buf);
82         }
83         fclose(fp);
84 }
85
86 static const char *const add_strings[] = {
87         "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"",   /* b */
88         "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"",   /* c */
89         "\"%07.7_ax \" 8/2 \"  %05u \" \"\\n\"",  /* d */
90         "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"",   /* o */
91         "\"%07.7_ax \" 8/2 \"   %04x \" \"\\n\"", /* x */
92 };
93
94 static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
95
96 static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R");
97
98 int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
99 int hexdump_main(int argc, char **argv)
100 {
101         dumper_t *dumper = alloc_dumper();
102         const char *p;
103         int ch;
104 #if ENABLE_FEATURE_HEXDUMP_REVERSE
105         FILE *fp;
106         smallint rdump = 0;
107 #endif
108
109         if (ENABLE_HD && !applet_name[2]) { /* we are "hd" */
110                 ch = 'C';
111                 goto hd_applet;
112         }
113
114         /* We cannot use getopt32: in hexdump options are cumulative.
115          * E.g. "hexdump -C -C file" should dump each line twice */
116         while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
117                 p = strchr(hexdump_opts, ch);
118                 if (!p)
119                         bb_show_usage();
120                 if ((p - hexdump_opts) < 5) {
121                         bb_dump_add(dumper, add_first);
122                         bb_dump_add(dumper, add_strings[(int)(p - hexdump_opts)]);
123                 }
124                 /* Save a little bit of space below by omitting the 'else's. */
125                 if (ch == 'C') {
126  hd_applet:
127                         bb_dump_add(dumper, "\"%08.8_Ax\n\"");
128                         bb_dump_add(dumper, "\"%08.8_ax  \" 8/1 \"%02x \" \"  \" 8/1 \"%02x \" ");
129                         bb_dump_add(dumper, "\"  |\" 16/1 \"%_p\" \"|\\n\"");
130                 }
131                 if (ch == 'e') {
132                         bb_dump_add(dumper, optarg);
133                 } /* else */
134                 if (ch == 'f') {
135                         bb_dump_addfile(dumper, optarg);
136                 } /* else */
137                 if (ch == 'n') {
138                         dumper->dump_length = xatoi_positive(optarg);
139                 } /* else */
140                 if (ch == 's') { /* compat: -s accepts hex numbers too */
141                         dumper->dump_skip = xstrtoull_range_sfx(
142                                 optarg,
143                                 /*base:*/ 0,
144                                 /*lo:*/ 0, /*hi:*/ OFF_T_MAX,
145                                 bkm_suffixes
146                         );
147                 } /* else */
148                 if (ch == 'v') {
149                         dumper->dump_vflag = ALL;
150                 }
151 #if ENABLE_FEATURE_HEXDUMP_REVERSE
152                 if (ch == 'R') {
153                         rdump = 1;
154                 }
155 #endif
156         }
157
158         if (!dumper->fshead) {
159                 bb_dump_add(dumper, add_first);
160                 bb_dump_add(dumper, "\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
161         }
162
163         argv += optind;
164
165 #if !ENABLE_FEATURE_HEXDUMP_REVERSE
166         return bb_dump_dump(dumper, argv);
167 #else
168         if (!rdump) {
169                 return bb_dump_dump(dumper, argv);
170         }
171
172         /* -R: reverse of 'hexdump -Cv' */
173         fp = stdin;
174         if (!*argv) {
175                 argv--;
176                 goto jump_in;
177         }
178
179         do {
180                 char *buf;
181                 fp = xfopen_for_read(*argv);
182  jump_in:
183                 while ((buf = xmalloc_fgetline(fp)) != NULL) {
184                         p = buf;
185                         while (1) {
186                                 /* skip address or previous byte */
187                                 while (isxdigit(*p)) p++;
188                                 while (*p == ' ') p++;
189                                 /* '|' char will break the line */
190                                 if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1)
191                                         break;
192                                 putchar(ch);
193                         }
194                         free(buf);
195                 }
196                 fclose(fp);
197         } while (*++argv);
198
199         fflush_stdout_and_exit(EXIT_SUCCESS);
200 #endif
201 }