1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33
34 #include <ctype.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <float.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "hexdump.h"
44
45 #define PADDING " "
46
47 int odmode;
48
49 static void odadd(const char *);
50 static void odformat(const char *);
51 static const char *odformatfp(char, const char *);
52 static const char *odformatint(char, const char *);
53 static void odoffset(int, char ***);
54 static void odusage(void);
55
56 void
oldsyntax(int argc,char *** argvp)57 oldsyntax(int argc, char ***argvp)
58 {
59 static char empty[] = "", padding[] = PADDING;
60 int ch;
61 char **argv, *end;
62
63 /* Add initial (default) address format. -A may change it later. */
64 #define TYPE_OFFSET 7
65 add("\"%07.7_Ao\n\"");
66 add("\"%07.7_ao \"");
67
68 odmode = 1;
69 argv = *argvp;
70 while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1)
71 switch (ch) {
72 case 'A':
73 switch (*optarg) {
74 case 'd': case 'o': case 'x':
75 fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
76 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
77 *optarg;
78 break;
79 case 'n':
80 fshead->nextfu->fmt = empty;
81 fshead->nextfs->nextfu->fmt = padding;
82 break;
83 default:
84 errx(1, "%s: invalid address base", optarg);
85 }
86 break;
87 case 'a':
88 odformat("a");
89 break;
90 case 'B':
91 case 'o':
92 odformat("o2");
93 break;
94 case 'b':
95 odformat("o1");
96 break;
97 case 'c':
98 odformat("c");
99 break;
100 case 'd':
101 odformat("u2");
102 break;
103 case 'D':
104 odformat("u4");
105 break;
106 case 'e': /* undocumented in od */
107 case 'F':
108 odformat("fD");
109 break;
110 case 'f':
111 odformat("fF");
112 break;
113 case 'H':
114 case 'X':
115 odformat("x4");
116 break;
117 case 'h':
118 case 'x':
119 odformat("x2");
120 break;
121 case 'I':
122 case 'L':
123 case 'l':
124 odformat("dL");
125 break;
126 case 'i':
127 odformat("dI");
128 break;
129 case 'j':
130 errno = 0;
131 skip = strtoll(optarg, &end, 0);
132 if (*end == 'b')
133 skip *= 512;
134 else if (*end == 'k')
135 skip *= 1024;
136 else if (*end == 'm')
137 skip *= 1048576L;
138 if (errno != 0 || skip < 0 || strlen(end) > 1)
139 errx(1, "%s: invalid skip amount", optarg);
140 break;
141 case 'N':
142 if ((length = atoi(optarg)) <= 0)
143 errx(1, "%s: invalid length", optarg);
144 break;
145 case 'O':
146 odformat("o4");
147 break;
148 case 's':
149 odformat("d2");
150 break;
151 case 't':
152 odformat(optarg);
153 break;
154 case 'v':
155 vflag = ALL;
156 break;
157 case '?':
158 default:
159 odusage();
160 }
161
162 if (fshead->nextfs->nextfs == NULL)
163 odformat("oS");
164
165 argc -= optind;
166 *argvp += optind;
167
168 if (argc)
169 odoffset(argc, argvp);
170 }
171
172 static void
odusage(void)173 odusage(void)
174 {
175
176 fprintf(stderr,
177 "usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n");
178 fprintf(stderr,
179 " [[+]offset[.][Bb]] [file ...]\n");
180 exit(1);
181 }
182
183 static void
odoffset(int argc,char *** argvp)184 odoffset(int argc, char ***argvp)
185 {
186 char *p, *num, *end;
187 int base;
188
189 /*
190 * The offset syntax of od(1) was genuinely bizarre. First, if
191 * it started with a plus it had to be an offset. Otherwise, if
192 * there were at least two arguments, a number or lower-case 'x'
193 * followed by a number makes it an offset. By default it was
194 * octal; if it started with 'x' or '0x' it was hex. If it ended
195 * in a '.', it was decimal. If a 'b' or 'B' was appended, it
196 * multiplied the number by 512 or 1024 byte units. There was
197 * no way to assign a block count to a hex offset.
198 *
199 * We assume it's a file if the offset is bad.
200 */
201 p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
202
203 if (*p != '+' && (argc < 2 ||
204 (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1])))))
205 return;
206
207 base = 0;
208 /*
209 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
210 * set base.
211 */
212 if (p[0] == '+')
213 ++p;
214 if (p[0] == 'x' && isxdigit(p[1])) {
215 ++p;
216 base = 16;
217 } else if (p[0] == '0' && p[1] == 'x') {
218 p += 2;
219 base = 16;
220 }
221
222 /* skip over the number */
223 if (base == 16)
224 for (num = p; isxdigit(*p); ++p);
225 else
226 for (num = p; isdigit(*p); ++p);
227
228 /* check for no number */
229 if (num == p)
230 return;
231
232 /* if terminates with a '.', base is decimal */
233 if (*p == '.') {
234 if (base)
235 return;
236 base = 10;
237 }
238
239 skip = strtoll(num, &end, base ? base : 8);
240
241 /* if end isn't the same as p, we got a non-octal digit */
242 if (end != p) {
243 skip = 0;
244 return;
245 }
246
247 if (*p) {
248 if (*p == 'B') {
249 skip *= 1024;
250 ++p;
251 } else if (*p == 'b') {
252 skip *= 512;
253 ++p;
254 }
255 }
256
257 if (*p) {
258 skip = 0;
259 return;
260 }
261
262 /*
263 * If the offset uses a non-octal base, the base of the offset
264 * is changed as well. This isn't pretty, but it's easy.
265 */
266 if (base == 16) {
267 fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
268 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
269 } else if (base == 10) {
270 fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
271 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
272 }
273
274 /* Terminate file list. */
275 (*argvp)[1] = NULL;
276 }
277
278 static void
odformat(const char * fmt)279 odformat(const char *fmt)
280 {
281 char fchar;
282
283 while (*fmt != '\0') {
284 switch ((fchar = *fmt++)) {
285 case 'a':
286 odadd("16/1 \"%3_u \" \"\\n\"");
287 break;
288 case 'c':
289 odadd("16/1 \"%3_c \" \"\\n\"");
290 break;
291 case 'o': case 'u': case 'd': case 'x':
292 fmt = odformatint(fchar, fmt);
293 break;
294 case 'f':
295 fmt = odformatfp(fchar, fmt);
296 break;
297 default:
298 errx(1, "%c: unrecognised format character", fchar);
299 }
300 }
301 }
302
303 static const char *
odformatfp(char fchar __unused,const char * fmt)304 odformatfp(char fchar __unused, const char *fmt)
305 {
306 size_t isize;
307 int digits;
308 char *end, *hdfmt;
309
310 isize = sizeof(double);
311 switch (*fmt) {
312 case 'F':
313 isize = sizeof(float);
314 fmt++;
315 break;
316 case 'D':
317 isize = sizeof(double);
318 fmt++;
319 break;
320 case 'L':
321 isize = sizeof(long double);
322 fmt++;
323 break;
324 default:
325 if (isdigit((unsigned char)*fmt)) {
326 errno = 0;
327 isize = (size_t)strtoul(fmt, &end, 10);
328 if (errno != 0 || isize == 0)
329 errx(1, "%s: invalid size", fmt);
330 fmt = (const char *)end;
331 }
332 }
333 switch (isize) {
334 case sizeof(float):
335 digits = FLT_DIG;
336 break;
337 case sizeof(double):
338 digits = DBL_DIG;
339 break;
340 default:
341 if (isize == sizeof(long double))
342 digits = LDBL_DIG;
343 else
344 errx(1, "unsupported floating point size %lu",
345 (u_long)isize);
346 }
347
348 asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"",
349 16UL / (u_long)isize, (u_long)isize, digits + 8, digits);
350 if (hdfmt == NULL)
351 err(1, NULL);
352 odadd(hdfmt);
353 free(hdfmt);
354
355 return (fmt);
356 }
357
358 static const char *
odformatint(char fchar,const char * fmt)359 odformatint(char fchar, const char *fmt)
360 {
361 unsigned long long n;
362 size_t isize;
363 int digits;
364 char *end, *hdfmt;
365
366 isize = sizeof(int);
367 switch (*fmt) {
368 case 'C':
369 isize = sizeof(char);
370 fmt++;
371 break;
372 case 'I':
373 isize = sizeof(int);
374 fmt++;
375 break;
376 case 'L':
377 isize = sizeof(long);
378 fmt++;
379 break;
380 case 'S':
381 isize = sizeof(short);
382 fmt++;
383 break;
384 default:
385 if (isdigit((unsigned char)*fmt)) {
386 errno = 0;
387 isize = (size_t)strtoul(fmt, &end, 10);
388 if (errno != 0 || isize == 0)
389 errx(1, "%s: invalid size", fmt);
390 if (isize != sizeof(char) && isize != sizeof(short) &&
391 isize != sizeof(int) && isize != sizeof(long))
392 errx(1, "unsupported int size %lu",
393 (u_long)isize);
394 fmt = (const char *)end;
395 }
396 }
397
398 /*
399 * Calculate the maximum number of digits we need to
400 * fit the number. Overestimate for decimal with log
401 * base 8. We need one extra space for signed numbers
402 * to store the sign.
403 */
404 n = (1ULL << (8 * isize)) - 1;
405 digits = 0;
406 while (n != 0) {
407 digits++;
408 n >>= (fchar == 'x') ? 4 : 3;
409 }
410 if (fchar == 'd')
411 digits++;
412 asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"",
413 16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits),
414 "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar);
415 if (hdfmt == NULL)
416 err(1, NULL);
417 odadd(hdfmt);
418 free(hdfmt);
419
420 return (fmt);
421 }
422
423 static void
odadd(const char * fmt)424 odadd(const char *fmt)
425 {
426 static int needpad;
427
428 if (needpad)
429 add("\""PADDING"\"");
430 add(fmt);
431 needpad = 1;
432 }
433