1 1.27 christos /* $NetBSD: display.c,v 1.27 2024/01/14 17:40:17 christos Exp $ */ 2 1.4 tls 3 1.1 cgd /* 4 1.6 mrg * Copyright (c) 1989, 1993 5 1.6 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.14 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.18 lukem #if HAVE_NBTOOL_CONFIG_H 33 1.18 lukem #include "nbtool_config.h" 34 1.18 lukem #endif 35 1.18 lukem 36 1.7 lukem #include <sys/cdefs.h> 37 1.18 lukem #if !defined(lint) 38 1.5 mikel #if 0 39 1.6 mrg static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93"; 40 1.5 mikel #else 41 1.27 christos __RCSID("$NetBSD: display.c,v 1.27 2024/01/14 17:40:17 christos Exp $"); 42 1.5 mikel #endif 43 1.1 cgd #endif /* not lint */ 44 1.1 cgd 45 1.1 cgd #include <sys/param.h> 46 1.1 cgd #include <sys/stat.h> 47 1.6 mrg 48 1.7 lukem #include <ctype.h> 49 1.7 lukem #include <err.h> 50 1.1 cgd #include <errno.h> 51 1.16 cl #include <inttypes.h> 52 1.1 cgd #include <stdio.h> 53 1.1 cgd #include <stdlib.h> 54 1.1 cgd #include <string.h> 55 1.5 mikel #include <unistd.h> 56 1.20 christos #include <util.h> 57 1.6 mrg 58 1.1 cgd #include "hexdump.h" 59 1.1 cgd 60 1.1 cgd enum _vflag vflag = FIRST; 61 1.1 cgd 62 1.1 cgd static off_t address; /* address/offset in stream */ 63 1.1 cgd static off_t eaddress; /* end address */ 64 1.1 cgd 65 1.23 dholland static u_char *get(void); 66 1.19 perry static inline void print(PR *, u_char *); 67 1.1 cgd 68 1.5 mikel void 69 1.19 perry display(void) 70 1.1 cgd { 71 1.7 lukem FS *fs; 72 1.7 lukem FU *fu; 73 1.7 lukem PR *pr; 74 1.7 lukem int cnt; 75 1.7 lukem u_char *bp; 76 1.1 cgd off_t saveaddress; 77 1.5 mikel u_char savech, *savebp; 78 1.1 cgd 79 1.7 lukem savech = 0; 80 1.5 mikel while ((bp = get()) != NULL) 81 1.1 cgd for (fs = fshead, savebp = bp, saveaddress = address; fs; 82 1.1 cgd fs = fs->nextfs, bp = savebp, address = saveaddress) 83 1.1 cgd for (fu = fs->nextfu; fu; fu = fu->nextfu) { 84 1.1 cgd if (fu->flags&F_IGNORE) 85 1.1 cgd break; 86 1.1 cgd for (cnt = fu->reps; cnt; --cnt) 87 1.1 cgd for (pr = fu->nextpr; pr; address += pr->bcnt, 88 1.1 cgd bp += pr->bcnt, pr = pr->nextpr) { 89 1.1 cgd if (eaddress && address >= eaddress && 90 1.6 mrg !(pr->flags & (F_TEXT|F_BPAD))) 91 1.1 cgd bpad(pr); 92 1.1 cgd if (cnt == 1 && pr->nospace) { 93 1.1 cgd savech = *pr->nospace; 94 1.1 cgd *pr->nospace = '\0'; 95 1.1 cgd } 96 1.6 mrg print(pr, bp); 97 1.1 cgd if (cnt == 1 && pr->nospace) 98 1.1 cgd *pr->nospace = savech; 99 1.1 cgd } 100 1.1 cgd } 101 1.1 cgd if (endfu) { 102 1.1 cgd /* 103 1.6 mrg * If eaddress not set, error or file size was multiple of 104 1.1 cgd * blocksize, and no partial block ever found. 105 1.1 cgd */ 106 1.1 cgd if (!eaddress) { 107 1.1 cgd if (!address) 108 1.1 cgd return; 109 1.1 cgd eaddress = address; 110 1.1 cgd } 111 1.1 cgd for (pr = endfu->nextpr; pr; pr = pr->nextpr) 112 1.1 cgd switch(pr->flags) { 113 1.1 cgd case F_ADDRESS: 114 1.15 wiz (void)printf(pr->fmt, (int64_t)eaddress); 115 1.1 cgd break; 116 1.1 cgd case F_TEXT: 117 1.9 itojun (void)printf("%s", pr->fmt); 118 1.1 cgd break; 119 1.1 cgd } 120 1.1 cgd } 121 1.1 cgd } 122 1.1 cgd 123 1.6 mrg static inline void 124 1.19 perry print(PR *pr, u_char *bp) 125 1.6 mrg { 126 1.6 mrg double f8; 127 1.6 mrg float f4; 128 1.6 mrg int16_t s2; 129 1.6 mrg int32_t s4; 130 1.11 bjh21 int64_t s8; 131 1.21 apb uint16_t u2; 132 1.21 apb uint32_t u4; 133 1.21 apb uint64_t u8; 134 1.6 mrg 135 1.6 mrg switch(pr->flags) { 136 1.6 mrg case F_ADDRESS: 137 1.15 wiz (void)printf(pr->fmt, (int64_t)address); 138 1.6 mrg break; 139 1.6 mrg case F_BPAD: 140 1.6 mrg (void)printf(pr->fmt, ""); 141 1.6 mrg break; 142 1.6 mrg case F_C: 143 1.6 mrg conv_c(pr, bp); 144 1.6 mrg break; 145 1.6 mrg case F_CHAR: 146 1.6 mrg (void)printf(pr->fmt, *bp); 147 1.6 mrg break; 148 1.6 mrg case F_DBL: 149 1.6 mrg switch(pr->bcnt) { 150 1.6 mrg case 4: 151 1.7 lukem memmove(&f4, bp, sizeof(f4)); 152 1.6 mrg (void)printf(pr->fmt, f4); 153 1.6 mrg break; 154 1.6 mrg case 8: 155 1.7 lukem memmove(&f8, bp, sizeof(f8)); 156 1.6 mrg (void)printf(pr->fmt, f8); 157 1.6 mrg break; 158 1.6 mrg } 159 1.6 mrg break; 160 1.6 mrg case F_INT: 161 1.6 mrg switch(pr->bcnt) { 162 1.6 mrg case 1: 163 1.15 wiz (void)printf(pr->fmt, (int64_t)*bp); 164 1.6 mrg break; 165 1.6 mrg case 2: 166 1.7 lukem memmove(&s2, bp, sizeof(s2)); 167 1.15 wiz (void)printf(pr->fmt, (int64_t)s2); 168 1.6 mrg break; 169 1.6 mrg case 4: 170 1.7 lukem memmove(&s4, bp, sizeof(s4)); 171 1.15 wiz (void)printf(pr->fmt, (int64_t)s4); 172 1.6 mrg break; 173 1.6 mrg case 8: 174 1.7 lukem memmove(&s8, bp, sizeof(s8)); 175 1.21 apb (void)printf(pr->fmt, (int64_t)s8); 176 1.6 mrg break; 177 1.6 mrg } 178 1.6 mrg break; 179 1.6 mrg case F_P: 180 1.6 mrg (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); 181 1.6 mrg break; 182 1.6 mrg case F_STR: 183 1.6 mrg (void)printf(pr->fmt, (char *)bp); 184 1.6 mrg break; 185 1.6 mrg case F_TEXT: 186 1.9 itojun (void)printf("%s", pr->fmt); 187 1.6 mrg break; 188 1.6 mrg case F_U: 189 1.6 mrg conv_u(pr, bp); 190 1.6 mrg break; 191 1.6 mrg case F_UINT: 192 1.6 mrg switch(pr->bcnt) { 193 1.6 mrg case 1: 194 1.15 wiz (void)printf(pr->fmt, (uint64_t)*bp); 195 1.6 mrg break; 196 1.6 mrg case 2: 197 1.7 lukem memmove(&u2, bp, sizeof(u2)); 198 1.15 wiz (void)printf(pr->fmt, (uint64_t)u2); 199 1.6 mrg break; 200 1.6 mrg case 4: 201 1.7 lukem memmove(&u4, bp, sizeof(u4)); 202 1.15 wiz (void)printf(pr->fmt, (uint64_t)u4); 203 1.6 mrg break; 204 1.6 mrg case 8: 205 1.7 lukem memmove(&u8, bp, sizeof(u8)); 206 1.21 apb (void)printf(pr->fmt, (uint64_t)u8); 207 1.6 mrg break; 208 1.6 mrg } 209 1.6 mrg break; 210 1.6 mrg } 211 1.6 mrg } 212 1.6 mrg 213 1.5 mikel void 214 1.19 perry bpad(PR *pr) 215 1.1 cgd { 216 1.5 mikel static const char *spec = " -0+#"; 217 1.7 lukem char *p1, *p2; 218 1.1 cgd 219 1.1 cgd /* 220 1.6 mrg * Remove all conversion flags; '-' is the only one valid 221 1.1 cgd * with %s, and it's not useful here. 222 1.1 cgd */ 223 1.1 cgd pr->flags = F_BPAD; 224 1.6 mrg pr->cchar[0] = 's'; 225 1.6 mrg pr->cchar[1] = '\0'; 226 1.1 cgd for (p1 = pr->fmt; *p1 != '%'; ++p1); 227 1.5 mikel for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1); 228 1.5 mikel while ((*p2++ = *p1++) != '\0'); 229 1.1 cgd } 230 1.1 cgd 231 1.1 cgd static char **_argv; 232 1.1 cgd 233 1.23 dholland static u_char * 234 1.19 perry get(void) 235 1.1 cgd { 236 1.1 cgd static int ateof = 1; 237 1.1 cgd static u_char *curp, *savp; 238 1.7 lukem int n; 239 1.1 cgd int need, nread; 240 1.1 cgd u_char *tmpp; 241 1.1 cgd 242 1.1 cgd if (!curp) { 243 1.20 christos curp = ecalloc(blocksize, 1); 244 1.20 christos savp = ecalloc(blocksize, 1); 245 1.1 cgd } else { 246 1.1 cgd tmpp = curp; 247 1.1 cgd curp = savp; 248 1.1 cgd savp = tmpp; 249 1.6 mrg address += blocksize; 250 1.1 cgd } 251 1.1 cgd for (need = blocksize, nread = 0;;) { 252 1.1 cgd /* 253 1.1 cgd * if read the right number of bytes, or at EOF for one file, 254 1.1 cgd * and no other files are available, zero-pad the rest of the 255 1.1 cgd * block and set the end flag. 256 1.1 cgd */ 257 1.24 dholland if (!length || (ateof && !next())) { 258 1.1 cgd if (need == blocksize) 259 1.26 christos return NULL ; 260 1.10 christos if (!need && vflag != ALL && 261 1.10 christos !memcmp(curp, savp, nread)) { 262 1.1 cgd if (vflag != DUP) 263 1.1 cgd (void)printf("*\n"); 264 1.26 christos return NULL ; 265 1.1 cgd } 266 1.7 lukem memset((char *)curp + nread, 0, need); 267 1.1 cgd eaddress = address + nread; 268 1.26 christos return curp ; 269 1.1 cgd } 270 1.1 cgd n = fread((char *)curp + nread, sizeof(u_char), 271 1.1 cgd length == -1 ? need : MIN(length, need), stdin); 272 1.1 cgd if (!n) { 273 1.1 cgd if (ferror(stdin)) 274 1.7 lukem warn("%s", _argv[-1]); 275 1.1 cgd ateof = 1; 276 1.1 cgd continue; 277 1.1 cgd } 278 1.1 cgd ateof = 0; 279 1.1 cgd if (length != -1) 280 1.1 cgd length -= n; 281 1.1 cgd if (!(need -= n)) { 282 1.1 cgd if (vflag == ALL || vflag == FIRST || 283 1.7 lukem memcmp(curp, savp, blocksize)) { 284 1.1 cgd if (vflag == DUP || vflag == FIRST) 285 1.1 cgd vflag = WAIT; 286 1.26 christos return curp ; 287 1.1 cgd } 288 1.1 cgd if (vflag == WAIT) 289 1.1 cgd (void)printf("*\n"); 290 1.1 cgd vflag = DUP; 291 1.6 mrg address += blocksize; 292 1.1 cgd need = blocksize; 293 1.1 cgd nread = 0; 294 1.1 cgd } 295 1.1 cgd else 296 1.1 cgd nread += n; 297 1.1 cgd } 298 1.1 cgd } 299 1.1 cgd 300 1.25 dholland /* 301 1.25 dholland * Save argv for later retrieval. 302 1.25 dholland */ 303 1.24 dholland void 304 1.24 dholland stashargv(char **argv) 305 1.24 dholland { 306 1.24 dholland _argv = argv; 307 1.24 dholland } 308 1.24 dholland 309 1.25 dholland /* 310 1.25 dholland * Get the next file. The idea with the twisty logic seems to be to 311 1.25 dholland * either read N filenames from argv and then exit, or if there aren't 312 1.25 dholland * any, to use stdin and then exit. It should probably be simplified. 313 1.25 dholland * The "done" flag doesn't mean "we are done", it means "we are done 314 1.25 dholland * once we run out of filenames". 315 1.25 dholland * 316 1.26 christos * Is there any reason not to remove the logic that inhibits 317 1.25 dholland * calling fstat if using stdin and not a filename? It should be safe 318 1.26 christos * to call fstat on any fd. Yes, because on stdin it st_size will not 319 1.26 christos * convey useful information. In addition on kernfs/procfs stat might 320 1.26 christos * not return proper size info. 321 1.25 dholland * 322 1.25 dholland * Note: I have ruled that if there is one file on the command line 323 1.25 dholland * and it doesn't open, we should exit after complaining about it and 324 1.25 dholland * not then proceed to read stdin; the latter seems like unexpected 325 1.25 dholland * and undesirable behavior. Also, it didn't work anyway, because the 326 1.25 dholland * freopen call clobbers stdin while failing. -- dholland 20160303 327 1.25 dholland */ 328 1.5 mikel int 329 1.24 dholland next(void) 330 1.1 cgd { 331 1.1 cgd static int done; 332 1.1 cgd int statok; 333 1.1 cgd 334 1.1 cgd for (;;) { 335 1.1 cgd if (*_argv) { 336 1.25 dholland done = 1; 337 1.1 cgd if (!(freopen(*_argv, "r", stdin))) { 338 1.7 lukem warn("%s", *_argv); 339 1.1 cgd exitval = 1; 340 1.1 cgd ++_argv; 341 1.1 cgd continue; 342 1.1 cgd } 343 1.25 dholland statok = 1; 344 1.1 cgd } else { 345 1.1 cgd if (done++) 346 1.26 christos return 0 ; 347 1.1 cgd statok = 0; 348 1.1 cgd } 349 1.1 cgd if (skip) 350 1.1 cgd doskip(statok ? *_argv : "stdin", statok); 351 1.1 cgd if (*_argv) 352 1.1 cgd ++_argv; 353 1.1 cgd if (!skip) 354 1.26 christos return 1 ; 355 1.1 cgd } 356 1.1 cgd /* NOTREACHED */ 357 1.1 cgd } 358 1.1 cgd 359 1.5 mikel void 360 1.19 perry doskip(const char *fname, int statok) 361 1.1 cgd { 362 1.7 lukem int cnt; 363 1.6 mrg struct stat sb; 364 1.1 cgd 365 1.1 cgd if (statok) { 366 1.6 mrg if (fstat(fileno(stdin), &sb)) 367 1.26 christos err(EXIT_FAILURE, "fstat %s", fname); 368 1.27 christos if (sb.st_size != 0 && 369 1.26 christos S_ISREG(sb.st_mode) && skip >= sb.st_size) { 370 1.6 mrg address += sb.st_size; 371 1.6 mrg skip -= sb.st_size; 372 1.1 cgd return; 373 1.1 cgd } 374 1.22 christos } else 375 1.22 christos sb.st_mode = S_IFIFO; 376 1.22 christos 377 1.6 mrg if (S_ISREG(sb.st_mode)) { 378 1.6 mrg if (fseek(stdin, skip, SEEK_SET)) 379 1.7 lukem err(1, "fseek %s", fname); 380 1.6 mrg address += skip; 381 1.6 mrg skip = 0; 382 1.6 mrg } else { 383 1.6 mrg for (cnt = 0; cnt < skip; ++cnt) 384 1.6 mrg if (getchar() == EOF) 385 1.6 mrg break; 386 1.6 mrg address += cnt; 387 1.6 mrg skip -= cnt; 388 1.1 cgd } 389 1.1 cgd } 390