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