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