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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3127315Scharnier#if 0 3223693Speterstatic char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95"; 3327315Scharnier#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include <sys/types.h> 391590Srgrimes 4023693Speter#include <ctype.h> 4127315Scharnier#include <err.h> 4296795Stjr#include <errno.h> 4396795Stjr#include <float.h> 4423693Speter#include <stdio.h> 451590Srgrimes#include <stdlib.h> 4696795Stjr#include <string.h> 4723693Speter#include <unistd.h> 4823693Speter 491590Srgrimes#include "hexdump.h" 501590Srgrimes 5196795Stjr#define PADDING " " 5296795Stjr 5396787Stjrint odmode; 541590Srgrimes 5596795Stjrstatic void odadd(const char *); 5696795Stjrstatic void odformat(const char *); 5796795Stjrstatic const char *odformatfp(char, const char *); 5896795Stjrstatic const char *odformatint(char, const char *); 5992920Simpstatic void odoffset(int, char ***); 6096795Stjrstatic void odusage(void); 611590Srgrimes 621590Srgrimesvoid 63102944Sdwmaloneoldsyntax(int argc, char ***argvp) 641590Srgrimes{ 6596795Stjr static char empty[] = "", padding[] = PADDING; 661590Srgrimes int ch; 6796795Stjr char **argv, *end; 681590Srgrimes 6996795Stjr /* Add initial (default) address format. -A may change it later. */ 7096795Stjr#define TYPE_OFFSET 7 7196795Stjr add("\"%07.7_Ao\n\""); 7296795Stjr add("\"%07.7_ao \""); 7396795Stjr 7496787Stjr odmode = 1; 751590Srgrimes argv = *argvp; 7696795Stjr while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1) 771590Srgrimes switch (ch) { 7896795Stjr case 'A': 7996795Stjr switch (*optarg) { 8096795Stjr case 'd': case 'o': case 'x': 8196795Stjr fshead->nextfu->fmt[TYPE_OFFSET] = *optarg; 8296795Stjr fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 8396795Stjr *optarg; 8496795Stjr break; 8596795Stjr case 'n': 8696795Stjr fshead->nextfu->fmt = empty; 8796795Stjr fshead->nextfs->nextfu->fmt = padding; 8896795Stjr break; 8996795Stjr default: 9096795Stjr errx(1, "%s: invalid address base", optarg); 9196795Stjr } 9296795Stjr break; 931590Srgrimes case 'a': 9496795Stjr odformat("a"); 951590Srgrimes break; 961590Srgrimes case 'B': 971590Srgrimes case 'o': 9896795Stjr odformat("o2"); 991590Srgrimes break; 1001590Srgrimes case 'b': 10196795Stjr odformat("o1"); 1021590Srgrimes break; 1031590Srgrimes case 'c': 10496795Stjr odformat("c"); 1051590Srgrimes break; 1061590Srgrimes case 'd': 10796795Stjr odformat("u2"); 1081590Srgrimes break; 1091590Srgrimes case 'D': 11096795Stjr odformat("u4"); 1111590Srgrimes break; 1121590Srgrimes case 'e': /* undocumented in od */ 1131590Srgrimes case 'F': 11496795Stjr odformat("fD"); 1151590Srgrimes break; 1161590Srgrimes case 'f': 11796795Stjr odformat("fF"); 1181590Srgrimes break; 1191590Srgrimes case 'H': 1201590Srgrimes case 'X': 12196795Stjr odformat("x4"); 1221590Srgrimes break; 1231590Srgrimes case 'h': 1241590Srgrimes case 'x': 12596795Stjr odformat("x2"); 1261590Srgrimes break; 1271590Srgrimes case 'I': 1281590Srgrimes case 'L': 1291590Srgrimes case 'l': 13096795Stjr odformat("dL"); 1311590Srgrimes break; 1321590Srgrimes case 'i': 13396795Stjr odformat("dI"); 1341590Srgrimes break; 13596795Stjr case 'j': 13696795Stjr errno = 0; 13796795Stjr skip = strtoll(optarg, &end, 0); 13896795Stjr if (*end == 'b') 13996795Stjr skip *= 512; 14096795Stjr else if (*end == 'k') 14196795Stjr skip *= 1024; 14296795Stjr else if (*end == 'm') 14396795Stjr skip *= 1048576L; 14496795Stjr if (errno != 0 || skip < 0 || strlen(end) > 1) 14596795Stjr errx(1, "%s: invalid skip amount", optarg); 14696795Stjr break; 14796795Stjr case 'N': 14896795Stjr if ((length = atoi(optarg)) <= 0) 14996795Stjr errx(1, "%s: invalid length", optarg); 15096795Stjr break; 1511590Srgrimes case 'O': 15296795Stjr odformat("o4"); 1531590Srgrimes break; 15496795Stjr case 's': 15596795Stjr odformat("d2"); 15696795Stjr break; 15796795Stjr case 't': 15896795Stjr odformat(optarg); 15996795Stjr break; 1601590Srgrimes case 'v': 1611590Srgrimes vflag = ALL; 1621590Srgrimes break; 1631590Srgrimes case '?': 1641590Srgrimes default: 16596795Stjr odusage(); 1661590Srgrimes } 1671590Srgrimes 16896795Stjr if (fshead->nextfs->nextfs == NULL) 16996795Stjr odformat("oS"); 1701590Srgrimes 1711590Srgrimes argc -= optind; 1721590Srgrimes *argvp += optind; 1731590Srgrimes 1741590Srgrimes if (argc) 1751590Srgrimes odoffset(argc, argvp); 1761590Srgrimes} 1771590Srgrimes 1781590Srgrimesstatic void 17996795Stjrodusage(void) 18096795Stjr{ 18196795Stjr 18296795Stjr fprintf(stderr, 18396795Stjr"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n"); 18496795Stjr fprintf(stderr, 18596795Stjr" [[+]offset[.][Bb]] [file ...]\n"); 18696795Stjr exit(1); 18796795Stjr} 18896795Stjr 18996795Stjrstatic void 190102944Sdwmaloneodoffset(int argc, char ***argvp) 1911590Srgrimes{ 192132541Sjohan char *p, *num, *end; 1931590Srgrimes int base; 1941590Srgrimes 1951590Srgrimes /* 1961590Srgrimes * The offset syntax of od(1) was genuinely bizarre. First, if 1971590Srgrimes * it started with a plus it had to be an offset. Otherwise, if 1981590Srgrimes * there were at least two arguments, a number or lower-case 'x' 1991590Srgrimes * followed by a number makes it an offset. By default it was 2001590Srgrimes * octal; if it started with 'x' or '0x' it was hex. If it ended 2011590Srgrimes * in a '.', it was decimal. If a 'b' or 'B' was appended, it 2021590Srgrimes * multiplied the number by 512 or 1024 byte units. There was 2031590Srgrimes * no way to assign a block count to a hex offset. 2041590Srgrimes * 2051590Srgrimes * We assume it's a file if the offset is bad. 2061590Srgrimes */ 2071590Srgrimes p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; 2081590Srgrimes 2091590Srgrimes if (*p != '+' && (argc < 2 || 2101590Srgrimes (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1]))))) 2111590Srgrimes return; 2121590Srgrimes 2131590Srgrimes base = 0; 2141590Srgrimes /* 2151590Srgrimes * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and 2161590Srgrimes * set base. 2171590Srgrimes */ 2181590Srgrimes if (p[0] == '+') 2191590Srgrimes ++p; 2201590Srgrimes if (p[0] == 'x' && isxdigit(p[1])) { 2211590Srgrimes ++p; 2221590Srgrimes base = 16; 2231590Srgrimes } else if (p[0] == '0' && p[1] == 'x') { 2241590Srgrimes p += 2; 2251590Srgrimes base = 16; 2261590Srgrimes } 2271590Srgrimes 2281590Srgrimes /* skip over the number */ 2291590Srgrimes if (base == 16) 2301590Srgrimes for (num = p; isxdigit(*p); ++p); 2311590Srgrimes else 2321590Srgrimes for (num = p; isdigit(*p); ++p); 2331590Srgrimes 2341590Srgrimes /* check for no number */ 2351590Srgrimes if (num == p) 2361590Srgrimes return; 2371590Srgrimes 2381590Srgrimes /* if terminates with a '.', base is decimal */ 2391590Srgrimes if (*p == '.') { 2401590Srgrimes if (base) 2411590Srgrimes return; 2421590Srgrimes base = 10; 2431590Srgrimes } 2441590Srgrimes 245132541Sjohan skip = strtoll(num, &end, base ? base : 8); 2461590Srgrimes 2471590Srgrimes /* if end isn't the same as p, we got a non-octal digit */ 2481590Srgrimes if (end != p) { 2491590Srgrimes skip = 0; 2501590Srgrimes return; 2511590Srgrimes } 2521590Srgrimes 25348566Sbillf if (*p) { 2541590Srgrimes if (*p == 'B') { 2551590Srgrimes skip *= 1024; 2561590Srgrimes ++p; 2571590Srgrimes } else if (*p == 'b') { 2581590Srgrimes skip *= 512; 2591590Srgrimes ++p; 2601590Srgrimes } 26148566Sbillf } 2621590Srgrimes 2631590Srgrimes if (*p) { 2641590Srgrimes skip = 0; 2651590Srgrimes return; 2661590Srgrimes } 2671590Srgrimes 2681590Srgrimes /* 2691590Srgrimes * If the offset uses a non-octal base, the base of the offset 2701590Srgrimes * is changed as well. This isn't pretty, but it's easy. 2711590Srgrimes */ 2721590Srgrimes if (base == 16) { 2731590Srgrimes fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; 2741590Srgrimes fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; 2751590Srgrimes } else if (base == 10) { 2761590Srgrimes fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; 2771590Srgrimes fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; 2781590Srgrimes } 2791590Srgrimes 2801590Srgrimes /* Terminate file list. */ 2811590Srgrimes (*argvp)[1] = NULL; 2821590Srgrimes} 2831590Srgrimes 2841590Srgrimesstatic void 28596795Stjrodformat(const char *fmt) 2861590Srgrimes{ 28796795Stjr char fchar; 2881590Srgrimes 28996795Stjr while (*fmt != '\0') { 29096795Stjr switch ((fchar = *fmt++)) { 29196795Stjr case 'a': 29296795Stjr odadd("16/1 \"%3_u \" \"\\n\""); 29396795Stjr break; 29496795Stjr case 'c': 29596795Stjr odadd("16/1 \"%3_c \" \"\\n\""); 29696795Stjr break; 29796795Stjr case 'o': case 'u': case 'd': case 'x': 29896795Stjr fmt = odformatint(fchar, fmt); 29996795Stjr break; 30096795Stjr case 'f': 30196795Stjr fmt = odformatfp(fchar, fmt); 30296795Stjr break; 30396795Stjr default: 30496795Stjr errx(1, "%c: unrecognised format character", fchar); 30596795Stjr } 30696795Stjr } 3071590Srgrimes} 30896795Stjr 30996795Stjrstatic const char * 31096795Stjrodformatfp(char fchar __unused, const char *fmt) 31196795Stjr{ 31296795Stjr size_t isize; 31396795Stjr int digits; 31496795Stjr char *end, *hdfmt; 31596795Stjr 31696795Stjr isize = sizeof(double); 31796795Stjr switch (*fmt) { 31896795Stjr case 'F': 31996795Stjr isize = sizeof(float); 32096795Stjr fmt++; 32196795Stjr break; 32296795Stjr case 'D': 32396795Stjr isize = sizeof(double); 32496795Stjr fmt++; 32596795Stjr break; 32696795Stjr case 'L': 32796795Stjr isize = sizeof(long double); 32896795Stjr fmt++; 32996795Stjr break; 33096795Stjr default: 33196795Stjr if (isdigit((unsigned char)*fmt)) { 33296795Stjr errno = 0; 33396795Stjr isize = (size_t)strtoul(fmt, &end, 10); 33496795Stjr if (errno != 0 || isize == 0) 33596795Stjr errx(1, "%s: invalid size", fmt); 33696795Stjr fmt = (const char *)end; 33796795Stjr } 33896795Stjr } 33996795Stjr switch (isize) { 34096795Stjr case sizeof(float): 34196795Stjr digits = FLT_DIG; 34296795Stjr break; 34396795Stjr case sizeof(double): 34496795Stjr digits = DBL_DIG; 34596795Stjr break; 34696795Stjr default: 34796795Stjr if (isize == sizeof(long double)) 34896795Stjr digits = LDBL_DIG; 34996795Stjr else 35096795Stjr errx(1, "unsupported floating point size %lu", 35196795Stjr (u_long)isize); 35296795Stjr } 35396795Stjr 35496795Stjr asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"", 35596795Stjr 16UL / (u_long)isize, (u_long)isize, digits + 8, digits); 35696795Stjr if (hdfmt == NULL) 35796795Stjr err(1, NULL); 35896795Stjr odadd(hdfmt); 35996795Stjr free(hdfmt); 36096795Stjr 36196795Stjr return (fmt); 36296795Stjr} 36396795Stjr 36496795Stjrstatic const char * 36596795Stjrodformatint(char fchar, const char *fmt) 36696795Stjr{ 36796795Stjr unsigned long long n; 36896795Stjr size_t isize; 36996795Stjr int digits; 37096795Stjr char *end, *hdfmt; 37196795Stjr 37296795Stjr isize = sizeof(int); 37396795Stjr switch (*fmt) { 37496795Stjr case 'C': 37596795Stjr isize = sizeof(char); 37696795Stjr fmt++; 37796795Stjr break; 37896795Stjr case 'I': 37996795Stjr isize = sizeof(int); 38096795Stjr fmt++; 38196795Stjr break; 38296795Stjr case 'L': 38396795Stjr isize = sizeof(long); 38496795Stjr fmt++; 38596795Stjr break; 38696795Stjr case 'S': 38796795Stjr isize = sizeof(short); 38896795Stjr fmt++; 38996795Stjr break; 39096795Stjr default: 39196795Stjr if (isdigit((unsigned char)*fmt)) { 39296795Stjr errno = 0; 39396795Stjr isize = (size_t)strtoul(fmt, &end, 10); 39496795Stjr if (errno != 0 || isize == 0) 39596795Stjr errx(1, "%s: invalid size", fmt); 39696795Stjr if (isize != sizeof(char) && isize != sizeof(short) && 39796795Stjr isize != sizeof(int) && isize != sizeof(long)) 39896795Stjr errx(1, "unsupported int size %lu", 39996795Stjr (u_long)isize); 40096795Stjr fmt = (const char *)end; 40196795Stjr } 40296795Stjr } 40396795Stjr 40496795Stjr /* 40596795Stjr * Calculate the maximum number of digits we need to 40696795Stjr * fit the number. Overestimate for decimal with log 40796795Stjr * base 8. We need one extra space for signed numbers 40896795Stjr * to store the sign. 40996795Stjr */ 41096795Stjr n = (1ULL << (8 * isize)) - 1; 41196795Stjr digits = 0; 41296795Stjr while (n != 0) { 41396795Stjr digits++; 41496795Stjr n >>= (fchar == 'x') ? 4 : 3; 41596795Stjr } 41696795Stjr if (fchar == 'd') 41796795Stjr digits++; 41896798Stjr asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"", 41996798Stjr 16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits), 42096798Stjr "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar); 42196795Stjr if (hdfmt == NULL) 42296795Stjr err(1, NULL); 42396795Stjr odadd(hdfmt); 42496795Stjr free(hdfmt); 42596795Stjr 42696795Stjr return (fmt); 42796795Stjr} 42896795Stjr 42996795Stjrstatic void 43096795Stjrodadd(const char *fmt) 43196795Stjr{ 43296795Stjr static int needpad; 43396795Stjr 43496795Stjr if (needpad) 43596795Stjr add("\""PADDING"\""); 43696795Stjr add(fmt); 43796795Stjr needpad = 1; 43896795Stjr} 439