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