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