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