31ebde2108ce6a0dfd1eb1a7d3561f8bea14f9b5
[oweals/busybox.git] / coreutils / od.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * od implementation for busybox
4  * Based on code from util-linux v 2.11l
5  *
6  * Copyright (c) 1990
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  * Original copyright notice is retained at the end of this file.
12  */
13
14 //usage:#define od_trivial_usage
15 //usage:       "[-aBbcDdeFfHhIiLlOovXx] " IF_DESKTOP("[-t TYPE] ") "[FILE]"
16 //usage:#define od_full_usage "\n\n"
17 //usage:       "Write an unambiguous representation, octal bytes by default, of FILE\n"
18 //usage:       "(or stdin) to stdout"
19
20 #include "libbb.h"
21 #if ENABLE_DESKTOP
22 /* This one provides -t (busybox's own build script needs it) */
23 #include "od_bloaty.c"
24 #else
25
26 #include "dump.h"
27
28 static void
29 odoffset(dumper_t *dumper, int argc, char ***argvp)
30 {
31         char *num, *p;
32         int base;
33         char *end;
34
35         /*
36          * The offset syntax of od(1) was genuinely bizarre.  First, if
37          * it started with a plus it had to be an offset.  Otherwise, if
38          * there were at least two arguments, a number or lower-case 'x'
39          * followed by a number makes it an offset.  By default it was
40          * octal; if it started with 'x' or '0x' it was hex.  If it ended
41          * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
42          * multiplied the number by 512 or 1024 byte units.  There was
43          * no way to assign a block count to a hex offset.
44          *
45          * We assumes it's a file if the offset is bad.
46          */
47         p = **argvp;
48
49         if (!p) {
50                 /* hey someone is probably piping to us ... */
51                 return;
52         }
53
54         if ((*p != '+')
55                 && (argc < 2
56                         || (!isdigit(p[0])
57                                 && ((p[0] != 'x') || !isxdigit(p[1])))))
58                 return;
59
60         base = 0;
61         /*
62          * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
63          * set base.
64          */
65         if (p[0] == '+')
66                 ++p;
67         if (p[0] == 'x' && isxdigit(p[1])) {
68                 ++p;
69                 base = 16;
70         } else if (p[0] == '0' && p[1] == 'x') {
71                 p += 2;
72                 base = 16;
73         }
74
75         /* skip over the number */
76         if (base == 16)
77                 for (num = p; isxdigit(*p); ++p)
78                         continue;
79         else
80                 for (num = p; isdigit(*p); ++p)
81                         continue;
82
83         /* check for no number */
84         if (num == p)
85                 return;
86
87         /* if terminates with a '.', base is decimal */
88         if (*p == '.') {
89                 if (base)
90                         return;
91                 base = 10;
92         }
93
94         dumper->dump_skip = strtol(num, &end, base ? base : 8);
95
96         /* if end isn't the same as p, we got a non-octal digit */
97         if (end != p)
98                 dumper->dump_skip = 0;
99         else {
100                 if (*p) {
101                         if (*p == 'b') {
102                                 dumper->dump_skip *= 512;
103                                 ++p;
104                         } else if (*p == 'B') {
105                                 dumper->dump_skip *= 1024;
106                                 ++p;
107                         }
108                 }
109                 if (*p)
110                         dumper->dump_skip = 0;
111                 else {
112                         ++*argvp;
113                         /*
114                          * If the offset uses a non-octal base, the base of
115                          * the offset is changed as well.  This isn't pretty,
116                          * but it's easy.
117                          */
118 #define TYPE_OFFSET 7
119                         {
120                                 char x_or_d;
121                                 if (base == 16) {
122                                         x_or_d = 'x';
123                                         goto DO_X_OR_D;
124                                 }
125                                 if (base == 10) {
126                                         x_or_d = 'd';
127  DO_X_OR_D:
128                                         dumper->fshead->nextfu->fmt[TYPE_OFFSET]
129                                                 = dumper->fshead->nextfs->nextfu->fmt[TYPE_OFFSET]
130                                                 = x_or_d;
131                                 }
132                         }
133                 }
134         }
135 }
136
137 static const char *const add_strings[] = {
138         "16/1 \"%3_u \" \"\\n\"",              /* a */
139         "8/2 \" %06o \" \"\\n\"",              /* B, o */
140         "16/1 \"%03o \" \"\\n\"",              /* b */
141         "16/1 \"%3_c \" \"\\n\"",              /* c */
142         "8/2 \"  %05u \" \"\\n\"",             /* d */
143         "4/4 \"     %010u \" \"\\n\"",         /* D */
144         "2/8 \"          %21.14e \" \"\\n\"",  /* e (undocumented in od), F */
145         "4/4 \" %14.7e \" \"\\n\"",            /* f */
146         "4/4 \"       %08x \" \"\\n\"",        /* H, X */
147         "8/2 \"   %04x \" \"\\n\"",            /* h, x */
148         "4/4 \"    %11d \" \"\\n\"",           /* I, L, l */
149         "8/2 \" %6d \" \"\\n\"",               /* i */
150         "4/4 \"    %011o \" \"\\n\"",          /* O */
151 };
152
153 static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxv";
154
155 static const char od_o2si[] ALIGN1 = {
156         0, 1, 2, 3, 5,
157         4, 6, 6, 7, 8,
158         9, 0xa, 0xb, 0xa, 0xa,
159         0xb, 1, 8, 9,
160 };
161
162 int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
163 int od_main(int argc, char **argv)
164 {
165         int ch;
166         int first = 1;
167         char *p;
168         dumper_t *dumper = alloc_dumper();
169
170         while ((ch = getopt(argc, argv, od_opts)) > 0) {
171                 if (ch == 'v') {
172                         dumper->dump_vflag = ALL;
173                 } else if (((p = strchr(od_opts, ch)) != NULL) && (*p != '\0')) {
174                         if (first) {
175                                 first = 0;
176                                 bb_dump_add(dumper, "\"%07.7_Ao\n\"");
177                                 bb_dump_add(dumper, "\"%07.7_ao  \"");
178                         } else {
179                                 bb_dump_add(dumper, "\"         \"");
180                         }
181                         bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]);
182                 } else {  /* P, p, s, w, or other unhandled */
183                         bb_show_usage();
184                 }
185         }
186         if (!dumper->fshead) {
187                 bb_dump_add(dumper, "\"%07.7_Ao\n\"");
188                 bb_dump_add(dumper, "\"%07.7_ao  \" 8/2 \"%06o \" \"\\n\"");
189         }
190
191         argc -= optind;
192         argv += optind;
193
194         odoffset(dumper, argc, &argv);
195
196         return bb_dump_dump(dumper, argv);
197 }
198 #endif /* ENABLE_DESKTOP */
199
200 /*-
201  * Copyright (c) 1990 The Regents of the University of California.
202  * All rights reserved.
203  *
204  * Redistribution and use in source and binary forms, with or without
205  * modification, are permitted provided that the following conditions
206  * are met:
207  * 1. Redistributions of source code must retain the above copyright
208  *    notice, this list of conditions and the following disclaimer.
209  * 2. Redistributions in binary form must reproduce the above copyright
210  *    notice, this list of conditions and the following disclaimer in the
211  *    documentation and/or other materials provided with the distribution.
212  * 3. Neither the name of the University nor the names of its contributors
213  *    may be used to endorse or promote products derived from this software
214  *    without specific prior written permission.
215  *
216  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
219  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
220  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
225  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
226  * SUCH DAMAGE.
227  */