1/* $OpenBSD: odsyntax.c,v 1.28 2017/05/30 05:58:44 tedu Exp $ */ 2/* $NetBSD: odsyntax.c,v 1.15 2001/12/07 15:14:29 bjh21 Exp $ */ 3 4/*- 5 * Copyright (c) 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/types.h> 34 35#include <ctype.h> 36#include <err.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <unistd.h> 40 41#include "hexdump.h" 42 43#define PADDING " " 44 45int odmode; 46 47static void odadd(const char *); 48static void odoffset(int, char ***); 49static __dead void oldusage(void); 50static void posixtypes(char *); 51 52/* 53 * formats used for -t 54 */ 55static const char *fmt[4][4] = { 56 { 57 "16/1 \"%3d \" \"\\n\"", 58 "8/2 \" %05d \" \"\\n\"", 59 "4/4 \" %010d \" \"\\n\"", 60 "2/8 \" %019d \" \"\\n\"" 61 }, { 62 "16/1 \"%03o \" \"\\n\"", 63 "8/2 \" %06o \" \"\\n\"", 64 "4/4 \" %011o\" \"\\n\"", 65 "2/8 \" %022o \" \"\\n\"" 66 }, { 67 "16/1 \"%03u \" \"\\n\"", 68 "8/2 \" %05u \" \"\\n\"", 69 "4/4 \" %010u \" \"\\n\"", 70 "2/8 \" %020u \" \"\\n\"" 71 }, { 72 "16/1 \" %02x \" \"\\n\"", 73 "8/2 \" %04x \" \"\\n\"", 74 "4/4 \" %08x \" \"\\n\"", 75 "2/8 \" %16x \" \"\\n\"" 76 } 77}; 78 79void 80oldsyntax(int argc, char ***argvp) 81{ 82 static char empty[] = "", padding[] = PADDING; 83 int ch; 84 char *p, **argv; 85 86#define TYPE_OFFSET 7 87 add("\"%07.7_Ao\n\""); 88 add("\"%07.7_ao \""); 89 90 odmode = 1; 91 argv = *argvp; 92 while ((ch = getopt(argc, argv, 93 "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1) 94 switch (ch) { 95 case 'A': 96 switch (*optarg) { 97 case 'd': case 'o': case 'x': 98 fshead->nextfu->fmt[TYPE_OFFSET] = *optarg; 99 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 100 *optarg; 101 break; 102 case 'n': 103 fshead->nextfu->fmt = empty; 104 fshead->nextfs->nextfu->fmt = padding; 105 break; 106 default: 107 errx(1, "%s: invalid address base", optarg); 108 } 109 break; 110 case 'a': 111 odadd("16/1 \"%3_u \" \"\\n\""); 112 break; 113 case 'B': 114 case 'o': 115 odadd("8/2 \" %06o \" \"\\n\""); 116 break; 117 case 'b': 118 odadd("16/1 \"%03o \" \"\\n\""); 119 break; 120 case 'c': 121 odadd("16/1 \"%3_c \" \"\\n\""); 122 break; 123 case 'd': 124 odadd("8/2 \" %05u \" \"\\n\""); 125 break; 126 case 'D': 127 odadd("4/4 \" %010u \" \"\\n\""); 128 break; 129 case 'e': 130 case 'F': 131 odadd("2/8 \" %21.14e \" \"\\n\""); 132 break; 133 case 'f': 134 odadd("4/4 \" %14.7e \" \"\\n\""); 135 break; 136 case 'H': 137 case 'X': 138 odadd("4/4 \" %08x \" \"\\n\""); 139 break; 140 case 'h': 141 case 'x': 142 odadd("8/2 \" %04x \" \"\\n\""); 143 break; 144 case 'I': 145 case 'L': 146 case 'l': 147 odadd("4/4 \" %11d \" \"\\n\""); 148 break; 149 case 'i': 150 odadd("8/2 \" %6d \" \"\\n\""); 151 break; 152 case 'j': 153 if ((skip = strtol(optarg, &p, 0)) < 0) 154 errx(1, "%s: bad skip value", optarg); 155 switch(*p) { 156 case 'b': 157 skip *= 512; 158 break; 159 case 'k': 160 skip *= 1024; 161 break; 162 case 'm': 163 skip *= 1048576; 164 break; 165 } 166 break; 167 case 'N': 168 if ((length = atoi(optarg)) < 0) 169 errx(1, "%s: bad length value", optarg); 170 break; 171 case 'O': 172 odadd("4/4 \" %011o \" \"\\n\""); 173 break; 174 case 's': 175 odadd("8/2 \" %05d \" \"\\n\""); 176 break; 177 case 't': 178 posixtypes(optarg); 179 break; 180 case 'v': 181 vflag = ALL; 182 break; 183 default: 184 oldusage(); 185 } 186 187 if (fshead->nextfs->nextfs == NULL) 188 odadd(" 8/2 \"%06o \" \"\\n\""); 189 190 argc -= optind; 191 *argvp += optind; 192 193 if (argc) 194 odoffset(argc, argvp); 195} 196 197/* 198 * Interpret a POSIX-style -t argument. 199 */ 200static void 201posixtypes(char *type_string) 202{ 203 int x, y, nbytes; 204 205 while (*type_string) { 206 switch (*type_string) { 207 case 'a': 208 type_string++; 209 odadd("16/1 \"%3_u \" \"\\n\""); 210 break; 211 case 'c': 212 type_string++; 213 odadd("16/1 \"%3_c \" \"\\n\""); 214 break; 215 case 'f': 216 type_string++; 217 if (*type_string == 'F' || 218 *type_string == '4') { 219 type_string++; 220 odadd("4/4 \" %14.7e\" \"\\n\""); 221 } else if (*type_string == 'L' || 222 *type_string == '8') { 223 type_string++; 224 odadd("2/8 \" %16.14e\" \"\\n\""); 225 } else if (*type_string == 'D') 226 /* long doubles vary in size */ 227 oldusage(); 228 else 229 odadd("2/8 \" %16.14e\" \"\\n\""); 230 break; 231 case 'd': 232 x = 0; 233 goto extensions; 234 case 'o': 235 x = 1; 236 goto extensions; 237 case 'u': 238 x = 2; 239 goto extensions; 240 case 'x': 241 x = 3; 242 extensions: 243 type_string++; 244 y = 2; 245 if (isupper((unsigned char)*type_string)) { 246 switch(*type_string) { 247 case 'C': 248 nbytes = sizeof(char); 249 break; 250 case 'S': 251 nbytes = sizeof(short); 252 break; 253 case 'I': 254 nbytes = sizeof(int); 255 break; 256 case 'L': 257 nbytes = sizeof(long); 258 break; 259 default: 260 warnx("Bad type-size qualifier '%c'", 261 *type_string); 262 oldusage(); 263 } 264 type_string++; 265 } else if (isdigit((unsigned char)*type_string)) 266 nbytes = strtol(type_string, &type_string, 10); 267 else 268 nbytes = 4; 269 270 switch (nbytes) { 271 case 1: 272 y = 0; 273 break; 274 case 2: 275 y = 1; 276 break; 277 case 4: 278 y = 2; 279 break; 280 case 8: 281 y = 3; 282 break; 283 default: 284 warnx("%d-byte integer formats are not " 285 "supported", nbytes); 286 oldusage(); 287 } 288 odadd(fmt[x][y]); 289 break; 290 default: 291 oldusage(); 292 } 293 } 294} 295 296static __dead void 297oldusage(void) 298{ 299 extern char *__progname; 300 fprintf(stderr, "usage: %s [-aBbcDdeFfHhIiLlOosvXx] [-A base] " 301 "[-j offset] [-N length]\n" 302 "\t[-t type_string] [file ...]\n", __progname); 303 exit(1); 304} 305 306static void 307odoffset(int argc, char ***argvp) 308{ 309 char *num, *p; 310 int base; 311 char *end; 312 313 /* 314 * The offset syntax of od(1) was genuinely bizarre. First, if 315 * it started with a plus it had to be an offset. Otherwise, if 316 * there were at least two arguments, a number or lower-case 'x' 317 * followed by a number makes it an offset. By default it was 318 * octal; if it started with 'x' or '0x' it was hex. If it ended 319 * in a '.', it was decimal. If a 'b' or 'B' was appended, it 320 * multiplied the number by 512 or 1024 byte units. There was 321 * no way to assign a block count to a hex offset. 322 * 323 * We assume it's a file if the offset is bad. 324 */ 325 p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; 326 if (!p) 327 return; 328 329 if (*p != '+' && (argc < 2 || 330 (!isdigit((unsigned char)p[0]) && 331 (p[0] != 'x' || !isxdigit((unsigned char)p[1]))))) 332 return; 333 334 base = 0; 335 /* 336 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and 337 * set base. 338 */ 339 if (p[0] == '+') 340 ++p; 341 if (p[0] == 'x' && isxdigit((unsigned char)p[1])) { 342 ++p; 343 base = 16; 344 } else if (p[0] == '0' && p[1] == 'x') { 345 p += 2; 346 base = 16; 347 } 348 349 /* skip over the number */ 350 if (base == 16) 351 for (num = p; isxdigit((unsigned char)*p); ++p); 352 else 353 for (num = p; isdigit((unsigned char)*p); ++p); 354 355 /* check for no number */ 356 if (num == p) 357 return; 358 359 /* if terminates with a '.', base is decimal */ 360 if (*p == '.') { 361 if (base) 362 return; 363 base = 10; 364 } 365 366 skip = strtol(num, &end, base ? base : 8); 367 368 /* if end isn't the same as p, we got a non-octal digit */ 369 if (end != p) { 370 skip = 0; 371 return; 372 } 373 374 if (*p == '.') 375 ++p; 376 if (*p) { 377 if (*p == 'B') { 378 skip *= 1024; 379 ++p; 380 } else if (*p == 'b') { 381 skip *= 512; 382 ++p; 383 } 384 } 385 if (*p) { 386 skip = 0; 387 return; 388 } 389 /* 390 * If the offset uses a non-octal base, the base of the offset 391 * is changed as well. This isn't pretty, but it's easy. 392 */ 393 if (base == 16) { 394 fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; 395 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; 396 } else if (base == 10) { 397 fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; 398 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; 399 } 400 401 /* Terminate file list. */ 402 (*argvp)[argc > 1] = NULL; 403} 404 405static void 406odadd(const char *format) 407{ 408 static int needpad; 409 410 if (needpad) 411 add("\""PADDING"\""); 412 add(format); 413 needpad = 1; 414} 415