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