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