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