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

5
Last change on this file since f97536d was f97536d, checked in by Sebastian Huber <sebastian.huber@…>, on 10/16/15 at 06:21:48

basdefs.h: Add and use RTEMS_UNUSED

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