odsyntax.c revision 96798
1121472Sume/*- 278064Sume * Copyright (c) 1990, 1993 362914Sume * The Regents of the University of California. All rights reserved. 462914Sume * 562914Sume * Redistribution and use in source and binary forms, with or without 662914Sume * modification, are permitted provided that the following conditions 762914Sume * are met: 862914Sume * 1. Redistributions of source code must retain the above copyright 962914Sume * notice, this list of conditions and the following disclaimer. 1062914Sume * 2. Redistributions in binary form must reproduce the above copyright 1162914Sume * notice, this list of conditions and the following disclaimer in the 1262914Sume * documentation and/or other materials provided with the distribution. 1362914Sume * 3. All advertising materials mentioning features or use of this software 1462914Sume * must display the following acknowledgement: 1562914Sume * This product includes software developed by the University of 1662914Sume * California, Berkeley and its contributors. 1762914Sume * 4. Neither the name of the University nor the names of its contributors 1862914Sume * may be used to endorse or promote products derived from this software 1962914Sume * without specific prior written permission. 2062914Sume * 2162914Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2262914Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2362914Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2462914Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2562914Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2662914Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2762914Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2862914Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2962914Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3062914Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31216586Scharnier * SUCH DAMAGE. 32216586Scharnier */ 33216586Scharnier 34216586Scharnier#ifndef lint 3562914Sume#if 0 3662914Sumestatic char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95"; 3762914Sume#endif 3862914Sumestatic const char rcsid[] = 3962914Sume "$FreeBSD: head/usr.bin/hexdump/odsyntax.c 96798 2002-05-17 08:54:32Z tjr $"; 40121472Sume#endif /* not lint */ 4162914Sume 4262914Sume#include <sys/types.h> 4362914Sume 4462914Sume#include <ctype.h> 4562914Sume#include <err.h> 4662914Sume#include <errno.h> 4762914Sume#include <float.h> 4862914Sume#include <stdio.h> 4962914Sume#include <stdlib.h> 5062914Sume#include <string.h> 5162914Sume#include <unistd.h> 5262914Sume 5362914Sume#include "hexdump.h" 5462914Sume 5562914Sume#define PADDING " " 5662914Sume 5762914Sumeint odmode; 58121472Sume 59121472Sumestatic void odadd(const char *); 60121472Sumestatic void odformat(const char *); 61121472Sumestatic const char *odformatfp(char, const char *); 62121472Sumestatic const char *odformatint(char, const char *); 63121472Sumestatic void odoffset(int, char ***); 64121472Sumestatic void odusage(void); 65121472Sume 66121472Sumevoid 67121472Sumeoldsyntax(argc, argvp) 68121472Sume int argc; 69121472Sume char ***argvp; 70121472Sume{ 71121472Sume static char empty[] = "", padding[] = PADDING; 72121472Sume int ch; 73121472Sume char **argv, *end; 74121472Sume 75121472Sume /* Add initial (default) address format. -A may change it later. */ 76121472Sume#define TYPE_OFFSET 7 7762914Sume add("\"%07.7_Ao\n\""); 7862914Sume add("\"%07.7_ao \""); 79121472Sume 8062914Sume odmode = 1; 8162914Sume argv = *argvp; 8262914Sume while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1) 8362914Sume switch (ch) { 8462914Sume case 'A': 8562914Sume switch (*optarg) { 8662914Sume case 'd': case 'o': case 'x': 8762914Sume fshead->nextfu->fmt[TYPE_OFFSET] = *optarg; 8862914Sume fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 8962914Sume *optarg; 9062914Sume break; 9162914Sume case 'n': 9262914Sume fshead->nextfu->fmt = empty; 9362914Sume fshead->nextfs->nextfu->fmt = padding; 9462914Sume break; 9562914Sume default: 9662914Sume errx(1, "%s: invalid address base", optarg); 9762914Sume } 9862914Sume break; 9962914Sume case 'a': 10062914Sume odformat("a"); 10162914Sume break; 10262914Sume case 'B': 103121472Sume case 'o': 10478064Sume odformat("o2"); 10562914Sume break; 10662914Sume case 'b': 107121472Sume odformat("o1"); 10862914Sume break; 10962914Sume case 'c': 110121472Sume odformat("c"); 11162914Sume break; 11262914Sume case 'd': 11362914Sume odformat("u2"); 11462914Sume break; 11562914Sume case 'D': 11662914Sume odformat("u4"); 11762914Sume break; 11862914Sume case 'e': /* undocumented in od */ 11962914Sume case 'F': 12062914Sume odformat("fD"); 12162914Sume break; 12262914Sume case 'f': 12362914Sume odformat("fF"); 12462914Sume break; 12562914Sume case 'H': 12662914Sume case 'X': 12778064Sume odformat("x4"); 12862914Sume break; 12962914Sume case 'h': 13062914Sume case 'x': 13162914Sume odformat("x2"); 13262914Sume break; 13362914Sume case 'I': 13462914Sume case 'L': 13562914Sume case 'l': 13662914Sume odformat("dL"); 13762914Sume break; 13862914Sume case 'i': 13962914Sume odformat("dI"); 14062914Sume break; 14162914Sume case 'j': 14262914Sume errno = 0; 14362914Sume skip = strtoll(optarg, &end, 0); 14462914Sume if (*end == 'b') 14562914Sume skip *= 512; 14662914Sume else if (*end == 'k') 14762914Sume skip *= 1024; 14862914Sume else if (*end == 'm') 14962914Sume skip *= 1048576L; 15062914Sume if (errno != 0 || skip < 0 || strlen(end) > 1) 15162914Sume errx(1, "%s: invalid skip amount", optarg); 15262914Sume break; 15362914Sume case 'N': 15462914Sume if ((length = atoi(optarg)) <= 0) 15562914Sume errx(1, "%s: invalid length", optarg); 15662914Sume break; 15762914Sume case 'O': 15862914Sume odformat("o4"); 15962914Sume break; 16062914Sume case 's': 16162914Sume odformat("d2"); 16262914Sume break; 16362914Sume case 't': 16462914Sume odformat(optarg); 165121472Sume break; 166121472Sume case 'v': 16762914Sume vflag = ALL; 16862914Sume break; 16962914Sume case '?': 17062914Sume default: 17162914Sume odusage(); 17262914Sume } 17362914Sume 17462914Sume if (fshead->nextfs->nextfs == NULL) 17562914Sume odformat("oS"); 17662914Sume 17762914Sume argc -= optind; 17862914Sume *argvp += optind; 17962914Sume 18062914Sume if (argc) 18162914Sume odoffset(argc, argvp); 18262914Sume} 18362914Sume 184121472Sumestatic void 185121472Sumeodusage(void) 186121472Sume{ 187121472Sume 18862914Sume fprintf(stderr, 189121472Sume"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n"); 19062914Sume fprintf(stderr, 19162914Sume" [[+]offset[.][Bb]] [file ...]\n"); 19262914Sume exit(1); 193121472Sume} 194121472Sume 19562914Sumestatic void 19662914Sumeodoffset(argc, argvp) 19762914Sume int argc; 19862914Sume char ***argvp; 19962914Sume{ 20062914Sume unsigned char *p, *num, *end; 20162914Sume int base; 20262914Sume 20362914Sume /* 20462914Sume * The offset syntax of od(1) was genuinely bizarre. First, if 20562914Sume * it started with a plus it had to be an offset. Otherwise, if 20662914Sume * there were at least two arguments, a number or lower-case 'x' 20762914Sume * followed by a number makes it an offset. By default it was 20862914Sume * octal; if it started with 'x' or '0x' it was hex. If it ended 20962914Sume * in a '.', it was decimal. If a 'b' or 'B' was appended, it 21062914Sume * multiplied the number by 512 or 1024 byte units. There was 21162914Sume * no way to assign a block count to a hex offset. 212121472Sume * 213121472Sume * We assume it's a file if the offset is bad. 214121472Sume */ 21562914Sume p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; 216121472Sume 217121472Sume if (*p != '+' && (argc < 2 || 218121472Sume (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1]))))) 219121472Sume return; 220121472Sume 221121472Sume base = 0; 222121472Sume /* 223121472Sume * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and 224121472Sume * set base. 225121472Sume */ 226121472Sume if (p[0] == '+') 227121472Sume ++p; 228121472Sume if (p[0] == 'x' && isxdigit(p[1])) { 229121472Sume ++p; 230121472Sume base = 16; 231121472Sume } else if (p[0] == '0' && p[1] == 'x') { 232121472Sume p += 2; 233121472Sume base = 16; 234121472Sume } 235121472Sume 236121472Sume /* skip over the number */ 237121472Sume if (base == 16) 238121472Sume for (num = p; isxdigit(*p); ++p); 239121472Sume else 240121472Sume for (num = p; isdigit(*p); ++p); 241121472Sume 242121472Sume /* check for no number */ 243121472Sume if (num == p) 244121472Sume return; 245121472Sume 246121472Sume /* if terminates with a '.', base is decimal */ 247121472Sume if (*p == '.') { 248121472Sume if (base) 24962914Sume return; 25062914Sume base = 10; 25162914Sume } 252121472Sume 25362914Sume skip = strtoll(num, (char **)&end, base ? base : 8); 25462914Sume 25562914Sume /* if end isn't the same as p, we got a non-octal digit */ 25662914Sume if (end != p) { 25762914Sume skip = 0; 25862914Sume return; 25962914Sume } 26078064Sume 26162914Sume if (*p) { 26262914Sume if (*p == 'B') { 26362914Sume skip *= 1024; 26462914Sume ++p; 265121472Sume } else if (*p == 'b') { 26662914Sume skip *= 512; 26762914Sume ++p; 268121472Sume } 269121472Sume } 270121472Sume 271121472Sume if (*p) { 272121472Sume skip = 0; 273121472Sume return; 274121472Sume } 275121472Sume 276121472Sume /* 277121472Sume * If the offset uses a non-octal base, the base of the offset 278121472Sume * is changed as well. This isn't pretty, but it's easy. 279121472Sume */ 280121472Sume if (base == 16) { 281121472Sume fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; 282121472Sume fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; 283121472Sume } else if (base == 10) { 28462914Sume fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; 28562914Sume fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; 286121472Sume } 28762914Sume 28862914Sume /* Terminate file list. */ 28962914Sume (*argvp)[1] = NULL; 29062914Sume} 291121472Sume 29262914Sumestatic void 29362914Sumeodformat(const char *fmt) 29462914Sume{ 29562914Sume char fchar; 29662914Sume 29762914Sume while (*fmt != '\0') { 298121472Sume switch ((fchar = *fmt++)) { 29962914Sume case 'a': 30062914Sume odadd("16/1 \"%3_u \" \"\\n\""); 30162914Sume break; 30262914Sume case 'c': 30362914Sume odadd("16/1 \"%3_c \" \"\\n\""); 30462914Sume break; 30562914Sume case 'o': case 'u': case 'd': case 'x': 30662914Sume fmt = odformatint(fchar, fmt); 30762914Sume break; 30862914Sume case 'f': 309121472Sume fmt = odformatfp(fchar, fmt); 31062914Sume break; 31162914Sume default: 31262914Sume errx(1, "%c: unrecognised format character", fchar); 31362914Sume } 314121472Sume } 31562914Sume} 31662914Sume 31762914Sumestatic const char * 31862914Sumeodformatfp(char fchar __unused, const char *fmt) 319121472Sume{ 32062914Sume size_t isize; 32162914Sume int digits; 32262914Sume char *end, *hdfmt; 32362914Sume 32462914Sume isize = sizeof(double); 32562914Sume switch (*fmt) { 32662914Sume case 'F': 32762914Sume isize = sizeof(float); 32862914Sume fmt++; 32962914Sume break; 330121472Sume case 'D': 33162914Sume isize = sizeof(double); 33262914Sume fmt++; 33362914Sume break; 33462914Sume case 'L': 33562914Sume isize = sizeof(long double); 33662914Sume fmt++; 337216586Scharnier break; 338121472Sume default: 33962914Sume if (isdigit((unsigned char)*fmt)) { 34062914Sume errno = 0; 34162914Sume isize = (size_t)strtoul(fmt, &end, 10); 34262914Sume if (errno != 0 || isize == 0) 34362914Sume errx(1, "%s: invalid size", fmt); 34462914Sume fmt = (const char *)end; 34562914Sume } 34662914Sume } 34762914Sume switch (isize) { 34862914Sume case sizeof(float): 349216586Scharnier digits = FLT_DIG; 35062914Sume break; 35162914Sume case sizeof(double): 35262914Sume digits = DBL_DIG; 35362914Sume break; 354 default: 355 if (isize == sizeof(long double)) 356 digits = LDBL_DIG; 357 else 358 errx(1, "unsupported floating point size %lu", 359 (u_long)isize); 360 } 361 362 asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"", 363 16UL / (u_long)isize, (u_long)isize, digits + 8, digits); 364 if (hdfmt == NULL) 365 err(1, NULL); 366 odadd(hdfmt); 367 free(hdfmt); 368 369 return (fmt); 370} 371 372static const char * 373odformatint(char fchar, const char *fmt) 374{ 375 unsigned long long n; 376 size_t isize; 377 int digits; 378 char *end, *hdfmt; 379 380 isize = sizeof(int); 381 switch (*fmt) { 382 case 'C': 383 isize = sizeof(char); 384 fmt++; 385 break; 386 case 'I': 387 isize = sizeof(int); 388 fmt++; 389 break; 390 case 'L': 391 isize = sizeof(long); 392 fmt++; 393 break; 394 case 'S': 395 isize = sizeof(short); 396 fmt++; 397 break; 398 default: 399 if (isdigit((unsigned char)*fmt)) { 400 errno = 0; 401 isize = (size_t)strtoul(fmt, &end, 10); 402 if (errno != 0 || isize == 0) 403 errx(1, "%s: invalid size", fmt); 404 if (isize != sizeof(char) && isize != sizeof(short) && 405 isize != sizeof(int) && isize != sizeof(long)) 406 errx(1, "unsupported int size %lu", 407 (u_long)isize); 408 fmt = (const char *)end; 409 } 410 } 411 412 /* 413 * Calculate the maximum number of digits we need to 414 * fit the number. Overestimate for decimal with log 415 * base 8. We need one extra space for signed numbers 416 * to store the sign. 417 */ 418 n = (1ULL << (8 * isize)) - 1; 419 digits = 0; 420 while (n != 0) { 421 digits++; 422 n >>= (fchar == 'x') ? 4 : 3; 423 } 424 if (fchar == 'd') 425 digits++; 426 asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"", 427 16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits), 428 "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar); 429 if (hdfmt == NULL) 430 err(1, NULL); 431 odadd(hdfmt); 432 free(hdfmt); 433 434 return (fmt); 435} 436 437static void 438odadd(const char *fmt) 439{ 440 static int needpad; 441 442 if (needpad) 443 add("\""PADDING"\""); 444 add(fmt); 445 needpad = 1; 446} 447