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