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 * 4. 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
30#ifndef lint
31#if 0
32static char sccsid[] = "@(#)display.c	8.1 (Berkeley) 6/6/93";
33#endif
34#endif /* not lint */
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#include <sys/param.h>
39#include <sys/stat.h>
40
41#include <ctype.h>
42#include <err.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47#include "hexdump.h"
48
49enum _vflag vflag = FIRST;
50
51static off_t address;			/* address/offset in stream */
52static off_t eaddress;			/* end address */
53
54static void print(PR *, u_char *);
55
56void
57display(void)
58{
59	FS *fs;
60	FU *fu;
61	PR *pr;
62	int cnt;
63	u_char *bp;
64	off_t saveaddress;
65	u_char savech, *savebp;
66
67	savech = 0;
68	while ((bp = get()))
69	    for (fs = fshead, savebp = bp, saveaddress = address; fs;
70		fs = fs->nextfs, bp = savebp, address = saveaddress)
71		    for (fu = fs->nextfu; fu; fu = fu->nextfu) {
72			if (fu->flags&F_IGNORE)
73				break;
74			for (cnt = fu->reps; cnt; --cnt)
75			    for (pr = fu->nextpr; pr; address += pr->bcnt,
76				bp += pr->bcnt, pr = pr->nextpr) {
77				    if (eaddress && address >= eaddress &&
78					!(pr->flags & (F_TEXT|F_BPAD)))
79					    bpad(pr);
80				    if (cnt == 1 && pr->nospace) {
81					savech = *pr->nospace;
82					*pr->nospace = '\0';
83				    }
84				    print(pr, bp);
85				    if (cnt == 1 && pr->nospace)
86					*pr->nospace = savech;
87			    }
88		    }
89	if (endfu) {
90		/*
91		 * If eaddress not set, error or file size was multiple of
92		 * blocksize, and no partial block ever found.
93		 */
94		if (!eaddress) {
95			if (!address)
96				return;
97			eaddress = address;
98		}
99		for (pr = endfu->nextpr; pr; pr = pr->nextpr)
100			switch(pr->flags) {
101			case F_ADDRESS:
102				(void)printf(pr->fmt, (quad_t)eaddress);
103				break;
104			case F_TEXT:
105				(void)printf("%s", pr->fmt);
106				break;
107			}
108	}
109}
110
111static void
112print(PR *pr, u_char *bp)
113{
114	long double ldbl;
115	   double f8;
116	    float f4;
117	  int16_t s2;
118	   int8_t s8;
119	  int32_t s4;
120	u_int16_t u2;
121	u_int32_t u4;
122	u_int64_t u8;
123
124	switch(pr->flags) {
125	case F_ADDRESS:
126		(void)printf(pr->fmt, (quad_t)address);
127		break;
128	case F_BPAD:
129		(void)printf(pr->fmt, "");
130		break;
131	case F_C:
132		conv_c(pr, bp, eaddress ? eaddress - address :
133		    blocksize - address % blocksize);
134		break;
135	case F_CHAR:
136		(void)printf(pr->fmt, *bp);
137		break;
138	case F_DBL:
139		switch(pr->bcnt) {
140		case 4:
141			bcopy(bp, &f4, sizeof(f4));
142			(void)printf(pr->fmt, f4);
143			break;
144		case 8:
145			bcopy(bp, &f8, sizeof(f8));
146			(void)printf(pr->fmt, f8);
147			break;
148		default:
149			if (pr->bcnt == sizeof(long double)) {
150				bcopy(bp, &ldbl, sizeof(ldbl));
151				(void)printf(pr->fmt, ldbl);
152			}
153			break;
154		}
155		break;
156	case F_INT:
157		switch(pr->bcnt) {
158		case 1:
159			(void)printf(pr->fmt, (quad_t)(signed char)*bp);
160			break;
161		case 2:
162			bcopy(bp, &s2, sizeof(s2));
163			(void)printf(pr->fmt, (quad_t)s2);
164			break;
165		case 4:
166			bcopy(bp, &s4, sizeof(s4));
167			(void)printf(pr->fmt, (quad_t)s4);
168			break;
169		case 8:
170			bcopy(bp, &s8, sizeof(s8));
171			(void)printf(pr->fmt, s8);
172			break;
173		}
174		break;
175	case F_P:
176		(void)printf(pr->fmt, isprint(*bp) ? *bp : '.');
177		break;
178	case F_STR:
179		(void)printf(pr->fmt, (char *)bp);
180		break;
181	case F_TEXT:
182		(void)printf("%s", pr->fmt);
183		break;
184	case F_U:
185		conv_u(pr, bp);
186		break;
187	case F_UINT:
188		switch(pr->bcnt) {
189		case 1:
190			(void)printf(pr->fmt, (u_quad_t)*bp);
191			break;
192		case 2:
193			bcopy(bp, &u2, sizeof(u2));
194			(void)printf(pr->fmt, (u_quad_t)u2);
195			break;
196		case 4:
197			bcopy(bp, &u4, sizeof(u4));
198			(void)printf(pr->fmt, (u_quad_t)u4);
199			break;
200		case 8:
201			bcopy(bp, &u8, sizeof(u8));
202			(void)printf(pr->fmt, u8);
203			break;
204		}
205		break;
206	}
207}
208
209void
210bpad(PR *pr)
211{
212	static char const *spec = " -0+#";
213	char *p1, *p2;
214
215	/*
216	 * Remove all conversion flags; '-' is the only one valid
217	 * with %s, and it's not useful here.
218	 */
219	pr->flags = F_BPAD;
220	pr->cchar[0] = 's';
221	pr->cchar[1] = '\0';
222	for (p1 = pr->fmt; *p1 != '%'; ++p1);
223	for (p2 = ++p1; *p1 && index(spec, *p1); ++p1);
224	while ((*p2++ = *p1++));
225}
226
227static char **_argv;
228
229u_char *
230get(void)
231{
232	static int ateof = 1;
233	static u_char *curp, *savp;
234	int n;
235	int need, nread;
236	int valid_save = 0;
237	u_char *tmpp;
238
239	if (!curp) {
240		if ((curp = calloc(1, blocksize)) == NULL)
241			err(1, NULL);
242		if ((savp = calloc(1, blocksize)) == NULL)
243			err(1, NULL);
244	} else {
245		tmpp = curp;
246		curp = savp;
247		savp = tmpp;
248		address += blocksize;
249		valid_save = 1;
250	}
251	for (need = blocksize, nread = 0;;) {
252		/*
253		 * if read the right number of bytes, or at EOF for one file,
254		 * and no other files are available, zero-pad the rest of the
255		 * block and set the end flag.
256		 */
257		if (!length || (ateof && !next((char **)NULL))) {
258			if (odmode && address < skip)
259				errx(1, "cannot skip past end of input");
260			if (need == blocksize)
261				return((u_char *)NULL);
262			/*
263			 * XXX bcmp() is not quite right in the presence
264			 * of multibyte characters.
265			 */
266			if (vflag != ALL &&
267			    valid_save &&
268			    bcmp(curp, savp, nread) == 0) {
269				if (vflag != DUP)
270					(void)printf("*\n");
271				return((u_char *)NULL);
272			}
273			bzero((char *)curp + nread, need);
274			eaddress = address + nread;
275			return(curp);
276		}
277		n = fread((char *)curp + nread, sizeof(u_char),
278		    length == -1 ? need : MIN(length, need), stdin);
279		if (!n) {
280			if (ferror(stdin))
281				warn("%s", _argv[-1]);
282			ateof = 1;
283			continue;
284		}
285		ateof = 0;
286		if (length != -1)
287			length -= n;
288		if (!(need -= n)) {
289			/*
290			 * XXX bcmp() is not quite right in the presence
291			 * of multibyte characters.
292			 */
293			if (vflag == ALL || vflag == FIRST ||
294			    valid_save == 0 ||
295			    bcmp(curp, savp, blocksize) != 0) {
296				if (vflag == DUP || vflag == FIRST)
297					vflag = WAIT;
298				return(curp);
299			}
300			if (vflag == WAIT)
301				(void)printf("*\n");
302			vflag = DUP;
303			address += blocksize;
304			need = blocksize;
305			nread = 0;
306		}
307		else
308			nread += n;
309	}
310}
311
312size_t
313peek(u_char *buf, size_t nbytes)
314{
315	size_t n, nread;
316	int c;
317
318	if (length != -1 && nbytes > (unsigned int)length)
319		nbytes = length;
320	nread = 0;
321	while (nread < nbytes && (c = getchar()) != EOF) {
322		*buf++ = c;
323		nread++;
324	}
325	n = nread;
326	while (n-- > 0) {
327		c = *--buf;
328		ungetc(c, stdin);
329	}
330	return (nread);
331}
332
333int
334next(char **argv)
335{
336	static int done;
337	int statok;
338
339	if (argv) {
340		_argv = argv;
341		return(1);
342	}
343	for (;;) {
344		if (*_argv) {
345			done = 1;
346			if (!(freopen(*_argv, "r", stdin))) {
347				warn("%s", *_argv);
348				exitval = 1;
349				++_argv;
350				continue;
351			}
352			statok = 1;
353		} else {
354			if (done++)
355				return(0);
356			statok = 0;
357		}
358		if (skip)
359			doskip(statok ? *_argv : "stdin", statok);
360		if (*_argv)
361			++_argv;
362		if (!skip)
363			return(1);
364	}
365	/* NOTREACHED */
366}
367
368void
369doskip(const char *fname, int statok)
370{
371	int cnt;
372	struct stat sb;
373
374	if (statok) {
375		if (fstat(fileno(stdin), &sb))
376			err(1, "%s", fname);
377		if (S_ISREG(sb.st_mode) && skip >= sb.st_size) {
378			address += sb.st_size;
379			skip -= sb.st_size;
380			return;
381		}
382	}
383	if (S_ISREG(sb.st_mode)) {
384		if (fseeko(stdin, skip, SEEK_SET))
385			err(1, "%s", fname);
386		address += skip;
387		skip = 0;
388	} else {
389		for (cnt = 0; cnt < skip; ++cnt)
390			if (getchar() == EOF)
391				break;
392		address += cnt;
393		skip -= cnt;
394	}
395}
396