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