]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - text-utils/hexdump-parse.c
2 * Copyright (c) 1989 The Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
34 /* 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL>
35 * - added Native Language Support
38 #include <sys/types.h>
50 static void escape(char *p1
);
51 static struct list_head
*color_fmt(char *cfmt
, int bcnt
);
53 static void __attribute__ ((__noreturn__
)) badcnt(const char *s
)
55 errx(EXIT_FAILURE
, _("bad byte count for conversion character %s"), s
);
58 static void __attribute__ ((__noreturn__
)) badsfmt(void)
60 errx(EXIT_FAILURE
, _("%%s requires a precision or a byte count"));
63 static void __attribute__ ((__noreturn__
)) badfmt(const char *fmt
)
65 errx(EXIT_FAILURE
, _("bad format {%s}"), fmt
);
68 static void __attribute__ ((__noreturn__
)) badconv(const char *ch
)
70 errx(EXIT_FAILURE
, _("bad conversion character %%%s"), ch
);
73 #define first_letter(s,f) strchr(f, *(s))
75 struct hexdump_fu
*endfu
; /* format at end-of-data */
77 void addfile(char *name
, struct hexdump
*hex
)
79 char *fmt
, *buf
= NULL
;
83 if ((fp
= fopen(name
, "r")) == NULL
)
84 err(EXIT_FAILURE
, _("can't read %s"), name
);
86 while (getline(&buf
, &n
, fp
) != -1) {
89 while (*fmt
&& isspace(*fmt
))
91 if (!*fmt
|| *fmt
== '#')
101 void add_fmt(const char *fmt
, struct hexdump
*hex
)
103 const char *p
, *savep
;
104 struct hexdump_fs
*tfs
;
105 struct hexdump_fu
*tfu
;
107 /* Start new linked list of format units. */
108 tfs
= xcalloc(1, sizeof(struct hexdump_fs
));
109 INIT_LIST_HEAD(&tfs
->fslist
);
110 INIT_LIST_HEAD(&tfs
->fulist
);
111 list_add_tail(&tfs
->fslist
, &hex
->fshead
);
113 /* Take the format string and break it up into format units. */
116 /* Skip leading white space. */
117 if (!*(p
= skip_space(p
)))
120 /* Allocate a new format unit and link it in. */
121 tfu
= xcalloc(1, sizeof(struct hexdump_fu
));
124 INIT_LIST_HEAD(&tfu
->fulist
);
125 INIT_LIST_HEAD(&tfu
->prlist
);
126 list_add_tail(&tfu
->fulist
, &tfs
->fulist
);
128 /* If leading digit, repetition count. */
133 if (!isspace(*p
) && *p
!= '/')
135 /* may overwrite either white space or slash */
136 tfu
->reps
= atoi(savep
);
137 tfu
->flags
= F_SETREP
;
138 /* skip trailing white space */
142 /* Skip slash and trailing white space. */
153 tfu
->bcnt
= atoi(savep
);
154 /* skip trailing white space */
166 tfu
->fmt
= xmalloc(p
- savep
+ 1);
167 xstrncpy(tfu
->fmt
, savep
, p
- savep
+ 1);
173 static const char *spec
= ".#-+ 0123456789";
175 int block_size(struct hexdump_fs
*fs
)
177 struct hexdump_fu
*fu
;
178 int bcnt
, prec
, cursize
= 0;
182 /* figure out the data block size needed for each format unit */
183 list_for_each (p
, &fs
->fulist
) {
184 fu
= list_entry(p
, struct hexdump_fu
, fulist
);
186 cursize
+= fu
->bcnt
* fu
->reps
;
197 * skip any special chars -- save precision in
198 * case it's a %s format.
200 while (strchr(spec
+ 1, *++fmt
))
202 if (*fmt
== '.' && isdigit(*++fmt
)) {
204 while (isdigit(*++fmt
))
207 if (first_letter(fmt
, "diouxX"))
209 else if (first_letter(fmt
, "efgEG"))
211 else if (*fmt
== 's')
213 else if (*fmt
== 'c' || (*fmt
== '_' && first_letter(++fmt
, "cpu")))
217 cursize
+= bcnt
* fu
->reps
;
222 void rewrite_rules(struct hexdump_fs
*fs
, struct hexdump
*hex
)
224 enum { NOTOKAY
, USEBCNT
, USEPREC
} sokay
;
225 struct hexdump_pr
*pr
;
226 struct hexdump_fu
*fu
;
227 struct list_head
*p
, *q
;
228 char *p1
, *p2
, *fmtp
;
232 list_for_each (p
, &fs
->fulist
) {
233 fu
= list_entry(p
, struct hexdump_fu
, fulist
);
235 * Break each format unit into print units; each
236 * conversion character gets its own.
241 pr
= xcalloc(1, sizeof(struct hexdump_pr
));
242 INIT_LIST_HEAD(&pr
->prlist
);
243 list_add_tail(&pr
->prlist
, &fu
->prlist
);
245 /* Skip preceding text and up to the next % sign. */
247 while (*p1
&& *p1
!= '%')
250 /* Only text in the string. */
252 pr
->fmt
= xstrdup(fmtp
);
258 * Get precision for %s -- if have a byte count, don't
263 /* skip to conversion character */
264 for (p1
++; strchr(spec
, *p1
); p1
++)
267 /* skip any special chars, field width */
268 while (strchr(spec
+ 1, *++p1
))
270 if (*p1
== '.' && isdigit(*++p1
)) {
273 while (isdigit(*++p1
))
279 p2
= p1
+ 1; /* Set end pointer. */
280 cs
[0] = *p1
; /* Set conversion string. */
284 * Figure out the byte count for each conversion;
285 * rewrite the format as necessary, set up blank-
286 * padding for end of data.
299 } else if (first_letter(cs
, "di")) {
302 } else if (first_letter(cs
, "ouxX")) {
322 } else if (first_letter(cs
, "efgEG")) {
336 } else if(*cs
== 's') {
348 } else if (*cs
== '_') {
353 fu
->flags
|= F_IGNORE
;
356 pr
->flags
= F_ADDRESS
;
358 if (first_letter(p1
+ 2, "dox")) {
370 /* cs[0] = 'c'; set in conv_c */
378 /* cs[0] = 'c'; set in conv_u */
379 isint2
: switch(fu
->bcnt
) {
398 /* Color unit(s) specified */
399 if (*p2
== '_' && p2
[1] == 'L') {
400 if (colors_wanted()) {
403 /* "cut out" the color_unit(s) */
405 p2
= strrchr(p2
, ']');
407 pr
->colorlist
= color_fmt(xstrndup(a
, p2
++ - a
), pr
->bcnt
);
411 /* we don't want colors, quietly skip over them */
413 p2
= strrchr(p2
, ']');
414 /* be a bit louder if we don't know how to skip over them */
421 * Copy to hexdump_pr format string, set conversion character
422 * pointer, update original.
426 pr
->fmt
= xmalloc(strlen(fmtp
) + strlen(cs
) + 1);
427 strcpy(pr
->fmt
, fmtp
);
430 pr
->cchar
= pr
->fmt
+ (p1
- fmtp
);
433 /* Only one conversion character if byte count */
434 if (!(pr
->flags
&F_ADDRESS
) && fu
->bcnt
&& nconv
++)
436 _("byte count with multiple conversion characters"));
439 * If format unit byte count not specified, figure it out
440 * so can adjust rep count later.
443 list_for_each(q
, &fu
->prlist
)
445 += (list_entry(q
, struct hexdump_pr
, prlist
))->bcnt
;
448 * If the format string interprets any data at all, and it's
449 * not the same as the blocksize, and its last format unit
450 * interprets any data at all, and has no iteration count,
451 * repeat it as necessary.
453 * If rep count is greater than 1, no trailing whitespace
454 * gets output from the last iteration of the format unit.
456 list_for_each (p
, &fs
->fulist
) {
457 fu
= list_entry(p
, struct hexdump_fu
, fulist
);
459 if (list_entry_is_last(&fu
->fulist
, &fs
->fulist
) &&
460 fs
->bcnt
< hex
->blocksize
&&
461 !(fu
->flags
&F_SETREP
) && fu
->bcnt
)
462 fu
->reps
+= (hex
->blocksize
- fs
->bcnt
) / fu
->bcnt
;
463 if (fu
->reps
> 1 && !list_empty(&fu
->prlist
)) {
464 pr
= list_last_entry(&fu
->prlist
, struct hexdump_pr
, prlist
);
467 for (p1
= pr
->fmt
, p2
= NULL
; *p1
; ++p1
)
468 p2
= isspace(*p1
) ? p1
: NULL
;
475 /* [!]color[:string|:hex_number|:oct_number][@offt|@offt_start-offt_end],... */
476 static struct list_head
*color_fmt(char *cfmt
, int bcnt
)
478 struct hexdump_clr
*hc
, *hcnext
;
479 struct list_head
*ret_head
;
482 ret_head
= xmalloc(sizeof(struct list_head
));
483 hcnext
= hc
= xcalloc(1, sizeof(struct hexdump_clr
));
485 INIT_LIST_HEAD(&hc
->colorlist
);
486 INIT_LIST_HEAD(ret_head
);
487 list_add_tail(&hc
->colorlist
, ret_head
);
490 while (cfmt
&& *cfmt
) {
492 /* invert this condition */
498 clr
= xstrndup(cfmt
, strcspn(cfmt
, ":@,"));
500 hcnext
->fmt
= color_sequence_from_colorname(clr
);
506 /* only colorize this specific value */
509 /* a hex or oct value */
514 if (cfmt
[1] == 'x' || cfmt
[1] == 'X')
515 hcnext
->val
= strtoul(cfmt
+ 2, &end
, 16);
517 hcnext
->val
= strtoul(cfmt
, &end
, 8);
518 if (errno
|| end
== cfmt
)
528 /* temporarily null-delimit the format, so we can reverse-search
529 * for the start of an offset specifier */
530 fmt_end
= strcspn(cfmt
, ",");
531 endchar
= cfmt
[fmt_end
];
532 cfmt
[fmt_end
] = '\0';
533 endstr
= strrchr(cfmt
, '@');
536 if (endstr
[1] != '\0')
538 hcnext
->str
= xstrndup(cfmt
, endstr
- cfmt
+ 1);
540 hcnext
->str
= xstrndup(cfmt
, fmt_end
);
542 /* restore the character */
543 cfmt
[fmt_end
] = endchar
;
544 cfmt
+= strlen(hcnext
->str
);
547 /* no specific value */
551 /* only colorize at this offset */
552 hcnext
->range
= bcnt
;
553 if (cfmt
&& *cfmt
== '@') {
555 hcnext
->offt
= strtoul(++cfmt
, &cfmt
, 10);
565 strtoul(cfmt
, &cfmt
, 10) - hcnext
->offt
+ 1;
568 /* offset range must be between 0 and format byte count */
569 if (hcnext
->range
< 0)
571 /* the offset extends over several print units, clone
572 * the condition, link it in and adjust the address/offset */
573 while (hcnext
->range
> bcnt
) {
574 hc
= xcalloc(1, sizeof(struct hexdump_clr
));
575 memcpy(hc
, hcnext
, sizeof(struct hexdump_clr
));
579 INIT_LIST_HEAD(&hc
->colorlist
);
580 list_add_tail(&hc
->colorlist
, ret_head
);
582 hcnext
->offt
+= bcnt
;
583 hcnext
->range
-= bcnt
;
586 /* no specific offset */
588 hcnext
->offt
= (off_t
)-1;
590 /* check if the string we're looking for is the same length as the range */
591 if (hcnext
->str
&& (int)strlen(hcnext
->str
) != hcnext
->range
)
594 /* link in another condition */
595 if (cfmt
&& *cfmt
== ',') {
598 hcnext
= xcalloc(1, sizeof(struct hexdump_clr
));
599 INIT_LIST_HEAD(&hcnext
->colorlist
);
600 list_add_tail(&hcnext
->colorlist
, ret_head
);
606 static void escape(char *p1
)
610 /* alphabetic escape sequences have to be done in place */