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