1 /* $NetBSD: display.c,v 1.20 2006/08/26 18:17:42 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 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[] = "@(#)display.c 8.1 (Berkeley) 6/6/93"; 40 #else 41 __RCSID("$NetBSD: display.c,v 1.20 2006/08/26 18:17:42 christos Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 48 #include <ctype.h> 49 #include <err.h> 50 #include <errno.h> 51 #include <inttypes.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 #include <util.h> 57 58 #include "hexdump.h" 59 60 enum _vflag vflag = FIRST; 61 62 static off_t address; /* address/offset in stream */ 63 static off_t eaddress; /* end address */ 64 65 static inline void print(PR *, u_char *); 66 67 void 68 display(void) 69 { 70 FS *fs; 71 FU *fu; 72 PR *pr; 73 int cnt; 74 u_char *bp; 75 off_t saveaddress; 76 u_char savech, *savebp; 77 78 savech = 0; 79 while ((bp = get()) != NULL) 80 for (fs = fshead, savebp = bp, saveaddress = address; fs; 81 fs = fs->nextfs, bp = savebp, address = saveaddress) 82 for (fu = fs->nextfu; fu; fu = fu->nextfu) { 83 if (fu->flags&F_IGNORE) 84 break; 85 for (cnt = fu->reps; cnt; --cnt) 86 for (pr = fu->nextpr; pr; address += pr->bcnt, 87 bp += pr->bcnt, pr = pr->nextpr) { 88 if (eaddress && address >= eaddress && 89 !(pr->flags & (F_TEXT|F_BPAD))) 90 bpad(pr); 91 if (cnt == 1 && pr->nospace) { 92 savech = *pr->nospace; 93 *pr->nospace = '\0'; 94 } 95 print(pr, bp); 96 if (cnt == 1 && pr->nospace) 97 *pr->nospace = savech; 98 } 99 } 100 if (endfu) { 101 /* 102 * If eaddress not set, error or file size was multiple of 103 * blocksize, and no partial block ever found. 104 */ 105 if (!eaddress) { 106 if (!address) 107 return; 108 eaddress = address; 109 } 110 for (pr = endfu->nextpr; pr; pr = pr->nextpr) 111 switch(pr->flags) { 112 case F_ADDRESS: 113 (void)printf(pr->fmt, (int64_t)eaddress); 114 break; 115 case F_TEXT: 116 (void)printf("%s", pr->fmt); 117 break; 118 } 119 } 120 } 121 122 static inline void 123 print(PR *pr, u_char *bp) 124 { 125 double f8; 126 float f4; 127 int16_t s2; 128 int32_t s4; 129 int64_t s8; 130 u_int16_t u2; 131 u_int32_t u4; 132 u_int64_t u8; 133 134 switch(pr->flags) { 135 case F_ADDRESS: 136 (void)printf(pr->fmt, (int64_t)address); 137 break; 138 case F_BPAD: 139 (void)printf(pr->fmt, ""); 140 break; 141 case F_C: 142 conv_c(pr, bp); 143 break; 144 case F_CHAR: 145 (void)printf(pr->fmt, *bp); 146 break; 147 case F_DBL: 148 switch(pr->bcnt) { 149 case 4: 150 memmove(&f4, bp, sizeof(f4)); 151 (void)printf(pr->fmt, f4); 152 break; 153 case 8: 154 memmove(&f8, bp, sizeof(f8)); 155 (void)printf(pr->fmt, f8); 156 break; 157 } 158 break; 159 case F_INT: 160 switch(pr->bcnt) { 161 case 1: 162 (void)printf(pr->fmt, (int64_t)*bp); 163 break; 164 case 2: 165 memmove(&s2, bp, sizeof(s2)); 166 (void)printf(pr->fmt, (int64_t)s2); 167 break; 168 case 4: 169 memmove(&s4, bp, sizeof(s4)); 170 (void)printf(pr->fmt, (int64_t)s4); 171 break; 172 case 8: 173 memmove(&s8, bp, sizeof(s8)); 174 (void)printf(pr->fmt, s8); 175 break; 176 } 177 break; 178 case F_P: 179 (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); 180 break; 181 case F_STR: 182 (void)printf(pr->fmt, (char *)bp); 183 break; 184 case F_TEXT: 185 (void)printf("%s", pr->fmt); 186 break; 187 case F_U: 188 conv_u(pr, bp); 189 break; 190 case F_UINT: 191 switch(pr->bcnt) { 192 case 1: 193 (void)printf(pr->fmt, (uint64_t)*bp); 194 break; 195 case 2: 196 memmove(&u2, bp, sizeof(u2)); 197 (void)printf(pr->fmt, (uint64_t)u2); 198 break; 199 case 4: 200 memmove(&u4, bp, sizeof(u4)); 201 (void)printf(pr->fmt, (uint64_t)u4); 202 break; 203 case 8: 204 memmove(&u8, bp, sizeof(u8)); 205 (void)printf(pr->fmt, u8); 206 break; 207 } 208 break; 209 } 210 } 211 212 void 213 bpad(PR *pr) 214 { 215 static const char *spec = " -0+#"; 216 char *p1, *p2; 217 218 /* 219 * Remove all conversion flags; '-' is the only one valid 220 * with %s, and it's not useful here. 221 */ 222 pr->flags = F_BPAD; 223 pr->cchar[0] = 's'; 224 pr->cchar[1] = '\0'; 225 for (p1 = pr->fmt; *p1 != '%'; ++p1); 226 for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1); 227 while ((*p2++ = *p1++) != '\0'); 228 } 229 230 static char **_argv; 231 232 u_char * 233 get(void) 234 { 235 static int ateof = 1; 236 static u_char *curp, *savp; 237 int n; 238 int need, nread; 239 u_char *tmpp; 240 241 if (!curp) { 242 curp = ecalloc(blocksize, 1); 243 savp = ecalloc(blocksize, 1); 244 } else { 245 tmpp = curp; 246 curp = savp; 247 savp = tmpp; 248 address += blocksize; 249 } 250 for (need = blocksize, nread = 0;;) { 251 /* 252 * if read the right number of bytes, or at EOF for one file, 253 * and no other files are available, zero-pad the rest of the 254 * block and set the end flag. 255 */ 256 if (!length || (ateof && !next(NULL))) { 257 if (need == blocksize) 258 return(NULL); 259 if (!need && vflag != ALL && 260 !memcmp(curp, savp, nread)) { 261 if (vflag != DUP) 262 (void)printf("*\n"); 263 return(NULL); 264 } 265 memset((char *)curp + nread, 0, need); 266 eaddress = address + nread; 267 return(curp); 268 } 269 n = fread((char *)curp + nread, sizeof(u_char), 270 length == -1 ? need : MIN(length, need), stdin); 271 if (!n) { 272 if (ferror(stdin)) 273 warn("%s", _argv[-1]); 274 ateof = 1; 275 continue; 276 } 277 ateof = 0; 278 if (length != -1) 279 length -= n; 280 if (!(need -= n)) { 281 if (vflag == ALL || vflag == FIRST || 282 memcmp(curp, savp, blocksize)) { 283 if (vflag == DUP || vflag == FIRST) 284 vflag = WAIT; 285 return(curp); 286 } 287 if (vflag == WAIT) 288 (void)printf("*\n"); 289 vflag = DUP; 290 address += blocksize; 291 need = blocksize; 292 nread = 0; 293 } 294 else 295 nread += n; 296 } 297 } 298 299 int 300 next(char **argv) 301 { 302 static int done; 303 int statok; 304 305 if (argv) { 306 _argv = argv; 307 return(1); 308 } 309 for (;;) { 310 if (*_argv) { 311 if (!(freopen(*_argv, "r", stdin))) { 312 warn("%s", *_argv); 313 exitval = 1; 314 ++_argv; 315 continue; 316 } 317 statok = done = 1; 318 } else { 319 if (done++) 320 return(0); 321 statok = 0; 322 } 323 if (skip) 324 doskip(statok ? *_argv : "stdin", statok); 325 if (*_argv) 326 ++_argv; 327 if (!skip) 328 return(1); 329 } 330 /* NOTREACHED */ 331 } 332 333 void 334 doskip(const char *fname, int statok) 335 { 336 int cnt; 337 struct stat sb; 338 339 if (statok) { 340 if (fstat(fileno(stdin), &sb)) 341 err(1, "fstat %s", fname); 342 if (S_ISREG(sb.st_mode) && skip >= sb.st_size) { 343 address += sb.st_size; 344 skip -= sb.st_size; 345 return; 346 } 347 } 348 if (S_ISREG(sb.st_mode)) { 349 if (fseek(stdin, skip, SEEK_SET)) 350 err(1, "fseek %s", fname); 351 address += skip; 352 skip = 0; 353 } else { 354 for (cnt = 0; cnt < skip; ++cnt) 355 if (getchar() == EOF) 356 break; 357 address += cnt; 358 skip -= cnt; 359 } 360 } 361