1 /* $OpenBSD: odsyntax.c,v 1.16 2007/02/06 20:55:13 jmc 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 #ifndef lint 34 /*static char sccsid[] = "from: @(#)odsyntax.c 5.4 (Berkeley) 3/8/91";*/ 35 static char rcsid[] = "$OpenBSD: odsyntax.c,v 1.16 2007/02/06 20:55:13 jmc Exp $"; 36 #endif /* not lint */ 37 38 #include <sys/types.h> 39 40 #include <ctype.h> 41 #include <err.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 46 #include "hexdump.h" 47 48 int deprecated; 49 50 static void odoffset(int, char ***); 51 static void posixtypes(char *); 52 static void odprecede(void); 53 54 55 /* 56 * formats used for -t 57 */ 58 static const char *fmt[4][4] = { 59 { 60 "16/1 \"%3d \" \"\\n\"", 61 "8/2 \" %05d \" \"\\n\"", 62 "4/4 \" %010d \" \"\\n\"", 63 "2/8 \" %019d \" \"\\n\"" 64 }, { 65 "16/1 \"%03o \" \"\\n\"", 66 "8/2 \" %06o \" \"\\n\"", 67 "4/4 \" %011o\" \"\\n\"", 68 "2/8 \" %022o \" \"\\n\"" 69 }, { 70 "16/1 \"%03u \" \"\\n\"", 71 "8/2 \" %05u \" \"\\n\"", 72 "4/4 \" %010u \" \"\\n\"", 73 "2/8 \" %020u \" \"\\n\"" 74 }, { 75 "16/1 \" %02x \" \"\\n\"", 76 "8/2 \" %04x \" \"\\n\"", 77 "4/4 \" %08x \" \"\\n\"", 78 "2/8 \" %16x \" \"\\n\"" 79 } 80 }; 81 82 void 83 oldsyntax(int argc, char ***argvp) 84 { 85 int ch; 86 char *p, **argv; 87 88 deprecated = 1; 89 argv = *argvp; 90 while ((ch = getopt(argc, argv, 91 "aBbcDdeFfHhIij:LlN:OoPpst:wvXx")) != -1) 92 switch (ch) { 93 case 'a': 94 odprecede(); 95 add("16/1 \"%3_u \" \"\\n\""); 96 break; 97 case 'B': 98 case 'o': 99 odprecede(); 100 add("8/2 \" %06o \" \"\\n\""); 101 break; 102 case 'b': 103 odprecede(); 104 add("16/1 \"%03o \" \"\\n\""); 105 break; 106 case 'c': 107 odprecede(); 108 add("16/1 \"%3_c \" \"\\n\""); 109 break; 110 case 'd': 111 odprecede(); 112 add("8/2 \" %05u \" \"\\n\""); 113 break; 114 case 'D': 115 odprecede(); 116 add("4/4 \" %010u \" \"\\n\""); 117 break; 118 case 'e': 119 case 'F': 120 odprecede(); 121 add("2/8 \" %21.14e \" \"\\n\""); 122 break; 123 124 case 'f': 125 odprecede(); 126 add("4/4 \" %14.7e \" \"\\n\""); 127 break; 128 case 'H': 129 case 'X': 130 odprecede(); 131 add("4/4 \" %08x \" \"\\n\""); 132 break; 133 case 'h': 134 case 'x': 135 odprecede(); 136 add("8/2 \" %04x \" \"\\n\""); 137 break; 138 case 'I': 139 case 'L': 140 case 'l': 141 odprecede(); 142 add("4/4 \" %11d \" \"\\n\""); 143 break; 144 case 'i': 145 odprecede(); 146 add("8/2 \" %6d \" \"\\n\""); 147 break; 148 case 'j': 149 if ((skip = strtol(optarg, &p, 0)) < 0) 150 errx(1, "%s: bad skip value", optarg); 151 switch(*p) { 152 case 'b': 153 skip *= 512; 154 break; 155 case 'k': 156 skip *= 1024; 157 break; 158 case 'm': 159 skip *= 1048576; 160 break; 161 } 162 break; 163 case 'N': 164 if ((length = atoi(optarg)) < 0) 165 errx(1, "%s: bad length value", optarg); 166 break; 167 case 'O': 168 odprecede(); 169 add("4/4 \" %011o \" \"\\n\""); 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" 187 " support the -%c option%s", 188 ch, ch == 's' ? "; see strings(1)." : "."); 189 oldusage(); 190 } 191 192 if (!fshead) { 193 add("\"%07.7_Ao\n\""); 194 add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\""); 195 } 196 197 argc -= optind; 198 *argvp += optind; 199 200 if (argc) 201 odoffset(argc, argvp); 202 } 203 204 /* 205 * Interpret a POSIX-style -t argument. 206 */ 207 static void 208 posixtypes(char *type_string) 209 { 210 int x, y, nbytes; 211 212 while (*type_string) { 213 odprecede(); 214 switch (*type_string) { 215 case 'a': 216 type_string++; 217 add("16/1 \"%3_u \" \"\\n\""); 218 break; 219 case 'c': 220 type_string++; 221 add("16/1 \"%3_c \" \"\\n\""); 222 break; 223 case 'f': 224 type_string++; 225 if (*type_string == 'F' || 226 *type_string == '4') { 227 type_string++; 228 add("4/4 \" %14.7e\" \"\\n\""); 229 } else if (*type_string == 'L' || 230 *type_string == '8') { 231 type_string++; 232 add("2/8 \" %16.14e\" \"\\n\""); 233 } else if (*type_string == 'D') 234 /* long doubles vary in size */ 235 oldusage(); 236 else 237 add("2/8 \" %16.14e\" \"\\n\""); 238 break; 239 case 'd': 240 x = 0; 241 goto extensions; 242 case 'o': 243 x = 1; 244 goto extensions; 245 case 'u': 246 x = 2; 247 goto extensions; 248 case 'x': 249 x = 3; 250 extensions: 251 type_string++; 252 y = 2; 253 if (isupper(*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 oldusage(); 271 } 272 type_string++; 273 } else if (isdigit(*type_string)) 274 nbytes = strtol(type_string, &type_string, 10); 275 276 switch (nbytes) { 277 case 1: 278 y = 0; 279 break; 280 case 2: 281 y = 1; 282 break; 283 case 4: 284 y = 2; 285 break; 286 case 8: 287 y = 3; 288 break; 289 default: 290 warnx("%d-byte integer formats are not " 291 "supported", nbytes); 292 oldusage(); 293 } 294 add(fmt[x][y]); 295 break; 296 default: 297 oldusage(); 298 } 299 } 300 } 301 302 void 303 oldusage(void) 304 { 305 extern char *__progname; 306 fprintf(stderr, "usage: %s [-aBbcDdeFfHhIiLlOovXx] [-j offset] " 307 "[-N length] [-t type_string]\n" 308 "\t[[+]offset[.][Bb]] [file ...]\n", __progname); 309 exit(1); 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 #define TYPE_OFFSET 7 398 if (base == 16) { 399 fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; 400 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; 401 } else if (base == 10) { 402 fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; 403 fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; 404 } 405 406 /* Terminate file list. */ 407 (*argvp)[1] = NULL; 408 } 409 410 static void 411 odprecede(void) 412 { 413 static int first = 1; 414 415 if (first) { 416 first = 0; 417 add("\"%07.7_Ao\n\""); 418 add("\"%07.7_ao \""); 419 } else 420 add("\" \""); 421 } 422