Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:29:27 dillon 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 void
57 display()
58 {
59         extern FU *endfu;
60         register FS *fs;
61         register FU *fu;
62         register PR *pr;
63         register int cnt;
64         register u_char *bp;
65         off_t saveaddress;
66         u_char savech, *savebp;
67
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
111 static __inline void
112 print(pr, bp)
113         PR *pr;
114         u_char *bp;
115 {
116         long double ldbl;
117            double f8;
118             float f4;
119           int16_t s2;
120            int8_t s8;
121           int32_t s4;
122         u_int16_t u2;
123         u_int32_t u4;
124         u_int64_t u8;
125
126         switch(pr->flags) {
127         case F_ADDRESS:
128                 (void)printf(pr->fmt, (quad_t)address);
129                 break;
130         case F_BPAD:
131                 (void)printf(pr->fmt, "");
132                 break;
133         case F_C:
134                 conv_c(pr, bp);
135                 break;
136         case F_CHAR:
137                 (void)printf(pr->fmt, *bp);
138                 break;
139         case F_DBL:
140                 switch(pr->bcnt) {
141                 case 4:
142                         bcopy(bp, &f4, sizeof(f4));
143                         (void)printf(pr->fmt, f4);
144                         break;
145                 case 8:
146                         bcopy(bp, &f8, sizeof(f8));
147                         (void)printf(pr->fmt, f8);
148                         break;
149                 default:
150                         if (pr->bcnt == sizeof(long double)) {
151                                 bcopy(bp, &ldbl, sizeof(ldbl));
152                                 (void)printf(pr->fmt, ldbl);
153                         }
154                         break;
155                 }
156                 break;
157         case F_INT:
158                 switch(pr->bcnt) {
159                 case 1:
160                         (void)printf(pr->fmt, (quad_t)(signed char)*bp);
161                         break;
162                 case 2:
163                         bcopy(bp, &s2, sizeof(s2));
164                         (void)printf(pr->fmt, (quad_t)s2);
165                         break;
166                 case 4:
167                         bcopy(bp, &s4, sizeof(s4));
168                         (void)printf(pr->fmt, (quad_t)s4);
169                         break;
170                 case 8:
171                         bcopy(bp, &s8, sizeof(s8));
172                         (void)printf(pr->fmt, s8);
173                         break;
174                 }
175                 break;
176         case F_P:
177                 (void)printf(pr->fmt, isprint(*bp) ? *bp : '.');
178                 break;
179         case F_STR:
180                 (void)printf(pr->fmt, (char *)bp);
181                 break;
182         case F_TEXT:
183                 (void)printf("%s", pr->fmt);
184                 break;
185         case F_U:
186                 conv_u(pr, bp);
187                 break;
188         case F_UINT:
189                 switch(pr->bcnt) {
190                 case 1:
191                         (void)printf(pr->fmt, (u_quad_t)*bp);
192                         break;
193                 case 2:
194                         bcopy(bp, &u2, sizeof(u2));
195                         (void)printf(pr->fmt, (u_quad_t)u2);
196                         break;
197                 case 4:
198                         bcopy(bp, &u4, sizeof(u4));
199                         (void)printf(pr->fmt, (u_quad_t)u4);
200                         break;
201                 case 8:
202                         bcopy(bp, &u8, sizeof(u8));
203                         (void)printf(pr->fmt, u8);
204                         break;
205                 }
206                 break;
207         }
208 }
209
210 void
211 bpad(pr)
212         PR *pr;
213 {
214         static char const *spec = " -0+#";
215         register char *p1, *p2;
216
217         /*
218          * Remove all conversion flags; '-' is the only one valid
219          * with %s, and it's not useful here.
220          */
221         pr->flags = F_BPAD;
222         pr->cchar[0] = 's';
223         pr->cchar[1] = '\0';
224         for (p1 = pr->fmt; *p1 != '%'; ++p1);
225         for (p2 = ++p1; *p1 && index(spec, *p1); ++p1);
226         while ((*p2++ = *p1++));
227 }
228
229 static char **_argv;
230
231 u_char *
232 get()
233 {
234         static int ateof = 1;
235         static u_char *curp, *savp;
236         register int n;
237         int need, nread;
238         int valid_save = 0;
239         u_char *tmpp;
240
241         if (!curp) {
242                 if ((curp = calloc(1, blocksize)) == NULL)
243                         err(1, NULL);
244                 if ((savp = calloc(1, blocksize)) == NULL)
245                         err(1, NULL);
246         } else {
247                 tmpp = curp;
248                 curp = savp;
249                 savp = tmpp;
250                 address += blocksize;
251                 valid_save = 1;
252         }
253         for (need = blocksize, nread = 0;;) {
254                 /*
255                  * if read the right number of bytes, or at EOF for one file,
256                  * and no other files are available, zero-pad the rest of the
257                  * block and set the end flag.
258                  */
259                 if (!length || (ateof && !next((char **)NULL))) {
260                         if (odmode && address < skip)
261                                 errx(1, "cannot skip past end of input");
262                         if (need == blocksize)
263                                 return((u_char *)NULL);
264                         if (vflag != ALL && 
265                             valid_save && 
266                             bcmp(curp, savp, nread) == 0) {
267                                 if (vflag != DUP)
268                                         (void)printf("*\n");
269                                 return((u_char *)NULL);
270                         }
271                         bzero((char *)curp + nread, need);
272                         eaddress = address + nread;
273                         return(curp);
274                 }
275                 n = fread((char *)curp + nread, sizeof(u_char),
276                     length == -1 ? need : MIN(length, need), stdin);
277                 if (!n) {
278                         if (ferror(stdin))
279                                 warn("%s", _argv[-1]);
280                         ateof = 1;
281                         continue;
282                 }
283                 ateof = 0;
284                 if (length != -1)
285                         length -= n;
286                 if (!(need -= n)) {
287                         if (vflag == ALL || vflag == FIRST ||
288                             valid_save == 0 ||
289                             bcmp(curp, savp, blocksize) != 0) {
290                                 if (vflag == DUP || vflag == FIRST)
291                                         vflag = WAIT;
292                                 return(curp);
293                         }
294                         if (vflag == WAIT)
295                                 (void)printf("*\n");
296                         vflag = DUP;
297                         address += blocksize;
298                         need = blocksize;
299                         nread = 0;
300                 }
301                 else
302                         nread += n;
303         }
304 }
305
306 int
307 next(argv)
308         char **argv;
309 {
310         extern int exitval;
311         static int done;
312         int statok;
313
314         if (argv) {
315                 _argv = argv;
316                 return(1);
317         }
318         for (;;) {
319                 if (*_argv) {
320                         if (!(freopen(*_argv, "r", stdin))) {
321                                 warn("%s", *_argv);
322                                 exitval = 1;
323                                 ++_argv;
324                                 continue;
325                         }
326                         statok = done = 1;
327                 } else {
328                         if (done++)
329                                 return(0);
330                         statok = 0;
331                 }
332                 if (skip)
333                         doskip(statok ? *_argv : "stdin", statok);
334                 if (*_argv)
335                         ++_argv;
336                 if (!skip)
337                         return(1);
338         }
339         /* NOTREACHED */
340 }
341
342 void
343 doskip(fname, statok)
344         const char *fname;
345         int statok;
346 {
347         register int cnt;
348         struct stat sb;
349
350         if (statok) {
351                 if (fstat(fileno(stdin), &sb))
352                         err(1, "%s", fname);
353                 if (S_ISREG(sb.st_mode) && skip >= sb.st_size) {
354                         address += sb.st_size;
355                         skip -= sb.st_size;
356                         return;
357                 }
358         }
359         if (S_ISREG(sb.st_mode)) {
360                 if (fseeko(stdin, skip, SEEK_SET))
361                         err(1, "%s", fname);
362                 address += skip;
363                 skip = 0;
364         } else {
365                 for (cnt = 0; cnt < skip; ++cnt)
366                         if (getchar() == EOF)
367                                 break;
368                 address += cnt;
369                 skip -= cnt;
370         }
371 }