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