]> git.ipfire.org Git - thirdparty/util-linux.git/blob - text-utils/hexdump-display.c
scriptlive: add new command to re-execute script(1) typescript
[thirdparty/util-linux.git] / text-utils / hexdump-display.c
1 /*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * 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
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "hexdump.h"
44 #include "xalloc.h"
45 #include "c.h"
46 #include "nls.h"
47 #include "colors.h"
48
49 static void doskip(const char *, int, struct hexdump *);
50 static u_char *get(struct hexdump *);
51
52 enum _vflag vflag = FIRST;
53
54 static off_t address; /* address/offset in stream */
55 static off_t eaddress; /* end address */
56
57 static const char *color_cond(struct hexdump_pr *pr, unsigned char *bp, int bcnt)
58 {
59 register struct list_head *p;
60 register struct hexdump_clr *clr;
61 off_t offt;
62 int match;
63
64 list_for_each(p, pr->colorlist) {
65 clr = list_entry(p, struct hexdump_clr, colorlist);
66 offt = clr->offt;
67 match = 0;
68
69 /* no offset or offset outside this print unit */
70 if (offt < 0)
71 offt = address;
72 if (offt < address || offt + clr->range > address + bcnt)
73 continue;
74
75 /* match a string */
76 if (clr->str) {
77 if (pr->flags == F_ADDRESS) {
78 /* TODO */
79 }
80 else if (!strncmp(clr->str, (char *)bp + offt
81 - address, clr->range))
82 match = 1;
83 /* match a value */
84 } else if (clr->val != -1) {
85 int val = 0;
86 /* addresses are not part of the input, so we can't
87 * compare with the contents of bp */
88 if (pr->flags == F_ADDRESS) {
89 if (clr->val == address)
90 match = 1;
91 } else {
92 memcpy(&val, bp + offt - address, clr->range);
93 if (val == clr->val)
94 match = 1;
95 }
96 /* no conditions, only a color was specified */
97 } else
98 return clr->fmt;
99
100 /* return the format string or check for another */
101 if (match ^ clr->invert)
102 return clr->fmt;
103 continue;
104 }
105
106 /* no match */
107 return NULL;
108 }
109
110 static inline void
111 print(struct hexdump_pr *pr, unsigned char *bp) {
112
113 const char *color = NULL;
114
115 if (pr->colorlist && (color = color_cond(pr, bp, pr->bcnt)))
116 color_enable(color);
117
118 switch(pr->flags) {
119 case F_ADDRESS:
120 printf(pr->fmt, address);
121 break;
122 case F_BPAD:
123 printf(pr->fmt, "");
124 break;
125 case F_C:
126 conv_c(pr, bp);
127 break;
128 case F_CHAR:
129 printf(pr->fmt, *bp);
130 break;
131 case F_DBL:
132 {
133 double dval;
134 float fval;
135 switch(pr->bcnt) {
136 case 4:
137 memmove(&fval, bp, sizeof(fval));
138 printf(pr->fmt, fval);
139 break;
140 case 8:
141 memmove(&dval, bp, sizeof(dval));
142 printf(pr->fmt, dval);
143 break;
144 }
145 break;
146 }
147 case F_INT:
148 {
149 short sval; /* int16_t */
150 int ival; /* int32_t */
151 long long Lval; /* int64_t, int64_t */
152
153 switch(pr->bcnt) {
154 case 1:
155 printf(pr->fmt, (unsigned long long) *bp);
156 break;
157 case 2:
158 memmove(&sval, bp, sizeof(sval));
159 printf(pr->fmt, (unsigned long long) sval);
160 break;
161 case 4:
162 memmove(&ival, bp, sizeof(ival));
163 printf(pr->fmt, (unsigned long long) ival);
164 break;
165 case 8:
166 memmove(&Lval, bp, sizeof(Lval));
167 printf(pr->fmt, Lval);
168 break;
169 }
170 break;
171 }
172 case F_P:
173 printf(pr->fmt, isprint(*bp) ? *bp : '.');
174 break;
175 case F_STR:
176 printf(pr->fmt, (char *)bp);
177 break;
178 case F_TEXT:
179 printf("%s", pr->fmt);
180 break;
181 case F_U:
182 conv_u(pr, bp);
183 break;
184 case F_UINT:
185 {
186 unsigned short sval; /* u_int16_t */
187 unsigned int ival; /* u_int32_t */
188 unsigned long long Lval;/* u_int64_t, u_int64_t */
189
190 switch(pr->bcnt) {
191 case 1:
192 printf(pr->fmt, (unsigned long long) *bp);
193 break;
194 case 2:
195 memmove(&sval, bp, sizeof(sval));
196 printf(pr->fmt, (unsigned long long) sval);
197 break;
198 case 4:
199 memmove(&ival, bp, sizeof(ival));
200 printf(pr->fmt, (unsigned long long) ival);
201 break;
202 case 8:
203 memmove(&Lval, bp, sizeof(Lval));
204 printf(pr->fmt, Lval);
205 break;
206 }
207 break;
208 }
209 }
210 if (color) /* did we colorize something? */
211 color_disable();
212 }
213
214 static void bpad(struct hexdump_pr *pr)
215 {
216 static const char *spec = " -0+#";
217 char *p1, *p2;
218
219 /*
220 * remove all conversion flags; '-' is the only one valid
221 * with %s, and it's not useful here.
222 */
223 pr->flags = F_BPAD;
224 pr->cchar[0] = 's';
225 pr->cchar[1] = 0;
226
227 p1 = pr->fmt;
228 while (*p1 != '%')
229 ++p1;
230
231 p2 = ++p1;
232 while (*p1 && strchr(spec, *p1))
233 ++p1;
234
235 while ((*p2++ = *p1++))
236 ;
237 }
238
239 void display(struct hexdump *hex)
240 {
241 register struct list_head *fs;
242 register struct hexdump_fs *fss;
243 register struct hexdump_fu *fu;
244 register struct hexdump_pr *pr;
245 register int cnt;
246 register unsigned char *bp;
247 off_t saveaddress;
248 unsigned char savech = 0, *savebp;
249 struct list_head *p, *q, *r;
250
251 while ((bp = get(hex)) != NULL) {
252 fs = &hex->fshead; savebp = bp; saveaddress = address;
253
254 list_for_each(p, fs) {
255 fss = list_entry(p, struct hexdump_fs, fslist);
256
257 list_for_each(q, &fss->fulist) {
258 fu = list_entry(q, struct hexdump_fu, fulist);
259
260 if (fu->flags&F_IGNORE)
261 break;
262
263 cnt = fu->reps;
264
265 while (cnt) {
266 list_for_each(r, &fu->prlist) {
267 pr = list_entry(r, struct hexdump_pr, prlist);
268
269 if (eaddress && address >= eaddress
270 && !(pr->flags&(F_TEXT|F_BPAD)))
271 bpad(pr);
272
273 if (cnt == 1 && pr->nospace) {
274 savech = *pr->nospace;
275 *pr->nospace = '\0';
276 print(pr, bp);
277 *pr->nospace = savech;
278 } else
279 print(pr, bp);
280
281 address += pr->bcnt;
282 bp += pr->bcnt;
283 }
284 --cnt;
285 }
286 }
287 bp = savebp;
288 address = saveaddress;
289 }
290 }
291 if (endfu) {
292 /*
293 * if eaddress not set, error or file size was multiple of
294 * blocksize, and no partial block ever found.
295 */
296 if (!eaddress) {
297 if (!address)
298 return;
299 eaddress = address;
300 }
301 list_for_each (p, &endfu->prlist) {
302 const char *color = NULL;
303
304 pr = list_entry(p, struct hexdump_pr, prlist);
305 if (colors_wanted() && pr->colorlist
306 && (color = color_cond(pr, bp, pr->bcnt))) {
307 color_enable(color);
308 }
309
310 switch(pr->flags) {
311 case F_ADDRESS:
312 printf(pr->fmt, eaddress);
313 break;
314 case F_TEXT:
315 printf("%s", pr->fmt);
316 break;
317 }
318 if (color) /* did we highlight something? */
319 color_disable();
320 }
321 }
322 }
323
324 static char **_argv;
325
326 static u_char *
327 get(struct hexdump *hex)
328 {
329 static int ateof = 1;
330 static u_char *curp, *savp;
331 ssize_t n, need, nread;
332 u_char *tmpp;
333
334 if (!curp) {
335 curp = xcalloc(1, hex->blocksize);
336 savp = xcalloc(1, hex->blocksize);
337 } else {
338 tmpp = curp;
339 curp = savp;
340 savp = tmpp;
341 address += hex->blocksize;
342 }
343 need = hex->blocksize, nread = 0;
344 while (TRUE) {
345 /*
346 * if read the right number of bytes, or at EOF for one file,
347 * and no other files are available, zero-pad the rest of the
348 * block and set the end flag.
349 */
350 if (!hex->length || (ateof && !next(NULL, hex))) {
351 if (need == hex->blocksize)
352 goto retnul;
353 if (!need && vflag != ALL &&
354 !memcmp(curp, savp, nread)) {
355 if (vflag != DUP)
356 printf("*\n");
357 goto retnul;
358 }
359 if (need > 0)
360 memset((char *)curp + nread, 0, need);
361 eaddress = address + nread;
362 return(curp);
363 }
364 if (fileno(stdin) == -1) {
365 warnx(_("all input file arguments failed"));
366 goto retnul;
367 }
368 n = fread((char *)curp + nread, sizeof(unsigned char),
369 hex->length == -1 ? need : min(hex->length, need), stdin);
370 if (!n) {
371 if (ferror(stdin))
372 warn("%s", _argv[-1]);
373 ateof = 1;
374 continue;
375 }
376 ateof = 0;
377 if (hex->length != -1)
378 hex->length -= n;
379 if (!(need -= n)) {
380 if (vflag == ALL || vflag == FIRST ||
381 memcmp(curp, savp, hex->blocksize)) {
382 if (vflag == DUP || vflag == FIRST)
383 vflag = WAIT;
384 return(curp);
385 }
386 if (vflag == WAIT)
387 printf("*\n");
388 vflag = DUP;
389 address += hex->blocksize;
390 need = hex->blocksize;
391 nread = 0;
392 }
393 else
394 nread += n;
395 }
396 retnul:
397 free (curp);
398 free (savp);
399 return NULL;
400 }
401
402 int next(char **argv, struct hexdump *hex)
403 {
404 static int done;
405 int statok;
406
407 if (argv) {
408 _argv = argv;
409 return(1);
410 }
411 while (TRUE) {
412 if (*_argv) {
413 if (!(freopen(*_argv, "r", stdin))) {
414 warn("%s", *_argv);
415 hex->exitval = EXIT_FAILURE;
416 ++_argv;
417 continue;
418 }
419 statok = done = 1;
420 } else {
421 if (done++)
422 return(0);
423 statok = 0;
424 }
425 if (hex->skip)
426 doskip(statok ? *_argv : "stdin", statok, hex);
427 if (*_argv)
428 ++_argv;
429 if (!hex->skip)
430 return(1);
431 }
432 /* NOTREACHED */
433 }
434
435 static void
436 doskip(const char *fname, int statok, struct hexdump *hex)
437 {
438 struct stat sbuf;
439
440 if (statok) {
441 if (fstat(fileno(stdin), &sbuf))
442 err(EXIT_FAILURE, "%s", fname);
443 if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) {
444 /* If size valid and skip >= size */
445 hex->skip -= sbuf.st_size;
446 address += sbuf.st_size;
447 return;
448 }
449 }
450 /* sbuf may be undefined here - do not test it */
451 if (fseek(stdin, hex->skip, SEEK_SET))
452 err(EXIT_FAILURE, "%s", fname);
453 address += hex->skip;
454 hex->skip = 0;
455 }