]>
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. */
131 while (isdigit(*p
) && ++p
)
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. */
149 while (isdigit(*p
) && ++p
)
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 while (++p1
&& strchr(spec
, *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")) {
321 } else if (first_letter(cs
, "efgEG")) {
335 } else if(*cs
== 's') {
347 } else if (*cs
== '_') {
352 fu
->flags
|= F_IGNORE
;
355 pr
->flags
= F_ADDRESS
;
357 if (first_letter(p1
+ 2, "dox")) {
368 /* cs[0] = 'c'; set in conv_c */
376 /* cs[0] = 'c'; set in conv_u */
377 isint2
: switch(fu
->bcnt
) {
396 /* Color unit(s) specified */
397 if (*p2
== '_' && p2
[1] == 'L') {
398 if (colors_wanted()) {
401 /* "cut out" the color_unit(s) */
403 p2
= strrchr(p2
, ']');
405 pr
->colorlist
= color_fmt(xstrndup(a
, p2
++ - a
), pr
->bcnt
);
409 /* we don't want colors, quietly skip over them */
411 p2
= strrchr(p2
, ']');
412 /* be a bit louder if we don't know how to skip over them */
419 * Copy to hexdump_pr format string, set conversion character
420 * pointer, update original.
424 pr
->fmt
= xmalloc(strlen(fmtp
) + strlen(cs
) + 1);
425 strcpy(pr
->fmt
, fmtp
);
428 pr
->cchar
= pr
->fmt
+ (p1
- fmtp
);
431 /* Only one conversion character if byte count */
432 if (!(pr
->flags
&F_ADDRESS
) && fu
->bcnt
&& nconv
++)
434 _("byte count with multiple conversion characters"));
437 * If format unit byte count not specified, figure it out
438 * so can adjust rep count later.
441 list_for_each(q
, &fu
->prlist
)
443 += (list_entry(q
, struct hexdump_pr
, prlist
))->bcnt
;
446 * If the format string interprets any data at all, and it's
447 * not the same as the blocksize, and its last format unit
448 * interprets any data at all, and has no iteration count,
449 * repeat it as necessary.
451 * If rep count is greater than 1, no trailing whitespace
452 * gets output from the last iteration of the format unit.
454 list_for_each (p
, &fs
->fulist
) {
455 fu
= list_entry(p
, struct hexdump_fu
, fulist
);
457 if (list_entry_is_last(&fu
->fulist
, &fs
->fulist
) &&
458 fs
->bcnt
< hex
->blocksize
&&
459 !(fu
->flags
&F_SETREP
) && fu
->bcnt
)
460 fu
->reps
+= (hex
->blocksize
- fs
->bcnt
) / fu
->bcnt
;
462 if (!list_empty(&fu
->prlist
)) {
463 pr
= list_last_entry(&fu
->prlist
,
464 struct hexdump_pr
, prlist
);
465 for (p1
= pr
->fmt
, p2
= NULL
; *p1
; ++p1
)
466 p2
= isspace(*p1
) ? p1
: NULL
;
474 /* [!]color[:string|:hex_number|:oct_number][@offt|@offt_start-offt_end],... */
475 static struct list_head
*color_fmt(char *cfmt
, int bcnt
)
477 struct hexdump_clr
*hc
, *hcnext
;
478 struct list_head
*ret_head
;
481 ret_head
= xmalloc(sizeof(struct list_head
));
482 hcnext
= hc
= xcalloc(1, sizeof(struct hexdump_clr
));
484 INIT_LIST_HEAD(&hc
->colorlist
);
485 INIT_LIST_HEAD(ret_head
);
486 list_add_tail(&hc
->colorlist
, ret_head
);
489 while (cfmt
&& *cfmt
) {
491 /* invert this condition */
497 clr
= xstrndup(cfmt
, strcspn(cfmt
, ":@,"));
499 hcnext
->fmt
= colorscheme_from_string(clr
);
505 /* only colorize this specific value */
508 /* a hex or oct value */
513 if (cfmt
[1] == 'x' || cfmt
[1] == 'X')
514 hcnext
->val
= strtoul(cfmt
+ 2, &end
, 16);
516 hcnext
->val
= strtoul(cfmt
, &end
, 8);
517 if (errno
|| end
== cfmt
)
527 /* temporarily null-delimit the format, so we can reverse-search
528 * for the start of an offset specifier */
529 fmt_end
= strcspn(cfmt
, ",");
530 endchar
= cfmt
[fmt_end
];
531 cfmt
[fmt_end
] = '\0';
532 endstr
= strrchr(cfmt
, '@');
535 if (endstr
[1] != '\0')
537 hcnext
->str
= xstrndup(cfmt
, endstr
- cfmt
+ 1);
539 hcnext
->str
= xstrndup(cfmt
, fmt_end
);
541 /* restore the character */
542 cfmt
[fmt_end
] = endchar
;
543 cfmt
+= strlen(hcnext
->str
);
546 /* no specific value */
550 /* only colorize at this offset */
551 hcnext
->range
= bcnt
;
552 if (cfmt
&& *cfmt
== '@') {
554 hcnext
->offt
= strtoul(++cfmt
, &cfmt
, 10);
564 strtoul(cfmt
, &cfmt
, 10) - hcnext
->offt
+ 1;
567 /* offset range must be between 0 and format byte count */
568 if (!(hcnext
->range
>= 0 && hcnext
->range
<= bcnt
))
571 /* no specific offset */
573 hcnext
->offt
= (off_t
)-1;
575 /* check if the string we're looking for is the same length as the range */
576 if (hcnext
->str
&& (int)strlen(hcnext
->str
) != hcnext
->range
)
579 /* link in another condition */
580 if (cfmt
&& *cfmt
== ',') {
583 hcnext
= xcalloc(1, sizeof(struct hexdump_clr
));
584 INIT_LIST_HEAD(&hcnext
->colorlist
);
585 list_add_tail(&hcnext
->colorlist
, ret_head
);
591 static void escape(char *p1
)
595 /* alphabetic escape sequences have to be done in place */