1 /* $NetBSD: odsyntax.c,v 1.23 2006/01/04 01:30:21 perry 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.23 2006/01/04 01:30:21 perry 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 53 #include "hexdump.h" 54 55 struct odformat { 56 char type; 57 int nbytes; 58 char const *format; 59 int minwidth; 60 }; 61 62 struct odaddrformat { 63 char type; 64 char const *format1; 65 char const *format2; 66 }; 67 68 int deprecated; 69 70 static void odoffset(int, char ***); 71 static void posixtypes(char const *); 72 static void odprecede(void); 73 74 75 void 76 oldsyntax(int argc, char ***argvp) 77 { 78 int ch; 79 char *p, **argv; 80 81 deprecated = 1; 82 argv = *argvp; 83 while ((ch = getopt(argc, argv, 84 "aBbcDdeFfHhIij:LlN:OoPpst:wvXx")) != -1) 85 switch (ch) { 86 case 'a': 87 posixtypes("a"); 88 break; 89 case 'B': 90 case 'o': 91 posixtypes("o2"); 92 break; 93 case 'b': 94 posixtypes("o1"); 95 break; 96 case 'c': 97 posixtypes("c"); 98 break; 99 case 'd': 100 posixtypes("u2"); 101 break; 102 case 'D': 103 posixtypes("u4"); 104 break; 105 case 'e': /* undocumented in od */ 106 case 'F': 107 posixtypes("f8"); 108 break; 109 case 'f': 110 posixtypes("f4"); 111 break; 112 case 'H': 113 case 'X': 114 posixtypes("x4"); 115 break; 116 case 'h': 117 case 'x': 118 posixtypes("x2"); 119 break; 120 case 'I': 121 case 'L': 122 case 'l': 123 posixtypes("d4"); 124 break; 125 case 'i': 126 posixtypes("d2"); 127 break; 128 case 'j': 129 if ((skip = strtol(optarg, &p, 0)) < 0) 130 errx(1, "%s: bad skip value", optarg); 131 switch(*p) { 132 case 'b': 133 skip *= 512; 134 break; 135 case 'k': 136 skip *= 1024; 137 break; 138 case 'm': 139 skip *= 1048576; 140 break; 141 } 142 break; 143 case 'N': 144 if ((length = atoi(optarg)) < 0) 145 errx(1, "%s: bad length value", optarg); 146 break; 147 case 'O': 148 posixtypes("o4"); 149 break; 150 case 't': 151 posixtypes(optarg); 152 break; 153 case 'v': 154 vflag = ALL; 155 break; 156 case 'P': 157 case 'p': 158 case 's': 159 case 'w': 160 case '?': 161 default: 162 warnx("od(1) has been deprecated for hexdump(1)."); 163 if (ch != '?') 164 warnx( 165 "hexdump(1) compatibility doesn't support the -%c option%s\n", 166 ch, ch == 's' ? "; see strings(1)." : "."); 167 usage(); 168 } 169 170 if (!fshead) { 171 add("\"%07.7_Ao\n\""); 172 add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\""); 173 } 174 175 argc -= optind; 176 *argvp += optind; 177 178 if (argc) 179 odoffset(argc, argvp); 180 } 181 182 /* formats used for -t */ 183 184 static const struct odformat odftab[] = { 185 { 'a', 1, "%3_u", 4 }, 186 { 'c', 1, "%3_c", 4 }, 187 { 'd', 1, "%4d", 5 }, 188 { 'd', 2, "%6d", 6 }, 189 { 'd', 4, "%11d", 11 }, 190 { 'd', 8, "%20d", 20 }, 191 { 'o', 1, "%03o", 4 }, 192 { 'o', 2, "%06o", 7 }, 193 { 'o', 4, "%011o", 12 }, 194 { 'o', 8, "%022o", 23 }, 195 { 'u', 1, "%03u" , 4 }, 196 { 'u', 2, "%05u" , 6 }, 197 { 'u', 4, "%010u", 11 }, 198 { 'u', 8, "%020u", 21 }, 199 { 'x', 1, "%02x", 3 }, 200 { 'x', 2, "%04x", 5 }, 201 { 'x', 4, "%08x", 9 }, 202 { 'x', 8, "%016x", 17 }, 203 { 'f', 4, "%14.7e", 15 }, 204 { 'f', 8, "%21.14e", 22 }, 205 { 0, 0, NULL, 0 } 206 }; 207 208 /* 209 * Interpret a POSIX-style -t argument. 210 */ 211 static void 212 posixtypes(char const *type_string) 213 { 214 int nbytes = 0; 215 char *fmt, type, *tmp; 216 struct odformat const *odf; 217 218 while (*type_string) { 219 odprecede(); 220 switch ((type = *type_string++)) { 221 case 'a': 222 case 'c': 223 nbytes = 1; 224 break; 225 case 'f': 226 if (isupper((unsigned char)*type_string)) { 227 switch(*type_string) { 228 case 'F': 229 nbytes = sizeof(float); 230 break; 231 case 'D': 232 nbytes = sizeof(double); 233 break; 234 case 'L': 235 nbytes = sizeof(long double); 236 break; 237 default: 238 warnx("Bad type-size qualifier '%c'", 239 *type_string); 240 usage(); 241 } 242 type_string++; 243 } else if (isdigit((unsigned char)*type_string)) { 244 nbytes = strtol(type_string, &tmp, 10); 245 type_string = tmp; 246 } else 247 nbytes = 8; 248 break; 249 case 'd': 250 case 'o': 251 case 'u': 252 case 'x': 253 if (isupper((unsigned char)*type_string)) { 254 switch(*type_string) { 255 case 'C': 256 nbytes = sizeof(char); 257 break; 258 case 'S': 259 nbytes = sizeof(short); 260 break; 261 case 'I': 262 nbytes = sizeof(int); 263 break; 264 case 'L': 265 nbytes = sizeof(long); 266 break; 267 default: 268 warnx("Bad type-size qualifier '%c'", 269 *type_string); 270 usage(); 271 } 272 type_string++; 273 } else if (isdigit((unsigned char)*type_string)) { 274 nbytes = strtol(type_string, &tmp, 10); 275 type_string = tmp; 276 } else 277 nbytes = 4; 278 break; 279 default: 280 usage(); 281 } 282 for (odf = odftab; odf->type != 0; odf++) 283 if (odf->type == type && odf->nbytes == nbytes) 284 break; 285 if (odf->type == 0) 286 errx(1, "%c%d: format not supported", type, nbytes); 287 asprintf(&fmt, "%d/%d \"%*s%s \" \"\\n\"", 288 16 / nbytes, nbytes, 289 4 * nbytes - odf->minwidth, "", odf->format); 290 if (fmt == NULL) nomem(); 291 add(fmt); 292 } 293 } 294 295 static void 296 odoffset(int argc, char ***argvp) 297 { 298 char *num, *p; 299 int base; 300 char *end; 301 302 /* 303 * The offset syntax of od(1) was genuinely bizarre. First, if 304 * it started with a plus it had to be an offset. Otherwise, if 305 * there were at least two arguments, a number or lower-case 'x' 306 * followed by a number makes it an offset. By default it was 307 * octal; if it started with 'x' or '0x' it was hex. If it ended 308 * in a '.', it was decimal. If a 'b' or 'B' was appended, it 309 * multiplied the number by 512 or 1024 byte units. There was 310 * no way to assign a block count to a hex offset. 311 * 312 * We assume it's a file if the offset is bad. 313 */ 314 p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; 315 if (!p) 316 return; 317 318 if (*p != '+' && (argc < 2 || 319 (!isdigit((unsigned char)p[0]) && 320 (p[0] != 'x' || !isxdigit((unsigned char)p[1]))))) 321 return; 322 323 base = 0; 324 /* 325 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and 326 * set base. 327 */ 328 if (p[0] == '+') 329 ++p; 330 if (p[0] == 'x' && isxdigit((unsigned char)p[1])) { 331 ++p; 332 base = 16; 333 } else if (p[0] == '0' && p[1] == 'x') { 334 p += 2; 335 base = 16; 336 } 337 338 /* skip over the number */ 339 if (base == 16) 340 for (num = p; isxdigit((unsigned char)*p); ++p); 341 else 342 for (num = p; isdigit((unsigned char)*p); ++p); 343 344 /* check for no number */ 345 if (num == p) 346 return; 347 348 /* if terminates with a '.', base is decimal */ 349 if (*p == '.') { 350 if (base) 351 return; 352 base = 10; 353 } 354 355 skip = strtol(num, &end, base ? base : 8); 356 357 /* if end isn't the same as p, we got a non-octal digit */ 358 if (end != p) { 359 skip = 0; 360 return; 361 } 362 363 if (*p) { 364 if (*p == 'B') { 365 skip *= 1024; 366 ++p; 367 } else if (*p == 'b') { 368 skip *= 512; 369 ++p; 370 } 371 } 372 if (*p) { 373 skip = 0; 374 return; 375 } 376 /* 377 * If the offset uses a non-octal base, the base of the offset 378 * is changed as well. This isn't pretty, but it's easy. 379 */ 380 #define TYPE_OFFSET 7 381 if (base == 16) { 382 fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; 383 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; 384 } else if (base == 10) { 385 fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; 386 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; 387 } 388 389 /* Terminate file list. */ 390 (*argvp)[1] = NULL; 391 } 392 393 static void 394 odprecede(void) 395 { 396 static int first = 1; 397 398 if (first) { 399 first = 0; 400 add("\"%07.7_Ao\n\""); 401 add("\"%07.7_ao \""); 402 } else 403 add("\" \""); 404 } 405