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