xref: /original-bsd/usr.bin/hexdump/display.c (revision 6570ed16)
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