1 /* $NetBSD: odsyntax.c,v 1.24 2006/08/26 18:17:42 christos 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.24 2006/08/26 18:17:42 christos 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 struct odformat { 57 char type; 58 int nbytes; 59 char const *format; 60 int minwidth; 61 }; 62 63 struct odaddrformat { 64 char type; 65 char const *format1; 66 char const *format2; 67 }; 68 69 int deprecated; 70 71 static void odoffset(int, char ***); 72 static void posixtypes(char const *); 73 static void odprecede(void); 74 75 76 void 77 oldsyntax(int argc, char ***argvp) 78 { 79 int ch; 80 char *p, **argv; 81 82 deprecated = 1; 83 argv = *argvp; 84 while ((ch = getopt(argc, argv, 85 "aBbcDdeFfHhIij:LlN:OoPpst:wvXx")) != -1) 86 switch (ch) { 87 case 'a': 88 posixtypes("a"); 89 break; 90 case 'B': 91 case 'o': 92 posixtypes("o2"); 93 break; 94 case 'b': 95 posixtypes("o1"); 96 break; 97 case 'c': 98 posixtypes("c"); 99 break; 100 case 'd': 101 posixtypes("u2"); 102 break; 103 case 'D': 104 posixtypes("u4"); 105 break; 106 case 'e': /* undocumented in od */ 107 case 'F': 108 posixtypes("f8"); 109 break; 110 case 'f': 111 posixtypes("f4"); 112 break; 113 case 'H': 114 case 'X': 115 posixtypes("x4"); 116 break; 117 case 'h': 118 case 'x': 119 posixtypes("x2"); 120 break; 121 case 'I': 122 case 'L': 123 case 'l': 124 posixtypes("d4"); 125 break; 126 case 'i': 127 posixtypes("d2"); 128 break; 129 case 'j': 130 if ((skip = strtol(optarg, &p, 0)) < 0) 131 errx(1, "%s: bad skip value", optarg); 132 switch(*p) { 133 case 'b': 134 skip *= 512; 135 break; 136 case 'k': 137 skip *= 1024; 138 break; 139 case 'm': 140 skip *= 1048576; 141 break; 142 } 143 break; 144 case 'N': 145 if ((length = atoi(optarg)) < 0) 146 errx(1, "%s: bad length value", optarg); 147 break; 148 case 'O': 149 posixtypes("o4"); 150 break; 151 case 't': 152 posixtypes(optarg); 153 break; 154 case 'v': 155 vflag = ALL; 156 break; 157 case 'P': 158 case 'p': 159 case 's': 160 case 'w': 161 case '?': 162 default: 163 warnx("od(1) has been deprecated for hexdump(1)."); 164 if (ch != '?') 165 warnx( 166 "hexdump(1) compatibility doesn't support the -%c option%s\n", 167 ch, ch == 's' ? "; see strings(1)." : "."); 168 usage(); 169 } 170 171 if (!fshead) { 172 add("\"%07.7_Ao\n\""); 173 add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\""); 174 } 175 176 argc -= optind; 177 *argvp += optind; 178 179 if (argc) 180 odoffset(argc, argvp); 181 } 182 183 /* formats used for -t */ 184 185 static const struct odformat odftab[] = { 186 { 'a', 1, "%3_u", 4 }, 187 { 'c', 1, "%3_c", 4 }, 188 { 'd', 1, "%4d", 5 }, 189 { 'd', 2, "%6d", 6 }, 190 { 'd', 4, "%11d", 11 }, 191 { 'd', 8, "%20d", 20 }, 192 { 'o', 1, "%03o", 4 }, 193 { 'o', 2, "%06o", 7 }, 194 { 'o', 4, "%011o", 12 }, 195 { 'o', 8, "%022o", 23 }, 196 { 'u', 1, "%03u" , 4 }, 197 { 'u', 2, "%05u" , 6 }, 198 { 'u', 4, "%010u", 11 }, 199 { 'u', 8, "%020u", 21 }, 200 { 'x', 1, "%02x", 3 }, 201 { 'x', 2, "%04x", 5 }, 202 { 'x', 4, "%08x", 9 }, 203 { 'x', 8, "%016x", 17 }, 204 { 'f', 4, "%14.7e", 15 }, 205 { 'f', 8, "%21.14e", 22 }, 206 { 0, 0, NULL, 0 } 207 }; 208 209 /* 210 * Interpret a POSIX-style -t argument. 211 */ 212 static void 213 posixtypes(char const *type_string) 214 { 215 int nbytes = 0; 216 char *fmt, type, *tmp; 217 struct odformat const *odf; 218 219 while (*type_string) { 220 odprecede(); 221 switch ((type = *type_string++)) { 222 case 'a': 223 case 'c': 224 nbytes = 1; 225 break; 226 case 'f': 227 if (isupper((unsigned char)*type_string)) { 228 switch(*type_string) { 229 case 'F': 230 nbytes = sizeof(float); 231 break; 232 case 'D': 233 nbytes = sizeof(double); 234 break; 235 case 'L': 236 nbytes = sizeof(long double); 237 break; 238 default: 239 warnx("Bad type-size qualifier '%c'", 240 *type_string); 241 usage(); 242 } 243 type_string++; 244 } else if (isdigit((unsigned char)*type_string)) { 245 nbytes = strtol(type_string, &tmp, 10); 246 type_string = tmp; 247 } else 248 nbytes = 8; 249 break; 250 case 'd': 251 case 'o': 252 case 'u': 253 case 'x': 254 if (isupper((unsigned char)*type_string)) { 255 switch(*type_string) { 256 case 'C': 257 nbytes = sizeof(char); 258 break; 259 case 'S': 260 nbytes = sizeof(short); 261 break; 262 case 'I': 263 nbytes = sizeof(int); 264 break; 265 case 'L': 266 nbytes = sizeof(long); 267 break; 268 default: 269 warnx("Bad type-size qualifier '%c'", 270 *type_string); 271 usage(); 272 } 273 type_string++; 274 } else if (isdigit((unsigned char)*type_string)) { 275 nbytes = strtol(type_string, &tmp, 10); 276 type_string = tmp; 277 } else 278 nbytes = 4; 279 break; 280 default: 281 usage(); 282 } 283 for (odf = odftab; odf->type != 0; odf++) 284 if (odf->type == type && odf->nbytes == nbytes) 285 break; 286 if (odf->type == 0) 287 errx(1, "%c%d: format not supported", type, nbytes); 288 (void)easprintf(&fmt, "%d/%d \"%*s%s \" \"\\n\"", 289 16 / nbytes, nbytes, 290 4 * nbytes - odf->minwidth, "", odf->format); 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