source: rtems/cpukit/libmisc/shell/hexdump-odsyntax.c @ 6cdaa85

5
Last change on this file since 6cdaa85 was 6cdaa85, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 4, 2018 at 6:16:45 PM

shell: Use #include "..." for local header files

Update #3375.

  • Property mode set to 100644
File size: 10.8 KB
Line 
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
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)odsyntax.c  8.2 (Berkeley) 5/4/95";
41#endif /* not lint */
42#ifdef __rtems__
43/* For asprintf() visibility */
44#define _GNU_SOURCE
45#endif /* __rtems__ */
46#include <sys/cdefs.h>
47__FBSDID("$FreeBSD: src/usr.bin/hexdump/odsyntax.c,v 1.17 2004/07/22 13:14:42 johan Exp $");
48#endif
49
50#include <sys/types.h>
51
52#include <ctype.h>
53#include "err.h"
54#include <errno.h>
55#include <float.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <unistd.h>
60
61#include "hexdump.h"
62
63#define __need_getopt_newlib
64#include <getopt.h>
65
66#define PADDING "         "
67
68#ifndef __unused
69#define __unused RTEMS_UNUSED
70#endif
71
72#if RTEMS_REMOVED
73int odmode;
74#endif
75
76static void odadd(rtems_shell_hexdump_globals*, const char *);
77static void odformat(rtems_shell_hexdump_globals*, const char *);
78static const char *odformatfp(rtems_shell_hexdump_globals*, char, const char *);
79static const char *odformatint(rtems_shell_hexdump_globals*, char, const char *);
80static void odoffset(rtems_shell_hexdump_globals*, int, char ***);
81static void odusage(rtems_shell_hexdump_globals*);
82
83void
84oldsyntax(rtems_shell_hexdump_globals* globals, int argc, char ***argvp)
85{
86        static char empty[] = "", padding[] = PADDING;
87        int ch;
88        char **argv, *end;
89
90  struct getopt_data getopt_reent;
91  memset(&getopt_reent, 0, sizeof(getopt_data));
92
93        /* Add initial (default) address format. -A may change it later. */
94#define TYPE_OFFSET     7
95        add(globals, "\"%07.7_Ao\n\"");
96        add(globals, "\"%07.7_ao  \"");
97
98        odmode = 1;
99        argv = *argvp;
100        while ((ch = getopt_r(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx", &getopt_reent)) != -1)
101                switch (ch) {
102                case 'A':
103                        switch (*optarg) {
104                        case 'd': case 'o': case 'x':
105                                fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
106                                fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
107                                    *optarg;
108                                break;
109                        case 'n':
110                                fshead->nextfu->fmt = empty;
111                                fshead->nextfs->nextfu->fmt = padding;
112                                break;
113                        default:
114                                errx(exit_jump, 1, "%s: invalid address base", optarg);
115                        }
116                        break;
117                case 'a':
118                        odformat(globals, "a");
119                        break;
120                case 'B':
121                case 'o':
122                        odformat(globals, "o2");
123                        break;
124                case 'b':
125                        odformat(globals, "o1");
126                        break;
127                case 'c':
128                        odformat(globals, "c");
129                        break;
130                case 'd':
131                        odformat(globals, "u2");
132                        break;
133                case 'D':
134                        odformat(globals, "u4");
135                        break;
136                case 'e':               /* undocumented in od */
137                case 'F':
138                        odformat(globals, "fD");
139                        break;
140                case 'f':
141                        odformat(globals, "fF");
142                        break;
143                case 'H':
144                case 'X':
145                        odformat(globals, "x4");
146                        break;
147                case 'h':
148                case 'x':
149                        odformat(globals, "x2");
150                        break;
151                case 'I':
152                case 'L':
153                case 'l':
154                        odformat(globals, "dL");
155                        break;
156                case 'i':
157                        odformat(globals, "dI");
158                        break;
159                case 'j':
160                        errno = 0;
161                        skip = strtoll(optarg, &end, 0);
162                        if (*end == 'b')
163                                skip *= 512;
164                        else if (*end == 'k')
165                                skip *= 1024;
166                        else if (*end == 'm')
167                                skip *= 1048576L;
168                        if (errno != 0 || skip < 0 || strlen(end) > 1)
169                                errx(exit_jump, 1, "%s: invalid skip amount", optarg);
170                        break;
171                case 'N':
172                        if ((length = atoi(optarg)) <= 0)
173                                errx(exit_jump, 1, "%s: invalid length", optarg);
174                        break;
175                case 'O':
176                        odformat(globals, "o4");
177                        break;
178                case 's':
179                        odformat(globals, "d2");
180                        break;
181                case 't':
182                        odformat(globals, optarg);
183                        break;
184                case 'v':
185                        vflag = ALL;
186                        break;
187                case '?':
188                default:
189                        odusage(globals);
190                }
191
192        if (fshead->nextfs->nextfs == NULL)
193                odformat(globals, "oS");
194
195        argc -= getopt_reent.optind;
196        *argvp += getopt_reent.optind;
197
198        if (argc)
199                odoffset(globals, argc, argvp);
200}
201
202static void
203odusage(rtems_shell_hexdump_globals* globals)
204{
205
206        fprintf(stderr,
207"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n");
208        fprintf(stderr,
209"          [[+]offset[.][Bb]] [file ...]\n");
210        exit(1);
211}
212
213static void
214odoffset(rtems_shell_hexdump_globals* globals, int argc, char ***argvp)
215{
216        char *p, *num, *end;
217        int base;
218
219        /*
220         * The offset syntax of od(1) was genuinely bizarre.  First, if
221         * it started with a plus it had to be an offset.  Otherwise, if
222         * there were at least two arguments, a number or lower-case 'x'
223         * followed by a number makes it an offset.  By default it was
224         * octal; if it started with 'x' or '0x' it was hex.  If it ended
225         * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
226         * multiplied the number by 512 or 1024 byte units.  There was
227         * no way to assign a block count to a hex offset.
228         *
229         * We assume it's a file if the offset is bad.
230         */
231        p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
232
233        if (*p != '+' && (argc < 2 ||
234            (!isdigit((unsigned char)p[0]) && (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
235                return;
236
237        base = 0;
238        /*
239         * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
240         * set base.
241         */
242        if (p[0] == '+')
243                ++p;
244        if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
245                ++p;
246                base = 16;
247        } else if (p[0] == '0' && p[1] == 'x') {
248                p += 2;
249                base = 16;
250        }
251
252        /* skip over the number */
253        if (base == 16)
254                for (num = p; isxdigit((unsigned char)*p); ++p);
255        else
256                for (num = p; isdigit((unsigned char)*p); ++p);
257
258        /* check for no number */
259        if (num == p)
260                return;
261
262        /* if terminates with a '.', base is decimal */
263        if (*p == '.') {
264                if (base)
265                        return;
266                base = 10;
267        }
268
269        skip = strtoll(num, &end, base ? base : 8);
270
271        /* if end isn't the same as p, we got a non-octal digit */
272        if (end != p) {
273                skip = 0;
274                return;
275        }
276
277        if (*p) {
278                if (*p == 'B') {
279                        skip *= 1024;
280                        ++p;
281                } else if (*p == 'b') {
282                        skip *= 512;
283                        ++p;
284                }
285        }
286
287        if (*p) {
288                skip = 0;
289                return;
290        }
291
292        /*
293         * If the offset uses a non-octal base, the base of the offset
294         * is changed as well.  This isn't pretty, but it's easy.
295         */
296        if (base == 16) {
297                fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
298                fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
299        } else if (base == 10) {
300                fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
301                fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
302        }
303
304        /* Terminate file list. */
305        (*argvp)[1] = NULL;
306}
307
308static void
309odformat(rtems_shell_hexdump_globals* globals, const char *fmt)
310{
311        char fchar;
312
313        while (*fmt != '\0') {
314                switch ((fchar = *fmt++)) {
315                case 'a':
316                        odadd(globals, "16/1 \"%3_u \" \"\\n\"");
317                        break;
318                case 'c':
319                        odadd(globals, "16/1 \"%3_c \" \"\\n\"");
320                        break;
321                case 'o': case 'u': case 'd': case 'x':
322                        fmt = odformatint(globals, fchar, fmt);
323                        break;
324                case 'f':
325                        fmt = odformatfp(globals, fchar, fmt);
326                        break;
327                default:
328                        errx(exit_jump, 1, "%c: unrecognised format character", fchar);
329                }
330        }
331}
332
333static const char *
334odformatfp(rtems_shell_hexdump_globals* globals, char fchar __unused, const char *fmt)
335{
336        size_t isize;
337        int digits;
338        char *end, *hdfmt;
339
340        isize = sizeof(double);
341        switch (*fmt) {
342        case 'F':
343                isize = sizeof(float);
344                fmt++;
345                break;
346        case 'D':
347                isize = sizeof(double);
348                fmt++;
349                break;
350        case 'L':
351                isize = sizeof(long double);
352                fmt++;
353                break;
354        default:
355                if (isdigit((unsigned char)*fmt)) {
356                        errno = 0;
357                        isize = (size_t)strtoul(fmt, &end, 10);
358                        if (errno != 0 || isize == 0)
359                                errx(exit_jump, 1, "%s: invalid size", fmt);
360                        fmt = (const char *)end;
361                }
362        }
363        if (isize == sizeof(float) ) {
364                digits = FLT_DIG;
365        } else if (isize == sizeof(double)) {
366                digits = DBL_DIG;
367        } else if (isize == sizeof(long double)) {
368                digits = LDBL_DIG;
369        } else {
370                errx(exit_jump, 1, "unsupported floating point size %zu",
371                        isize);
372        }
373
374        asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"",
375            16UL / (u_long)isize, (u_long)isize, digits + 8, digits);
376        if (hdfmt == NULL)
377                err(exit_jump, 1, NULL);
378        odadd(globals, hdfmt);
379        free(hdfmt);
380
381        return (fmt);
382}
383
384static const char *
385odformatint(rtems_shell_hexdump_globals* globals, char fchar, const char *fmt)
386{
387        unsigned long long n;
388        size_t isize;
389        int digits;
390        char *end, *hdfmt;
391
392        isize = sizeof(int);
393        switch (*fmt) {
394        case 'C':
395                isize = sizeof(char);
396                fmt++;
397                break;
398        case 'I':
399                isize = sizeof(int);
400                fmt++;
401                break;
402        case 'L':
403                isize = sizeof(long);
404                fmt++;
405                break;
406        case 'S':
407                isize = sizeof(short);
408                fmt++;
409                break;
410        default:
411                if (isdigit((unsigned char)*fmt)) {
412                        errno = 0;
413                        isize = (size_t)strtoul(fmt, &end, 10);
414                        if (errno != 0 || isize == 0)
415                                errx(exit_jump, 1, "%s: invalid size", fmt);
416                        if (isize != sizeof(char) && isize != sizeof(short) &&
417                            isize != sizeof(int) && isize != sizeof(long))
418                                errx(exit_jump, 1, "unsupported int size %lu",
419                                    (u_long)isize);
420                        fmt = (const char *)end;
421                }
422        }
423
424        /*
425         * Calculate the maximum number of digits we need to
426         * fit the number. Overestimate for decimal with log
427         * base 8. We need one extra space for signed numbers
428         * to store the sign.
429         */
430        n = (1ULL << (8 * isize)) - 1;
431        digits = 0;
432        while (n != 0) {
433                digits++;
434                n >>= (fchar == 'x') ? 4 : 3;
435        }
436        if (fchar == 'd')
437                digits++;
438        asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"",
439            16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits),
440            "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar);
441        if (hdfmt == NULL)
442                err(exit_jump, 1, NULL);
443        odadd(globals, hdfmt);
444        free(hdfmt);
445
446        return (fmt);
447}
448
449static void
450odadd(rtems_shell_hexdump_globals* globals, const char *fmt)
451{
452        static int needpad;
453
454        if (needpad)
455                add(globals, "\""PADDING"\"");
456        add(globals, fmt);
457        needpad = 1;
458}
Note: See TracBrowser for help on using the repository browser.