]>
Commit | Line | Data |
---|---|---|
6dbe3af9 KZ |
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 | ||
6dbe3af9 KZ |
34 | #include <sys/param.h> |
35 | #include <sys/stat.h> | |
00c505d9 | 36 | #include <sys/types.h> |
6dbe3af9 KZ |
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" | |
85bf44b7 | 44 | #include "xalloc.h" |
3bbef076 | 45 | #include "c.h" |
3c44e03f | 46 | #include "nls.h" |
098ab077 | 47 | #include "colors.h" |
6dbe3af9 | 48 | |
1f77e9c3 OO |
49 | static void doskip(const char *, int, struct hexdump *); |
50 | static u_char *get(struct hexdump *); | |
fd6b7a7f | 51 | |
6dbe3af9 KZ |
52 | enum _vflag vflag = FIRST; |
53 | ||
54 | static off_t address; /* address/offset in stream */ | |
55 | static off_t eaddress; /* end address */ | |
6dbe3af9 | 56 | |
098ab077 OO |
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 | ||
ffc43748 | 110 | static inline void |
4c73d29c | 111 | print(struct hexdump_pr *pr, unsigned char *bp) { |
ffc43748 | 112 | |
098ab077 OO |
113 | const char *color = NULL; |
114 | ||
115 | if (pr->colorlist && (color = color_cond(pr, bp, pr->bcnt))) | |
116 | color_enable(color); | |
117 | ||
ffc43748 KZ |
118 | switch(pr->flags) { |
119 | case F_ADDRESS: | |
5988eede | 120 | printf(pr->fmt, address); |
ffc43748 KZ |
121 | break; |
122 | case F_BPAD: | |
cbc6c0da | 123 | printf(pr->fmt, ""); |
ffc43748 KZ |
124 | break; |
125 | case F_C: | |
126 | conv_c(pr, bp); | |
127 | break; | |
128 | case F_CHAR: | |
cbc6c0da | 129 | printf(pr->fmt, *bp); |
ffc43748 KZ |
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)); | |
cbc6c0da | 138 | printf(pr->fmt, fval); |
ffc43748 KZ |
139 | break; |
140 | case 8: | |
141 | memmove(&dval, bp, sizeof(dval)); | |
cbc6c0da | 142 | printf(pr->fmt, dval); |
ffc43748 KZ |
143 | break; |
144 | } | |
145 | break; | |
146 | } | |
147 | case F_INT: | |
148 | { | |
149 | short sval; /* int16_t */ | |
150 | int ival; /* int32_t */ | |
95961ee2 | 151 | long long Lval; /* int64_t, int64_t */ |
ffc43748 KZ |
152 | |
153 | switch(pr->bcnt) { | |
154 | case 1: | |
5500c817 | 155 | printf(pr->fmt, (unsigned long long) *bp); |
ffc43748 KZ |
156 | break; |
157 | case 2: | |
158 | memmove(&sval, bp, sizeof(sval)); | |
5500c817 | 159 | printf(pr->fmt, (unsigned long long) sval); |
ffc43748 KZ |
160 | break; |
161 | case 4: | |
162 | memmove(&ival, bp, sizeof(ival)); | |
5500c817 | 163 | printf(pr->fmt, (unsigned long long) ival); |
ffc43748 KZ |
164 | break; |
165 | case 8: | |
166 | memmove(&Lval, bp, sizeof(Lval)); | |
5988eede | 167 | printf(pr->fmt, Lval); |
ffc43748 KZ |
168 | break; |
169 | } | |
170 | break; | |
171 | } | |
172 | case F_P: | |
cbc6c0da | 173 | printf(pr->fmt, isprint(*bp) ? *bp : '.'); |
ffc43748 KZ |
174 | break; |
175 | case F_STR: | |
cbc6c0da | 176 | printf(pr->fmt, (char *)bp); |
ffc43748 KZ |
177 | break; |
178 | case F_TEXT: | |
cbc6c0da | 179 | printf("%s", pr->fmt); |
ffc43748 KZ |
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 */ | |
95961ee2 | 188 | unsigned long long Lval;/* u_int64_t, u_int64_t */ |
ffc43748 KZ |
189 | |
190 | switch(pr->bcnt) { | |
191 | case 1: | |
5500c817 | 192 | printf(pr->fmt, (unsigned long long) *bp); |
ffc43748 KZ |
193 | break; |
194 | case 2: | |
195 | memmove(&sval, bp, sizeof(sval)); | |
5500c817 | 196 | printf(pr->fmt, (unsigned long long) sval); |
ffc43748 KZ |
197 | break; |
198 | case 4: | |
199 | memmove(&ival, bp, sizeof(ival)); | |
5500c817 | 200 | printf(pr->fmt, (unsigned long long) ival); |
ffc43748 KZ |
201 | break; |
202 | case 8: | |
203 | memmove(&Lval, bp, sizeof(Lval)); | |
5988eede | 204 | printf(pr->fmt, Lval); |
ffc43748 KZ |
205 | break; |
206 | } | |
207 | break; | |
208 | } | |
209 | } | |
098ab077 OO |
210 | if (color) /* did we colorize something? */ |
211 | color_disable(); | |
6dbe3af9 KZ |
212 | } |
213 | ||
4c73d29c | 214 | static void bpad(struct hexdump_pr *pr) |
fd6b7a7f | 215 | { |
ffc43748 KZ |
216 | static const char *spec = " -0+#"; |
217 | char *p1, *p2; | |
fd6b7a7f KZ |
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; | |
ffc43748 KZ |
224 | pr->cchar[0] = 's'; |
225 | pr->cchar[1] = 0; | |
d6e5614e OO |
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 | ; | |
fd6b7a7f KZ |
237 | } |
238 | ||
1f77e9c3 | 239 | void display(struct hexdump *hex) |
6dbe3af9 | 240 | { |
cbc6c0da | 241 | register struct list_head *fs; |
bb8ae572 | 242 | register struct hexdump_fs *fss; |
046921da | 243 | register struct hexdump_fu *fu; |
4c73d29c | 244 | register struct hexdump_pr *pr; |
6dbe3af9 | 245 | register int cnt; |
95961ee2 | 246 | register unsigned char *bp; |
6dbe3af9 | 247 | off_t saveaddress; |
95961ee2 | 248 | unsigned char savech = 0, *savebp; |
9db51207 | 249 | struct list_head *p, *q, *r; |
6dbe3af9 | 250 | |
1f77e9c3 OO |
251 | while ((bp = get(hex)) != NULL) { |
252 | fs = &hex->fshead; savebp = bp; saveaddress = address; | |
cda43391 | 253 | |
9db51207 | 254 | list_for_each(p, fs) { |
bb8ae572 | 255 | fss = list_entry(p, struct hexdump_fs, fslist); |
cda43391 | 256 | |
bbc8c153 | 257 | list_for_each(q, &fss->fulist) { |
046921da | 258 | fu = list_entry(q, struct hexdump_fu, fulist); |
cda43391 | 259 | |
9db51207 OO |
260 | if (fu->flags&F_IGNORE) |
261 | break; | |
cda43391 | 262 | |
9db51207 | 263 | cnt = fu->reps; |
cda43391 | 264 | |
9db51207 | 265 | while (cnt) { |
bbc8c153 | 266 | list_for_each(r, &fu->prlist) { |
4c73d29c | 267 | pr = list_entry(r, struct hexdump_pr, prlist); |
cda43391 OO |
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; | |
9db51207 OO |
283 | } |
284 | --cnt; | |
285 | } | |
286 | } | |
cda43391 OO |
287 | bp = savebp; |
288 | address = saveaddress; | |
9db51207 OO |
289 | } |
290 | } | |
6dbe3af9 KZ |
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 | } | |
bbc8c153 | 301 | list_for_each (p, &endfu->prlist) { |
098ab077 | 302 | const char *color = NULL; |
c308e205 SK |
303 | |
304 | pr = list_entry(p, struct hexdump_pr, prlist); | |
098ab077 OO |
305 | if (colors_wanted() && pr->colorlist |
306 | && (color = color_cond(pr, bp, pr->bcnt))) { | |
307 | color_enable(color); | |
308 | } | |
309 | ||
6dbe3af9 KZ |
310 | switch(pr->flags) { |
311 | case F_ADDRESS: | |
5988eede | 312 | printf(pr->fmt, eaddress); |
6dbe3af9 KZ |
313 | break; |
314 | case F_TEXT: | |
9db51207 | 315 | printf("%s", pr->fmt); |
6dbe3af9 KZ |
316 | break; |
317 | } | |
098ab077 OO |
318 | if (color) /* did we highlight something? */ |
319 | color_disable(); | |
9db51207 | 320 | } |
6dbe3af9 KZ |
321 | } |
322 | } | |
323 | ||
6dbe3af9 KZ |
324 | static char **_argv; |
325 | ||
22853e4a | 326 | static u_char * |
1f77e9c3 | 327 | get(struct hexdump *hex) |
6dbe3af9 | 328 | { |
6dbe3af9 KZ |
329 | static int ateof = 1; |
330 | static u_char *curp, *savp; | |
b6b0ea09 | 331 | ssize_t n, need, nread; |
6dbe3af9 KZ |
332 | u_char *tmpp; |
333 | ||
334 | if (!curp) { | |
1f77e9c3 OO |
335 | curp = xcalloc(1, hex->blocksize); |
336 | savp = xcalloc(1, hex->blocksize); | |
6dbe3af9 KZ |
337 | } else { |
338 | tmpp = curp; | |
339 | curp = savp; | |
340 | savp = tmpp; | |
1f77e9c3 | 341 | address += hex->blocksize; |
6dbe3af9 | 342 | } |
1f77e9c3 | 343 | need = hex->blocksize, nread = 0; |
f77ad413 | 344 | while (TRUE) { |
6dbe3af9 KZ |
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 | */ | |
1f77e9c3 OO |
350 | if (!hex->length || (ateof && !next(NULL, hex))) { |
351 | if (need == hex->blocksize) | |
d2740b0e | 352 | goto retnul; |
ffc43748 KZ |
353 | if (!need && vflag != ALL && |
354 | !memcmp(curp, savp, nread)) { | |
6dbe3af9 | 355 | if (vflag != DUP) |
cbc6c0da | 356 | printf("*\n"); |
d2740b0e | 357 | goto retnul; |
6dbe3af9 | 358 | } |
42c9ce52 KZ |
359 | if (need > 0) |
360 | memset((char *)curp + nread, 0, need); | |
6dbe3af9 KZ |
361 | eaddress = address + nread; |
362 | return(curp); | |
363 | } | |
3c44e03f SK |
364 | if (fileno(stdin) == -1) { |
365 | warnx(_("all input file arguments failed")); | |
d2740b0e | 366 | goto retnul; |
3c44e03f | 367 | } |
95961ee2 | 368 | n = fread((char *)curp + nread, sizeof(unsigned char), |
1f77e9c3 | 369 | hex->length == -1 ? need : min(hex->length, need), stdin); |
6dbe3af9 KZ |
370 | if (!n) { |
371 | if (ferror(stdin)) | |
85bf44b7 | 372 | warn("%s", _argv[-1]); |
6dbe3af9 KZ |
373 | ateof = 1; |
374 | continue; | |
375 | } | |
376 | ateof = 0; | |
1f77e9c3 OO |
377 | if (hex->length != -1) |
378 | hex->length -= n; | |
6dbe3af9 KZ |
379 | if (!(need -= n)) { |
380 | if (vflag == ALL || vflag == FIRST || | |
1f77e9c3 | 381 | memcmp(curp, savp, hex->blocksize)) { |
6dbe3af9 KZ |
382 | if (vflag == DUP || vflag == FIRST) |
383 | vflag = WAIT; | |
384 | return(curp); | |
385 | } | |
386 | if (vflag == WAIT) | |
cbc6c0da | 387 | printf("*\n"); |
6dbe3af9 | 388 | vflag = DUP; |
1f77e9c3 OO |
389 | address += hex->blocksize; |
390 | need = hex->blocksize; | |
6dbe3af9 KZ |
391 | nread = 0; |
392 | } | |
393 | else | |
394 | nread += n; | |
395 | } | |
d2740b0e OO |
396 | retnul: |
397 | free (curp); | |
398 | free (savp); | |
399 | return NULL; | |
6dbe3af9 KZ |
400 | } |
401 | ||
1f77e9c3 | 402 | int next(char **argv, struct hexdump *hex) |
6dbe3af9 | 403 | { |
6dbe3af9 | 404 | static int done; |
4ccf1137 | 405 | int statok; |
6dbe3af9 KZ |
406 | |
407 | if (argv) { | |
408 | _argv = argv; | |
409 | return(1); | |
410 | } | |
c889d525 | 411 | while (TRUE) { |
6dbe3af9 KZ |
412 | if (*_argv) { |
413 | if (!(freopen(*_argv, "r", stdin))) { | |
85bf44b7 | 414 | warn("%s", *_argv); |
1f77e9c3 | 415 | hex->exitval = EXIT_FAILURE; |
6dbe3af9 KZ |
416 | ++_argv; |
417 | continue; | |
418 | } | |
419 | statok = done = 1; | |
420 | } else { | |
421 | if (done++) | |
4ccf1137 | 422 | return(0); |
6dbe3af9 KZ |
423 | statok = 0; |
424 | } | |
1f77e9c3 OO |
425 | if (hex->skip) |
426 | doskip(statok ? *_argv : "stdin", statok, hex); | |
6dbe3af9 KZ |
427 | if (*_argv) |
428 | ++_argv; | |
1f77e9c3 | 429 | if (!hex->skip) |
6dbe3af9 KZ |
430 | return(1); |
431 | } | |
432 | /* NOTREACHED */ | |
433 | } | |
434 | ||
fd6b7a7f | 435 | static void |
1f77e9c3 | 436 | doskip(const char *fname, int statok, struct hexdump *hex) |
6dbe3af9 | 437 | { |
6dbe3af9 KZ |
438 | struct stat sbuf; |
439 | ||
440 | if (statok) { | |
85bf44b7 SK |
441 | if (fstat(fileno(stdin), &sbuf)) |
442 | err(EXIT_FAILURE, "%s", fname); | |
1f77e9c3 | 443 | if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) { |
fd6b7a7f | 444 | /* If size valid and skip >= size */ |
1f77e9c3 | 445 | hex->skip -= sbuf.st_size; |
6dbe3af9 KZ |
446 | address += sbuf.st_size; |
447 | return; | |
448 | } | |
449 | } | |
ffc43748 | 450 | /* sbuf may be undefined here - do not test it */ |
1f77e9c3 | 451 | if (fseek(stdin, hex->skip, SEEK_SET)) |
85bf44b7 | 452 | err(EXIT_FAILURE, "%s", fname); |
1f77e9c3 OO |
453 | address += hex->skip; |
454 | hex->skip = 0; | |
6dbe3af9 | 455 | } |