Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /*-
0002  * Copyright (c) 1990, 1993
0003  *  The Regents of the University of California.  All rights reserved.
0004  *
0005  * Redistribution and use in source and binary forms, with or without
0006  * modification, are permitted provided that the following conditions
0007  * are met:
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  * 3. All advertising materials mentioning features or use of this software
0014  *    must display the following acknowledgement:
0015  *  This product includes software developed by the University of
0016  *  California, Berkeley and its contributors.
0017  * 4. Neither the name of the University nor the names of its contributors
0018  *    may be used to endorse or promote products derived from this software
0019  *    without specific prior written permission.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0031  * SUCH DAMAGE.
0032  */
0033 
0034 #ifdef __rtems__
0035 /* For asprintf() visibility */
0036 #define _GNU_SOURCE
0037 #endif /* __rtems__ */
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #ifndef lint
0043 #if 0
0044 static char sccsid[] = "@(#)odsyntax.c  8.2 (Berkeley) 5/4/95";
0045 #endif /* not lint */
0046 #include <sys/cdefs.h>
0047 __FBSDID("$FreeBSD: src/usr.bin/hexdump/odsyntax.c,v 1.17 2004/07/22 13:14:42 johan Exp $");
0048 #endif
0049 
0050 #include <sys/types.h>
0051 
0052 #include <ctype.h>
0053 #include "err.h"
0054 #include <errno.h>
0055 #include <float.h>
0056 #include <stdio.h>
0057 #include <stdlib.h>
0058 #include <string.h>
0059 #include <unistd.h>
0060 
0061 #include "hexdump.h"
0062 
0063 #define __need_getopt_newlib
0064 #include <getopt.h>
0065 
0066 #define PADDING "         "
0067 
0068 #ifndef __unused
0069 #define __unused RTEMS_UNUSED
0070 #endif
0071 
0072 #if RTEMS_REMOVED
0073 int odmode;
0074 #endif
0075 
0076 static void odadd(rtems_shell_hexdump_globals*, const char *);
0077 static void odformat(rtems_shell_hexdump_globals*, const char *);
0078 static const char *odformatfp(rtems_shell_hexdump_globals*, char, const char *);
0079 static const char *odformatint(rtems_shell_hexdump_globals*, char, const char *);
0080 static void odoffset(rtems_shell_hexdump_globals*, int, char ***);
0081 static void odusage(rtems_shell_hexdump_globals*);
0082 
0083 void
0084 oldsyntax(rtems_shell_hexdump_globals* globals, int argc, char ***argvp)
0085 {
0086     static char empty[] = "", padding[] = PADDING;
0087     int ch;
0088     char **argv, *end;
0089 
0090   struct getopt_data getopt_reent;
0091   memset(&getopt_reent, 0, sizeof(getopt_data));
0092 
0093     /* Add initial (default) address format. -A may change it later. */
0094 #define TYPE_OFFSET 7
0095     add(globals, "\"%07.7_Ao\n\"");
0096     add(globals, "\"%07.7_ao  \"");
0097 
0098     odmode = 1;
0099     argv = *argvp;
0100     while ((ch = getopt_r(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx", &getopt_reent)) != -1)
0101         switch (ch) {
0102         case 'A':
0103             switch (*optarg) {
0104             case 'd': case 'o': case 'x':
0105                 fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
0106                 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
0107                     *optarg;
0108                 break;
0109             case 'n':
0110                 fshead->nextfu->fmt = empty;
0111                 fshead->nextfs->nextfu->fmt = padding;
0112                 break;
0113             default:
0114                 errx(exit_jump, 1, "%s: invalid address base", optarg);
0115             }
0116             break;
0117         case 'a':
0118             odformat(globals, "a");
0119             break;
0120         case 'B':
0121         case 'o':
0122             odformat(globals, "o2");
0123             break;
0124         case 'b':
0125             odformat(globals, "o1");
0126             break;
0127         case 'c':
0128             odformat(globals, "c");
0129             break;
0130         case 'd':
0131             odformat(globals, "u2");
0132             break;
0133         case 'D':
0134             odformat(globals, "u4");
0135             break;
0136         case 'e':       /* undocumented in od */
0137         case 'F':
0138             odformat(globals, "fD");
0139             break;
0140         case 'f':
0141             odformat(globals, "fF");
0142             break;
0143         case 'H':
0144         case 'X':
0145             odformat(globals, "x4");
0146             break;
0147         case 'h':
0148         case 'x':
0149             odformat(globals, "x2");
0150             break;
0151         case 'I':
0152         case 'L':
0153         case 'l':
0154             odformat(globals, "dL");
0155             break;
0156         case 'i':
0157             odformat(globals, "dI");
0158             break;
0159         case 'j':
0160             errno = 0;
0161             skip = strtoll(optarg, &end, 0);
0162             if (*end == 'b')
0163                 skip *= 512;
0164             else if (*end == 'k')
0165                 skip *= 1024;
0166             else if (*end == 'm')
0167                 skip *= 1048576L;
0168             if (errno != 0 || skip < 0 || strlen(end) > 1)
0169                 errx(exit_jump, 1, "%s: invalid skip amount", optarg);
0170             break;
0171         case 'N':
0172             if ((length = atoi(optarg)) <= 0)
0173                 errx(exit_jump, 1, "%s: invalid length", optarg);
0174             break;
0175         case 'O':
0176             odformat(globals, "o4");
0177             break;
0178         case 's':
0179             odformat(globals, "d2");
0180             break;
0181         case 't':
0182             odformat(globals, optarg);
0183             break;
0184         case 'v':
0185             vflag = ALL;
0186             break;
0187         case '?':
0188         default:
0189             odusage(globals);
0190         }
0191 
0192     if (fshead->nextfs->nextfs == NULL)
0193         odformat(globals, "oS");
0194 
0195     argc -= getopt_reent.optind;
0196     *argvp += getopt_reent.optind;
0197 
0198     if (argc)
0199         odoffset(globals, argc, argvp);
0200 }
0201 
0202 static void
0203 odusage(rtems_shell_hexdump_globals* globals)
0204 {
0205 
0206     fprintf(stderr,
0207 "usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n");
0208     fprintf(stderr,
0209 "          [[+]offset[.][Bb]] [file ...]\n");
0210     exit(1);
0211 }
0212 
0213 static void
0214 odoffset(rtems_shell_hexdump_globals* globals, int argc, char ***argvp)
0215 {
0216     char *p, *num, *end;
0217     int base;
0218 
0219     /*
0220      * The offset syntax of od(1) was genuinely bizarre.  First, if
0221      * it started with a plus it had to be an offset.  Otherwise, if
0222      * there were at least two arguments, a number or lower-case 'x'
0223      * followed by a number makes it an offset.  By default it was
0224      * octal; if it started with 'x' or '0x' it was hex.  If it ended
0225      * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
0226      * multiplied the number by 512 or 1024 byte units.  There was
0227      * no way to assign a block count to a hex offset.
0228      *
0229      * We assume it's a file if the offset is bad.
0230      */
0231     p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
0232 
0233     if (*p != '+' && (argc < 2 ||
0234         (!isdigit((unsigned char)p[0]) && (p[0] != 'x' || !isxdigit((unsigned char)p[1])))))
0235         return;
0236 
0237     base = 0;
0238     /*
0239      * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
0240      * set base.
0241      */
0242     if (p[0] == '+')
0243         ++p;
0244     if (p[0] == 'x' && isxdigit((unsigned char)p[1])) {
0245         ++p;
0246         base = 16;
0247     } else if (p[0] == '0' && p[1] == 'x') {
0248         p += 2;
0249         base = 16;
0250     }
0251 
0252     /* skip over the number */
0253     if (base == 16)
0254         for (num = p; isxdigit((unsigned char)*p); ++p);
0255     else
0256         for (num = p; isdigit((unsigned char)*p); ++p);
0257 
0258     /* check for no number */
0259     if (num == p)
0260         return;
0261 
0262     /* if terminates with a '.', base is decimal */
0263     if (*p == '.') {
0264         if (base)
0265             return;
0266         base = 10;
0267     }
0268 
0269     skip = strtoll(num, &end, base ? base : 8);
0270 
0271     /* if end isn't the same as p, we got a non-octal digit */
0272     if (end != p) {
0273         skip = 0;
0274         return;
0275     }
0276 
0277     if (*p) {
0278         if (*p == 'B') {
0279             skip *= 1024;
0280             ++p;
0281         } else if (*p == 'b') {
0282             skip *= 512;
0283             ++p;
0284         }
0285     }
0286 
0287     if (*p) {
0288         skip = 0;
0289         return;
0290     }
0291 
0292     /*
0293      * If the offset uses a non-octal base, the base of the offset
0294      * is changed as well.  This isn't pretty, but it's easy.
0295      */
0296     if (base == 16) {
0297         fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
0298         fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
0299     } else if (base == 10) {
0300         fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
0301         fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
0302     }
0303 
0304     /* Terminate file list. */
0305     (*argvp)[1] = NULL;
0306 }
0307 
0308 static void
0309 odformat(rtems_shell_hexdump_globals* globals, const char *fmt)
0310 {
0311     char fchar;
0312 
0313     while (*fmt != '\0') {
0314         switch ((fchar = *fmt++)) {
0315         case 'a':
0316             odadd(globals, "16/1 \"%3_u \" \"\\n\"");
0317             break;
0318         case 'c':
0319             odadd(globals, "16/1 \"%3_c \" \"\\n\"");
0320             break;
0321         case 'o': case 'u': case 'd': case 'x':
0322             fmt = odformatint(globals, fchar, fmt);
0323             break;
0324         case 'f':
0325             fmt = odformatfp(globals, fchar, fmt);
0326             break;
0327         default:
0328             errx(exit_jump, 1, "%c: unrecognised format character", fchar);
0329         }
0330     }
0331 }
0332 
0333 static const char *
0334 odformatfp(rtems_shell_hexdump_globals* globals, char fchar __unused, const char *fmt)
0335 {
0336     size_t isize;
0337     int digits;
0338     char *end, *hdfmt;
0339 
0340     isize = sizeof(double);
0341     switch (*fmt) {
0342     case 'F':
0343         isize = sizeof(float);
0344         fmt++;
0345         break;
0346     case 'D':
0347         isize = sizeof(double);
0348         fmt++;
0349         break;
0350     case 'L':
0351         isize = sizeof(long double);
0352         fmt++;
0353         break;
0354     default:
0355         if (isdigit((unsigned char)*fmt)) {
0356             errno = 0;
0357             isize = (size_t)strtoul(fmt, &end, 10);
0358             if (errno != 0 || isize == 0)
0359                 errx(exit_jump, 1, "%s: invalid size", fmt);
0360             fmt = (const char *)end;
0361         }
0362     }
0363     if (isize == sizeof(float) ) {
0364         digits = FLT_DIG;
0365         } else if (isize == sizeof(double)) {
0366         digits = DBL_DIG;
0367         } else if (isize == sizeof(long double)) {
0368         digits = LDBL_DIG;
0369         } else {
0370             errx(exit_jump, 1, "unsupported floating point size %zu",
0371                 isize);
0372     }
0373 
0374     asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"",
0375         16UL / (u_long)isize, (u_long)isize, digits + 8, digits);
0376     if (hdfmt == NULL)
0377         err(exit_jump, 1, NULL);
0378     odadd(globals, hdfmt);
0379     free(hdfmt);
0380 
0381     return (fmt);
0382 }
0383 
0384 static const char *
0385 odformatint(rtems_shell_hexdump_globals* globals, char fchar, const char *fmt)
0386 {
0387     unsigned long long n;
0388     size_t isize;
0389     int digits;
0390     char *end, *hdfmt;
0391 
0392     isize = sizeof(int);
0393     switch (*fmt) {
0394     case 'C':
0395         isize = sizeof(char);
0396         fmt++;
0397         break;
0398     case 'I':
0399         isize = sizeof(int);
0400         fmt++;
0401         break;
0402     case 'L':
0403         isize = sizeof(long);
0404         fmt++;
0405         break;
0406     case 'S':
0407         isize = sizeof(short);
0408         fmt++;
0409         break;
0410     default:
0411         if (isdigit((unsigned char)*fmt)) {
0412             errno = 0;
0413             isize = (size_t)strtoul(fmt, &end, 10);
0414             if (errno != 0 || isize == 0)
0415                 errx(exit_jump, 1, "%s: invalid size", fmt);
0416             if (isize != sizeof(char) && isize != sizeof(short) &&
0417                 isize != sizeof(int) && isize != sizeof(long))
0418                 errx(exit_jump, 1, "unsupported int size %lu",
0419                     (u_long)isize);
0420             fmt = (const char *)end;
0421         }
0422     }
0423 
0424     /*
0425      * Calculate the maximum number of digits we need to
0426      * fit the number. Overestimate for decimal with log
0427      * base 8. We need one extra space for signed numbers
0428      * to store the sign.
0429      */
0430     n = (1ULL << (8 * isize)) - 1;
0431     digits = 0;
0432     while (n != 0) {
0433         digits++;
0434         n >>= (fchar == 'x') ? 4 : 3;
0435     }
0436     if (fchar == 'd')
0437         digits++;
0438     asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"",
0439         16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits),
0440         "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar);
0441     if (hdfmt == NULL)
0442         err(exit_jump, 1, NULL);
0443     odadd(globals, hdfmt);
0444     free(hdfmt);
0445 
0446     return (fmt);
0447 }
0448 
0449 static void
0450 odadd(rtems_shell_hexdump_globals* globals, const char *fmt)
0451 {
0452     static int needpad;
0453 
0454     if (needpad)
0455         add(globals, "\""PADDING"\"");
0456     add(globals, fmt);
0457     needpad = 1;
0458 }