odsyntax.c revision 102944
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3527315Scharnier#if 0 3623693Speterstatic char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95"; 3727315Scharnier#endif 381590Srgrimes#endif /* not lint */ 3999112Sobrien#include <sys/cdefs.h> 4099112Sobrien__FBSDID("$FreeBSD: head/usr.bin/hexdump/odsyntax.c 102944 2002-09-04 23:29:10Z dwmalone $"); 411590Srgrimes 421590Srgrimes#include <sys/types.h> 431590Srgrimes 4423693Speter#include <ctype.h> 4527315Scharnier#include <err.h> 4696795Stjr#include <errno.h> 4796795Stjr#include <float.h> 4823693Speter#include <stdio.h> 491590Srgrimes#include <stdlib.h> 5096795Stjr#include <string.h> 5123693Speter#include <unistd.h> 5223693Speter 531590Srgrimes#include "hexdump.h" 541590Srgrimes 5596795Stjr#define PADDING " " 5696795Stjr 5796787Stjrint odmode; 581590Srgrimes 5996795Stjrstatic void odadd(const char *); 6096795Stjrstatic void odformat(const char *); 6196795Stjrstatic const char *odformatfp(char, const char *); 6296795Stjrstatic const char *odformatint(char, const char *); 6392920Simpstatic void odoffset(int, char ***); 6496795Stjrstatic void odusage(void); 651590Srgrimes 661590Srgrimesvoid 67102944Sdwmaloneoldsyntax(int argc, char ***argvp) 681590Srgrimes{ 6996795Stjr static char empty[] = "", padding[] = PADDING; 701590Srgrimes int ch; 7196795Stjr char **argv, *end; 721590Srgrimes 7396795Stjr /* Add initial (default) address format. -A may change it later. */ 7496795Stjr#define TYPE_OFFSET 7 7596795Stjr add("\"%07.7_Ao\n\""); 7696795Stjr add("\"%07.7_ao \""); 7796795Stjr 7896787Stjr odmode = 1; 791590Srgrimes argv = *argvp; 8096795Stjr while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1) 811590Srgrimes switch (ch) { 8296795Stjr case 'A': 8396795Stjr switch (*optarg) { 8496795Stjr case 'd': case 'o': case 'x': 8596795Stjr fshead->nextfu->fmt[TYPE_OFFSET] = *optarg; 8696795Stjr fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 8796795Stjr *optarg; 8896795Stjr break; 8996795Stjr case 'n': 9096795Stjr fshead->nextfu->fmt = empty; 9196795Stjr fshead->nextfs->nextfu->fmt = padding; 9296795Stjr break; 9396795Stjr default: 9496795Stjr errx(1, "%s: invalid address base", optarg); 9596795Stjr } 9696795Stjr break; 971590Srgrimes case 'a': 9896795Stjr odformat("a"); 991590Srgrimes break; 1001590Srgrimes case 'B': 1011590Srgrimes case 'o': 10296795Stjr odformat("o2"); 1031590Srgrimes break; 1041590Srgrimes case 'b': 10596795Stjr odformat("o1"); 1061590Srgrimes break; 1071590Srgrimes case 'c': 10896795Stjr odformat("c"); 1091590Srgrimes break; 1101590Srgrimes case 'd': 11196795Stjr odformat("u2"); 1121590Srgrimes break; 1131590Srgrimes case 'D': 11496795Stjr odformat("u4"); 1151590Srgrimes break; 1161590Srgrimes case 'e': /* undocumented in od */ 1171590Srgrimes case 'F': 11896795Stjr odformat("fD"); 1191590Srgrimes break; 1201590Srgrimes case 'f': 12196795Stjr odformat("fF"); 1221590Srgrimes break; 1231590Srgrimes case 'H': 1241590Srgrimes case 'X': 12596795Stjr odformat("x4"); 1261590Srgrimes break; 1271590Srgrimes case 'h': 1281590Srgrimes case 'x': 12996795Stjr odformat("x2"); 1301590Srgrimes break; 1311590Srgrimes case 'I': 1321590Srgrimes case 'L': 1331590Srgrimes case 'l': 13496795Stjr odformat("dL"); 1351590Srgrimes break; 1361590Srgrimes case 'i': 13796795Stjr odformat("dI"); 1381590Srgrimes break; 13996795Stjr case 'j': 14096795Stjr errno = 0; 14196795Stjr skip = strtoll(optarg, &end, 0); 14296795Stjr if (*end == 'b') 14396795Stjr skip *= 512; 14496795Stjr else if (*end == 'k') 14596795Stjr skip *= 1024; 14696795Stjr else if (*end == 'm') 14796795Stjr skip *= 1048576L; 14896795Stjr if (errno != 0 || skip < 0 || strlen(end) > 1) 14996795Stjr errx(1, "%s: invalid skip amount", optarg); 15096795Stjr break; 15196795Stjr case 'N': 15296795Stjr if ((length = atoi(optarg)) <= 0) 15396795Stjr errx(1, "%s: invalid length", optarg); 15496795Stjr break; 1551590Srgrimes case 'O': 15696795Stjr odformat("o4"); 1571590Srgrimes break; 15896795Stjr case 's': 15996795Stjr odformat("d2"); 16096795Stjr break; 16196795Stjr case 't': 16296795Stjr odformat(optarg); 16396795Stjr break; 1641590Srgrimes case 'v': 1651590Srgrimes vflag = ALL; 1661590Srgrimes break; 1671590Srgrimes case '?': 1681590Srgrimes default: 16996795Stjr odusage(); 1701590Srgrimes } 1711590Srgrimes 17296795Stjr if (fshead->nextfs->nextfs == NULL) 17396795Stjr odformat("oS"); 1741590Srgrimes 1751590Srgrimes argc -= optind; 1761590Srgrimes *argvp += optind; 1771590Srgrimes 1781590Srgrimes if (argc) 1791590Srgrimes odoffset(argc, argvp); 1801590Srgrimes} 1811590Srgrimes 1821590Srgrimesstatic void 18396795Stjrodusage(void) 18496795Stjr{ 18596795Stjr 18696795Stjr fprintf(stderr, 18796795Stjr"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n"); 18896795Stjr fprintf(stderr, 18996795Stjr" [[+]offset[.][Bb]] [file ...]\n"); 19096795Stjr exit(1); 19196795Stjr} 19296795Stjr 19396795Stjrstatic void 194102944Sdwmaloneodoffset(int argc, char ***argvp) 1951590Srgrimes{ 19630921Sache unsigned char *p, *num, *end; 1971590Srgrimes int base; 1981590Srgrimes 1991590Srgrimes /* 2001590Srgrimes * The offset syntax of od(1) was genuinely bizarre. First, if 2011590Srgrimes * it started with a plus it had to be an offset. Otherwise, if 2021590Srgrimes * there were at least two arguments, a number or lower-case 'x' 2031590Srgrimes * followed by a number makes it an offset. By default it was 2041590Srgrimes * octal; if it started with 'x' or '0x' it was hex. If it ended 2051590Srgrimes * in a '.', it was decimal. If a 'b' or 'B' was appended, it 2061590Srgrimes * multiplied the number by 512 or 1024 byte units. There was 2071590Srgrimes * no way to assign a block count to a hex offset. 2081590Srgrimes * 2091590Srgrimes * We assume it's a file if the offset is bad. 2101590Srgrimes */ 2111590Srgrimes p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; 2121590Srgrimes 2131590Srgrimes if (*p != '+' && (argc < 2 || 2141590Srgrimes (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1]))))) 2151590Srgrimes return; 2161590Srgrimes 2171590Srgrimes base = 0; 2181590Srgrimes /* 2191590Srgrimes * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and 2201590Srgrimes * set base. 2211590Srgrimes */ 2221590Srgrimes if (p[0] == '+') 2231590Srgrimes ++p; 2241590Srgrimes if (p[0] == 'x' && isxdigit(p[1])) { 2251590Srgrimes ++p; 2261590Srgrimes base = 16; 2271590Srgrimes } else if (p[0] == '0' && p[1] == 'x') { 2281590Srgrimes p += 2; 2291590Srgrimes base = 16; 2301590Srgrimes } 2311590Srgrimes 2321590Srgrimes /* skip over the number */ 2331590Srgrimes if (base == 16) 2341590Srgrimes for (num = p; isxdigit(*p); ++p); 2351590Srgrimes else 2361590Srgrimes for (num = p; isdigit(*p); ++p); 2371590Srgrimes 2381590Srgrimes /* check for no number */ 2391590Srgrimes if (num == p) 2401590Srgrimes return; 2411590Srgrimes 2421590Srgrimes /* if terminates with a '.', base is decimal */ 2431590Srgrimes if (*p == '.') { 2441590Srgrimes if (base) 2451590Srgrimes return; 2461590Srgrimes base = 10; 2471590Srgrimes } 2481590Srgrimes 24982766Sache skip = strtoll(num, (char **)&end, base ? base : 8); 2501590Srgrimes 2511590Srgrimes /* if end isn't the same as p, we got a non-octal digit */ 2521590Srgrimes if (end != p) { 2531590Srgrimes skip = 0; 2541590Srgrimes return; 2551590Srgrimes } 2561590Srgrimes 25748566Sbillf if (*p) { 2581590Srgrimes if (*p == 'B') { 2591590Srgrimes skip *= 1024; 2601590Srgrimes ++p; 2611590Srgrimes } else if (*p == 'b') { 2621590Srgrimes skip *= 512; 2631590Srgrimes ++p; 2641590Srgrimes } 26548566Sbillf } 2661590Srgrimes 2671590Srgrimes if (*p) { 2681590Srgrimes skip = 0; 2691590Srgrimes return; 2701590Srgrimes } 2711590Srgrimes 2721590Srgrimes /* 2731590Srgrimes * If the offset uses a non-octal base, the base of the offset 2741590Srgrimes * is changed as well. This isn't pretty, but it's easy. 2751590Srgrimes */ 2761590Srgrimes if (base == 16) { 2771590Srgrimes fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; 2781590Srgrimes fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; 2791590Srgrimes } else if (base == 10) { 2801590Srgrimes fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; 2811590Srgrimes fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; 2821590Srgrimes } 2831590Srgrimes 2841590Srgrimes /* Terminate file list. */ 2851590Srgrimes (*argvp)[1] = NULL; 2861590Srgrimes} 2871590Srgrimes 2881590Srgrimesstatic void 28996795Stjrodformat(const char *fmt) 2901590Srgrimes{ 29196795Stjr char fchar; 2921590Srgrimes 29396795Stjr while (*fmt != '\0') { 29496795Stjr switch ((fchar = *fmt++)) { 29596795Stjr case 'a': 29696795Stjr odadd("16/1 \"%3_u \" \"\\n\""); 29796795Stjr break; 29896795Stjr case 'c': 29996795Stjr odadd("16/1 \"%3_c \" \"\\n\""); 30096795Stjr break; 30196795Stjr case 'o': case 'u': case 'd': case 'x': 30296795Stjr fmt = odformatint(fchar, fmt); 30396795Stjr break; 30496795Stjr case 'f': 30596795Stjr fmt = odformatfp(fchar, fmt); 30696795Stjr break; 30796795Stjr default: 30896795Stjr errx(1, "%c: unrecognised format character", fchar); 30996795Stjr } 31096795Stjr } 3111590Srgrimes} 31296795Stjr 31396795Stjrstatic const char * 31496795Stjrodformatfp(char fchar __unused, const char *fmt) 31596795Stjr{ 31696795Stjr size_t isize; 31796795Stjr int digits; 31896795Stjr char *end, *hdfmt; 31996795Stjr 32096795Stjr isize = sizeof(double); 32196795Stjr switch (*fmt) { 32296795Stjr case 'F': 32396795Stjr isize = sizeof(float); 32496795Stjr fmt++; 32596795Stjr break; 32696795Stjr case 'D': 32796795Stjr isize = sizeof(double); 32896795Stjr fmt++; 32996795Stjr break; 33096795Stjr case 'L': 33196795Stjr isize = sizeof(long double); 33296795Stjr fmt++; 33396795Stjr break; 33496795Stjr default: 33596795Stjr if (isdigit((unsigned char)*fmt)) { 33696795Stjr errno = 0; 33796795Stjr isize = (size_t)strtoul(fmt, &end, 10); 33896795Stjr if (errno != 0 || isize == 0) 33996795Stjr errx(1, "%s: invalid size", fmt); 34096795Stjr fmt = (const char *)end; 34196795Stjr } 34296795Stjr } 34396795Stjr switch (isize) { 34496795Stjr case sizeof(float): 34596795Stjr digits = FLT_DIG; 34696795Stjr break; 34796795Stjr case sizeof(double): 34896795Stjr digits = DBL_DIG; 34996795Stjr break; 35096795Stjr default: 35196795Stjr if (isize == sizeof(long double)) 35296795Stjr digits = LDBL_DIG; 35396795Stjr else 35496795Stjr errx(1, "unsupported floating point size %lu", 35596795Stjr (u_long)isize); 35696795Stjr } 35796795Stjr 35896795Stjr asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"", 35996795Stjr 16UL / (u_long)isize, (u_long)isize, digits + 8, digits); 36096795Stjr if (hdfmt == NULL) 36196795Stjr err(1, NULL); 36296795Stjr odadd(hdfmt); 36396795Stjr free(hdfmt); 36496795Stjr 36596795Stjr return (fmt); 36696795Stjr} 36796795Stjr 36896795Stjrstatic const char * 36996795Stjrodformatint(char fchar, const char *fmt) 37096795Stjr{ 37196795Stjr unsigned long long n; 37296795Stjr size_t isize; 37396795Stjr int digits; 37496795Stjr char *end, *hdfmt; 37596795Stjr 37696795Stjr isize = sizeof(int); 37796795Stjr switch (*fmt) { 37896795Stjr case 'C': 37996795Stjr isize = sizeof(char); 38096795Stjr fmt++; 38196795Stjr break; 38296795Stjr case 'I': 38396795Stjr isize = sizeof(int); 38496795Stjr fmt++; 38596795Stjr break; 38696795Stjr case 'L': 38796795Stjr isize = sizeof(long); 38896795Stjr fmt++; 38996795Stjr break; 39096795Stjr case 'S': 39196795Stjr isize = sizeof(short); 39296795Stjr fmt++; 39396795Stjr break; 39496795Stjr default: 39596795Stjr if (isdigit((unsigned char)*fmt)) { 39696795Stjr errno = 0; 39796795Stjr isize = (size_t)strtoul(fmt, &end, 10); 39896795Stjr if (errno != 0 || isize == 0) 39996795Stjr errx(1, "%s: invalid size", fmt); 40096795Stjr if (isize != sizeof(char) && isize != sizeof(short) && 40196795Stjr isize != sizeof(int) && isize != sizeof(long)) 40296795Stjr errx(1, "unsupported int size %lu", 40396795Stjr (u_long)isize); 40496795Stjr fmt = (const char *)end; 40596795Stjr } 40696795Stjr } 40796795Stjr 40896795Stjr /* 40996795Stjr * Calculate the maximum number of digits we need to 41096795Stjr * fit the number. Overestimate for decimal with log 41196795Stjr * base 8. We need one extra space for signed numbers 41296795Stjr * to store the sign. 41396795Stjr */ 41496795Stjr n = (1ULL << (8 * isize)) - 1; 41596795Stjr digits = 0; 41696795Stjr while (n != 0) { 41796795Stjr digits++; 41896795Stjr n >>= (fchar == 'x') ? 4 : 3; 41996795Stjr } 42096795Stjr if (fchar == 'd') 42196795Stjr digits++; 42296798Stjr asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"", 42396798Stjr 16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits), 42496798Stjr "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar); 42596795Stjr if (hdfmt == NULL) 42696795Stjr err(1, NULL); 42796795Stjr odadd(hdfmt); 42896795Stjr free(hdfmt); 42996795Stjr 43096795Stjr return (fmt); 43196795Stjr} 43296795Stjr 43396795Stjrstatic void 43496795Stjrodadd(const char *fmt) 43596795Stjr{ 43696795Stjr static int needpad; 43796795Stjr 43896795Stjr if (needpad) 43996795Stjr add("\""PADDING"\""); 44096795Stjr add(fmt); 44196795Stjr needpad = 1; 44296795Stjr} 443