K&R style function removal. Update functions to ANSI style.
[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.3 2003/10/04 20:36:45 hmp 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(void)
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 *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);
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                         bcopy(bp, &f4, sizeof(f4));
141                         (void)printf(pr->fmt, f4);
142                         break;
143                 case 8:
144                         bcopy(bp, &f8, sizeof(f8));
145                         (void)printf(pr->fmt, f8);
146                         break;
147                 default:
148                         if (pr->bcnt == sizeof(long double)) {
149                                 bcopy(bp, &ldbl, sizeof(ldbl));
150                                 (void)printf(pr->fmt, ldbl);
151                         }
152                         break;
153                 }
154                 break;
155         case F_INT:
156                 switch(pr->bcnt) {
157                 case 1:
158                         (void)printf(pr->fmt, (quad_t)(signed char)*bp);
159                         break;
160                 case 2:
161                         bcopy(bp, &s2, sizeof(s2));
162                         (void)printf(pr->fmt, (quad_t)s2);
163                         break;
164                 case 4:
165                         bcopy(bp, &s4, sizeof(s4));
166                         (void)printf(pr->fmt, (quad_t)s4);
167                         break;
168                 case 8:
169                         bcopy(bp, &s8, sizeof(s8));
170                         (void)printf(pr->fmt, s8);
171                         break;
172                 }
173                 break;
174         case F_P:
175                 (void)printf(pr->fmt, isprint(*bp) ? *bp : '.');
176                 break;
177         case F_STR:
178                 (void)printf(pr->fmt, (char *)bp);
179                 break;
180         case F_TEXT:
181                 (void)printf("%s", pr->fmt);
182                 break;
183         case F_U:
184                 conv_u(pr, bp);
185                 break;
186         case F_UINT:
187                 switch(pr->bcnt) {
188                 case 1:
189                         (void)printf(pr->fmt, (u_quad_t)*bp);
190                         break;
191                 case 2:
192                         bcopy(bp, &u2, sizeof(u2));
193                         (void)printf(pr->fmt, (u_quad_t)u2);
194                         break;
195                 case 4:
196                         bcopy(bp, &u4, sizeof(u4));
197                         (void)printf(pr->fmt, (u_quad_t)u4);
198                         break;
199                 case 8:
200                         bcopy(bp, &u8, sizeof(u8));
201                         (void)printf(pr->fmt, u8);
202                         break;
203                 }
204                 break;
205         }
206 }
207
208 void
209 bpad(PR *pr)
210 {
211         static char const *spec = " -0+#";
212         register 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 && index(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         register 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         extern int exitval;
307         static int done;
308         int statok;
309
310         if (argv) {
311                 _argv = argv;
312                 return(1);
313         }
314         for (;;) {
315                 if (*_argv) {
316                         if (!(freopen(*_argv, "r", stdin))) {
317                                 warn("%s", *_argv);
318                                 exitval = 1;
319                                 ++_argv;
320                                 continue;
321                         }
322                         statok = done = 1;
323                 } else {
324                         if (done++)
325                                 return(0);
326                         statok = 0;
327                 }
328                 if (skip)
329                         doskip(statok ? *_argv : "stdin", statok);
330                 if (*_argv)
331                         ++_argv;
332                 if (!skip)
333                         return(1);
334         }
335         /* NOTREACHED */
336 }
337
338 void
339 doskip(const char *fname, int statok)
340 {
341         register int cnt;
342         struct stat sb;
343
344         if (statok) {
345                 if (fstat(fileno(stdin), &sb))
346                         err(1, "%s", fname);
347                 if (S_ISREG(sb.st_mode) && skip >= sb.st_size) {
348                         address += sb.st_size;
349                         skip -= sb.st_size;
350                         return;
351                 }
352         }
353         if (S_ISREG(sb.st_mode)) {
354                 if (fseeko(stdin, skip, SEEK_SET))
355                         err(1, "%s", fname);
356                 address += skip;
357                 skip = 0;
358         } else {
359                 for (cnt = 0; cnt < skip; ++cnt)
360                         if (getchar() == EOF)
361                                 break;
362                 address += cnt;
363                 skip -= cnt;
364         }
365 }