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