1 /* $NetBSD: odsyntax.c,v 1.25 2008/09/03 16:32:57 drochner 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 39 static char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95"; 40 #else 41 __RCSID("$NetBSD: odsyntax.c,v 1.25 2008/09/03 16:32:57 drochner 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 58 struct odformat { 59 char type; 60 int nbytes; 61 char const *format; 62 int minwidth; 63 }; 64 65 struct odaddrformat { 66 char type; 67 char const *format1; 68 char const *format2; 69 }; 70 71 int deprecated; 72 73 static void odoffset(int, char ***); 74 static void posixtypes(char const *); 75 76 void 77 oldsyntax(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 deprecated = 1; 88 argv = *argvp; 89 while ((ch = getopt(argc, argv, 90 "A:aBbcDdeFfHhIij:LlN:OoPpst:wvXx")) != -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 'P': 178 case 'p': 179 case 's': 180 case 'w': 181 case '?': 182 default: 183 warnx("od(1) has been deprecated for hexdump(1)."); 184 if (ch != '?') 185 warnx( 186 "hexdump(1) compatibility doesn't support the -%c option%s\n", 187 ch, ch == 's' ? "; see strings(1)." : "."); 188 usage(); 189 } 190 191 if (fshead->nextfs->nextfs == NULL) 192 posixtypes("oS"); 193 194 argc -= optind; 195 *argvp += optind; 196 197 if (argc) 198 odoffset(argc, argvp); 199 } 200 201 /* formats used for -t */ 202 203 static const struct odformat odftab[] = { 204 { 'a', 1, "%3_u", 4 }, 205 { 'c', 1, "%3_c", 4 }, 206 { 'd', 1, "%4d", 5 }, 207 { 'd', 2, "%6d", 6 }, 208 { 'd', 4, "%11d", 11 }, 209 { 'd', 8, "%20d", 20 }, 210 { 'o', 1, "%03o", 4 }, 211 { 'o', 2, "%06o", 7 }, 212 { 'o', 4, "%011o", 12 }, 213 { 'o', 8, "%022o", 23 }, 214 { 'u', 1, "%03u" , 4 }, 215 { 'u', 2, "%05u" , 6 }, 216 { 'u', 4, "%010u", 11 }, 217 { 'u', 8, "%020u", 21 }, 218 { 'x', 1, "%02x", 3 }, 219 { 'x', 2, "%04x", 5 }, 220 { 'x', 4, "%08x", 9 }, 221 { 'x', 8, "%016x", 17 }, 222 { 'f', 4, "%14.7e", 15 }, 223 { 'f', 8, "%21.14e", 22 }, 224 { 0, 0, NULL, 0 } 225 }; 226 227 /* 228 * Interpret a POSIX-style -t argument. 229 */ 230 static void 231 posixtypes(char const *type_string) 232 { 233 int nbytes = 0; 234 char *fmt, type, *tmp; 235 struct odformat const *odf; 236 237 while (*type_string) { 238 switch ((type = *type_string++)) { 239 case 'a': 240 case 'c': 241 nbytes = 1; 242 break; 243 case 'f': 244 if (isupper((unsigned char)*type_string)) { 245 switch(*type_string) { 246 case 'F': 247 nbytes = sizeof(float); 248 break; 249 case 'D': 250 nbytes = sizeof(double); 251 break; 252 case 'L': 253 nbytes = sizeof(long double); 254 break; 255 default: 256 warnx("Bad type-size qualifier '%c'", 257 *type_string); 258 usage(); 259 } 260 type_string++; 261 } else if (isdigit((unsigned char)*type_string)) { 262 nbytes = strtol(type_string, &tmp, 10); 263 type_string = tmp; 264 } else 265 nbytes = 8; 266 break; 267 case 'd': 268 case 'o': 269 case 'u': 270 case 'x': 271 if (isupper((unsigned char)*type_string)) { 272 switch(*type_string) { 273 case 'C': 274 nbytes = sizeof(char); 275 break; 276 case 'S': 277 nbytes = sizeof(short); 278 break; 279 case 'I': 280 nbytes = sizeof(int); 281 break; 282 case 'L': 283 nbytes = sizeof(long); 284 break; 285 default: 286 warnx("Bad type-size qualifier '%c'", 287 *type_string); 288 usage(); 289 } 290 type_string++; 291 } else if (isdigit((unsigned char)*type_string)) { 292 nbytes = strtol(type_string, &tmp, 10); 293 type_string = tmp; 294 } else 295 nbytes = 4; 296 break; 297 default: 298 usage(); 299 } 300 for (odf = odftab; odf->type != 0; odf++) 301 if (odf->type == type && odf->nbytes == nbytes) 302 break; 303 if (odf->type == 0) 304 errx(1, "%c%d: format not supported", type, nbytes); 305 (void)easprintf(&fmt, "%d/%d \"%*s%s \" \"\\n\"", 306 16 / nbytes, nbytes, 307 4 * nbytes - odf->minwidth, "", odf->format); 308 add(fmt); 309 } 310 } 311 312 static void 313 odoffset(int argc, char ***argvp) 314 { 315 char *num, *p; 316 int base; 317 char *end; 318 319 /* 320 * The offset syntax of od(1) was genuinely bizarre. First, if 321 * it started with a plus it had to be an offset. Otherwise, if 322 * there were at least two arguments, a number or lower-case 'x' 323 * followed by a number makes it an offset. By default it was 324 * octal; if it started with 'x' or '0x' it was hex. If it ended 325 * in a '.', it was decimal. If a 'b' or 'B' was appended, it 326 * multiplied the number by 512 or 1024 byte units. There was 327 * no way to assign a block count to a hex offset. 328 * 329 * We assume it's a file if the offset is bad. 330 */ 331 p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; 332 if (!p) 333 return; 334 335 if (*p != '+' && (argc < 2 || 336 (!isdigit((unsigned char)p[0]) && 337 (p[0] != 'x' || !isxdigit((unsigned char)p[1]))))) 338 return; 339 340 base = 0; 341 /* 342 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and 343 * set base. 344 */ 345 if (p[0] == '+') 346 ++p; 347 if (p[0] == 'x' && isxdigit((unsigned char)p[1])) { 348 ++p; 349 base = 16; 350 } else if (p[0] == '0' && p[1] == 'x') { 351 p += 2; 352 base = 16; 353 } 354 355 /* skip over the number */ 356 if (base == 16) 357 for (num = p; isxdigit((unsigned char)*p); ++p); 358 else 359 for (num = p; isdigit((unsigned char)*p); ++p); 360 361 /* check for no number */ 362 if (num == p) 363 return; 364 365 /* if terminates with a '.', base is decimal */ 366 if (*p == '.') { 367 if (base) 368 return; 369 base = 10; 370 } 371 372 skip = strtol(num, &end, base ? base : 8); 373 374 /* if end isn't the same as p, we got a non-octal digit */ 375 if (end != p) { 376 skip = 0; 377 return; 378 } 379 380 if (*p) { 381 if (*p == 'B') { 382 skip *= 1024; 383 ++p; 384 } else if (*p == 'b') { 385 skip *= 512; 386 ++p; 387 } 388 } 389 if (*p) { 390 skip = 0; 391 return; 392 } 393 /* 394 * If the offset uses a non-octal base, the base of the offset 395 * is changed as well. This isn't pretty, but it's easy. 396 */ 397 if (base == 16) { 398 fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; 399 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; 400 } else if (base == 10) { 401 fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; 402 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; 403 } 404 405 /* Terminate file list. */ 406 (*argvp)[1] = NULL; 407 } 408