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