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