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