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