]> git.ipfire.org Git - thirdparty/util-linux.git/blame - text-utils/hexdump-parse.c
hexdump: add __attribute__ ((__noreturn__)) to bad*() functions
[thirdparty/util-linux.git] / text-utils / hexdump-parse.c
CommitLineData
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
b50945d4 34 /* 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c
KZ
35 * - added Native Language Support
36 */
37
6dbe3af9
KZ
38#include <sys/types.h>
39#include <sys/file.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <ctype.h>
43#include <string.h>
44#include "hexdump.h"
7eda085c 45#include "nls.h"
85bf44b7 46#include "xalloc.h"
bec2d458 47#include "strutils.h"
6dbe3af9 48
ffc43748 49static void escape(char *p1);
1be6ed6a
OO
50
51static void __attribute__ ((__noreturn__)) badcnt(const char *s)
52{
53 errx(EXIT_FAILURE, _("bad byte count for conversion character %s"), s);
54}
55
56static void __attribute__ ((__noreturn__)) badsfmt(void)
57{
58 errx(EXIT_FAILURE, _("%%s requires a precision or a byte count"));
59}
60
61static void __attribute__ ((__noreturn__)) badfmt(const char *fmt)
62{
63 errx(EXIT_FAILURE, _("bad format {%s}"), fmt);
64}
65
66static void __attribute__ ((__noreturn__)) badconv(const char *ch)
67{
68 errx(EXIT_FAILURE, _("bad conversion character %%%s"), ch);
69}
fd6b7a7f 70
d01d144c 71#define first_letter(s,f) strchr(f, *(s))
f65e62e0 72
046921da 73struct hexdump_fu *endfu; /* format at end-of-data */
6dbe3af9 74
fd6b7a7f 75void addfile(char *name)
6dbe3af9 76{
3917a95d 77 char *fmt, *buf = NULL;
6dbe3af9 78 FILE *fp;
96ea3d32 79 size_t n;
6dbe3af9 80
85bf44b7
SK
81 if ((fp = fopen(name, "r")) == NULL)
82 err(EXIT_FAILURE, _("can't read %s"), name);
96ea3d32
OO
83
84 while (getline(&buf, &n, fp) != -1) {
3917a95d 85 fmt = buf;
96ea3d32 86
3917a95d
OO
87 while (*fmt && isspace(*fmt))
88 ++fmt;
89 if (!*fmt || *fmt == '#')
6dbe3af9 90 continue;
96ea3d32 91
9fa53ceb 92 add_fmt(fmt);
6dbe3af9 93 }
96ea3d32
OO
94
95 free(buf);
9db51207 96 fclose(fp);
6dbe3af9
KZ
97}
98
9fa53ceb 99void add_fmt(const char *fmt)
6dbe3af9 100{
cb986008 101 const char *p, *savep;
bb8ae572 102 struct hexdump_fs *tfs;
046921da 103 struct hexdump_fu *tfu;
6dbe3af9 104
ffc43748 105 /* Start new linked list of format units. */
bb8ae572 106 tfs = xcalloc(1, sizeof(struct hexdump_fs));
bbc8c153
OO
107 INIT_LIST_HEAD(&tfs->fslist);
108 INIT_LIST_HEAD(&tfs->fulist);
109 list_add_tail(&tfs->fslist, &fshead);
bafd2d46 110
ffc43748 111 /* Take the format string and break it up into format units. */
cb986008 112 p = fmt;
9db51207 113 while (TRUE) {
ffc43748 114 /* Skip leading white space. */
0acd3f5d 115 if (!*(p = skip_space(p)))
6dbe3af9
KZ
116 break;
117
ffc43748 118 /* Allocate a new format unit and link it in. */
046921da 119 tfu = xcalloc(1, sizeof(struct hexdump_fu));
acf74fc2
OO
120 tfu->reps = 1;
121
bbc8c153
OO
122 INIT_LIST_HEAD(&tfu->fulist);
123 INIT_LIST_HEAD(&tfu->prlist);
124 list_add_tail(&tfu->fulist, &tfs->fulist);
6dbe3af9 125
ffc43748 126 /* If leading digit, repetition count. */
9db51207
OO
127 if (isdigit(*p)) {
128 savep = p;
129 while (isdigit(*p) && ++p)
130 ;
131 if (!isspace(*p) && *p != '/')
6dbe3af9
KZ
132 badfmt(fmt);
133 /* may overwrite either white space or slash */
cb986008 134 tfu->reps = atoi(savep);
6dbe3af9
KZ
135 tfu->flags = F_SETREP;
136 /* skip trailing white space */
0acd3f5d 137 p = skip_space(++p);
6dbe3af9
KZ
138 }
139
ffc43748 140 /* Skip slash and trailing white space. */
6dbe3af9 141 if (*p == '/')
0acd3f5d 142 p = skip_space(p);
6dbe3af9
KZ
143
144 /* byte count */
9db51207
OO
145 if (isdigit(*p)) {
146 savep = p;
147 while (isdigit(*p) && ++p)
148 ;
149 if (!isspace(*p))
6dbe3af9 150 badfmt(fmt);
cb986008 151 tfu->bcnt = atoi(savep);
6dbe3af9 152 /* skip trailing white space */
0acd3f5d 153 p = skip_space(++p);
6dbe3af9
KZ
154 }
155
156 /* format */
157 if (*p != '"')
158 badfmt(fmt);
9db51207 159 savep = ++p;
acf74fc2 160 while (*p != '"') {
7e6e290b 161 if (!*p++)
6dbe3af9 162 badfmt(fmt);
acf74fc2 163 }
85bf44b7 164 tfu->fmt = xmalloc(p - savep + 1);
cb986008 165 xstrncpy(tfu->fmt, savep, p - savep + 1);
6dbe3af9 166 escape(tfu->fmt);
acf74fc2 167 ++p;
6dbe3af9
KZ
168 }
169}
170
ffc43748 171static const char *spec = ".#-+ 0123456789";
fd6b7a7f 172
bb8ae572 173int block_size(struct hexdump_fs *fs)
6dbe3af9 174{
046921da 175 struct hexdump_fu *fu;
acf74fc2 176 int bcnt, prec, cursize = 0;
cb986008 177 char *fmt;
9db51207 178 struct list_head *p;
6dbe3af9
KZ
179
180 /* figure out the data block size needed for each format unit */
bbc8c153 181 list_for_each (p, &fs->fulist) {
046921da 182 fu = list_entry(p, struct hexdump_fu, fulist);
6dbe3af9
KZ
183 if (fu->bcnt) {
184 cursize += fu->bcnt * fu->reps;
185 continue;
186 }
9db51207 187 bcnt = prec = 0;
cb986008 188 fmt = fu->fmt;
9db51207
OO
189 while (*fmt) {
190 if (*fmt != '%') {
191 ++fmt;
6dbe3af9 192 continue;
9db51207 193 }
6dbe3af9
KZ
194 /*
195 * skip any special chars -- save precision in
196 * case it's a %s format.
197 */
acf74fc2
OO
198 while (strchr(spec + 1, *++fmt))
199 ;
9db51207 200 if (*fmt == '.' && isdigit(*++fmt)) {
cb986008 201 prec = atoi(fmt);
9db51207
OO
202 while (isdigit(*++fmt))
203 ;
6dbe3af9 204 }
d01d144c 205 if (first_letter(fmt, "diouxX"))
6dbe3af9 206 bcnt += 4;
d01d144c 207 else if (first_letter(fmt, "efgEG"))
6dbe3af9 208 bcnt += 8;
f65e62e0 209 else if (*fmt == 's')
6dbe3af9 210 bcnt += prec;
d01d144c 211 else if (*fmt == 'c' || (*fmt == '_' && first_letter(++fmt, "cpu")))
f65e62e0 212 ++bcnt;
9db51207 213 ++fmt;
6dbe3af9
KZ
214 }
215 cursize += bcnt * fu->reps;
216 }
217 return(cursize);
218}
219
bb8ae572 220void rewrite_rules(struct hexdump_fs *fs)
6dbe3af9
KZ
221{
222 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
4c73d29c 223 struct hexdump_pr *pr;
046921da 224 struct hexdump_fu *fu;
9db51207 225 struct list_head *p, *q;
acf74fc2
OO
226 char *p1, *p2, *fmtp;
227 char savech, cs[3];
228 int nconv, prec = 0;
6dbe3af9 229
bbc8c153 230 list_for_each (p, &fs->fulist) {
046921da 231 fu = list_entry(p, struct hexdump_fu, fulist);
6dbe3af9 232 /*
ffc43748 233 * Break each format unit into print units; each
6dbe3af9
KZ
234 * conversion character gets its own.
235 */
9db51207
OO
236 nconv = 0;
237 fmtp = fu->fmt;
238 while (*fmtp) {
4c73d29c 239 pr = xcalloc(1, sizeof(struct hexdump_pr));
bbc8c153
OO
240 INIT_LIST_HEAD(&pr->prlist);
241 list_add_tail(&pr->prlist, &fu->prlist);
6dbe3af9 242
ffc43748 243 /* Skip preceding text and up to the next % sign. */
eef27d32
OO
244 p1 = fmtp;
245 while (*p1 && *p1 != '%')
246 ++p1;
6dbe3af9 247
ffc43748 248 /* Only text in the string. */
6dbe3af9 249 if (!*p1) {
d2740b0e 250 pr->fmt = xstrdup(fmtp);
6dbe3af9
KZ
251 pr->flags = F_TEXT;
252 break;
253 }
254
255 /*
ffc43748 256 * Get precision for %s -- if have a byte count, don't
6dbe3af9
KZ
257 * need it.
258 */
259 if (fu->bcnt) {
260 sokay = USEBCNT;
261 /* skip to conversion character */
eef27d32
OO
262 while (++p1 && strchr(spec, *p1))
263 ;
6dbe3af9
KZ
264 } else {
265 /* skip any special chars, field width */
eef27d32
OO
266 while (strchr(spec + 1, *++p1))
267 ;
dabfe2ad 268 if (*p1 == '.' && isdigit(*++p1)) {
6dbe3af9
KZ
269 sokay = USEPREC;
270 prec = atoi(p1);
dabfe2ad 271 while (isdigit(*++p1))
eef27d32 272 ;
ffc43748 273 } else
6dbe3af9
KZ
274 sokay = NOTOKAY;
275 }
276
ffc43748
KZ
277 p2 = p1 + 1; /* Set end pointer. */
278 cs[0] = *p1; /* Set conversion string. */
279 cs[1] = 0;
6dbe3af9
KZ
280
281 /*
ffc43748 282 * Figure out the byte count for each conversion;
6dbe3af9
KZ
283 * rewrite the format as necessary, set up blank-
284 * padding for end of data.
285 */
f65e62e0
OO
286 if (*cs == 'c') {
287 pr->flags = F_CHAR;
288 switch(fu->bcnt) {
289 case 0:
290 case 1:
291 pr->bcnt = 1;
292 break;
293 default:
294 p1[1] = '\0';
295 badcnt(p1);
296 }
d01d144c 297 } else if (first_letter(cs, "di")) {
f65e62e0
OO
298 pr->flags = F_INT;
299 goto isint;
d01d144c 300 } else if (first_letter(cs, "ouxX")) {
f65e62e0
OO
301 pr->flags = F_UINT;
302isint: cs[2] = '\0';
303 cs[1] = cs[0];
304 cs[0] = 'q';
305 switch(fu->bcnt) {
306 case 0:
307 pr->bcnt = 4;
308 break;
309 case 1:
310 case 2:
311 case 4:
312 case 8:
313 pr->bcnt = fu->bcnt;
314 break;
315 default:
316 p1[1] = '\0';
317 badcnt(p1);
318 }
d01d144c 319 } else if (first_letter(cs, "efgEG")) {
f65e62e0
OO
320 pr->flags = F_DBL;
321 switch(fu->bcnt) {
322 case 0:
323 pr->bcnt = 8;
324 break;
325 case 4:
326 case 8:
327 pr->bcnt = fu->bcnt;
328 break;
329 default:
330 p1[1] = '\0';
331 badcnt(p1);
332 }
333 } else if(*cs == 's') {
334 pr->flags = F_STR;
335 switch(sokay) {
eef27d32
OO
336 case NOTOKAY:
337 badsfmt();
338 case USEBCNT:
339 pr->bcnt = fu->bcnt;
340 break;
341 case USEPREC:
342 pr->bcnt = prec;
343 break;
f65e62e0
OO
344 }
345 } else if (*cs == '_') {
346 ++p2;
347 switch(p1[1]) {
348 case 'A':
349 endfu = fu;
350 fu->flags |= F_IGNORE;
351 /* FALLTHROUGH */
352 case 'a':
353 pr->flags = F_ADDRESS;
354 ++p2;
d01d144c 355 if (first_letter(p1 + 2, "dox")) {
f65e62e0
OO
356 cs[0] = 'q';
357 cs[1] = p1[2];
358 cs[2] = '\0';
359 } else {
360 p1[3] = '\0';
eef27d32 361 badconv(p1);
f65e62e0
OO
362 }
363 break;
364 case 'c':
365 pr->flags = F_C;
366 /* cs[0] = 'c'; set in conv_c */
367 goto isint2;
368 case 'p':
369 pr->flags = F_P;
370 cs[0] = 'c';
371 goto isint2;
372 case 'u':
373 pr->flags = F_U;
374 /* cs[0] = 'c'; set in conv_u */
375 isint2: switch(fu->bcnt) {
376 case 0:
377 case 1:
378 pr->bcnt = 1;
379 break;
380 default:
381 p1[2] = '\0';
382 badcnt(p1);
383 }
384 break;
385 default:
386 p1[2] = '\0';
387 badconv(p1);
388 }
389 } else {
390 p1[1] = '\0';
391 badconv(p1);
6dbe3af9
KZ
392 }
393
394 /*
4c73d29c 395 * Copy to hexdump_pr format string, set conversion character
6dbe3af9
KZ
396 * pointer, update original.
397 */
398 savech = *p2;
ffc43748 399 p1[0] = '\0';
85bf44b7 400 pr->fmt = xmalloc(strlen(fmtp) + strlen(cs) + 1);
eef27d32
OO
401 strcpy(pr->fmt, fmtp);
402 strcat(pr->fmt, cs);
6dbe3af9
KZ
403 *p2 = savech;
404 pr->cchar = pr->fmt + (p1 - fmtp);
405 fmtp = p2;
406
ffc43748 407 /* Only one conversion character if byte count */
85bf44b7
SK
408 if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
409 errx(EXIT_FAILURE,
410 _("byte count with multiple conversion characters"));
6dbe3af9
KZ
411 }
412 /*
ffc43748 413 * If format unit byte count not specified, figure it out
6dbe3af9
KZ
414 * so can adjust rep count later.
415 */
416 if (!fu->bcnt)
bbc8c153 417 list_for_each(q, &fu->prlist)
4c73d29c
OO
418 fu->bcnt
419 += (list_entry(q, struct hexdump_pr, prlist))->bcnt;
6dbe3af9
KZ
420 }
421 /*
ffc43748 422 * If the format string interprets any data at all, and it's
6dbe3af9
KZ
423 * not the same as the blocksize, and its last format unit
424 * interprets any data at all, and has no iteration count,
425 * repeat it as necessary.
426 *
ffc43748 427 * If rep count is greater than 1, no trailing whitespace
6dbe3af9
KZ
428 * gets output from the last iteration of the format unit.
429 */
bbc8c153 430 list_for_each (p, &fs->fulist) {
046921da 431 fu = list_entry(p, struct hexdump_fu, fulist);
acf74fc2
OO
432
433 if (list_entry_is_last(&fu->fulist, &fs->fulist) &&
434 fs->bcnt < blocksize &&
435 !(fu->flags&F_SETREP) && fu->bcnt)
436 fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
6dbe3af9 437 if (fu->reps > 1) {
bbc8c153 438 if (!list_empty(&fu->prlist)) {
4c73d29c
OO
439 pr = list_last_entry(&fu->prlist,
440 struct hexdump_pr, prlist);
d6e5614e
OO
441 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
442 p2 = isspace(*p1) ? p1 : NULL;
443 if (p2)
444 pr->nospace = p2;
f1107b4a 445 }
6dbe3af9 446 }
6dbe3af9
KZ
447 }
448}
449
450
ffc43748 451static void escape(char *p1)
6dbe3af9 452{
ffc43748 453 char *p2;
6dbe3af9
KZ
454
455 /* alphabetic escape sequences have to be done in place */
9c2cb9b0
OO
456 p2 = p1;
457 while (TRUE) {
6dbe3af9
KZ
458 if (!*p1) {
459 *p2 = *p1;
460 break;
461 }
462 if (*p1 == '\\')
463 switch(*++p1) {
464 case 'a':
465 /* *p2 = '\a'; */
466 *p2 = '\007';
467 break;
468 case 'b':
469 *p2 = '\b';
470 break;
471 case 'f':
472 *p2 = '\f';
473 break;
474 case 'n':
475 *p2 = '\n';
476 break;
477 case 'r':
478 *p2 = '\r';
479 break;
480 case 't':
481 *p2 = '\t';
482 break;
483 case 'v':
484 *p2 = '\v';
485 break;
486 default:
487 *p2 = *p1;
488 break;
489 }
9c2cb9b0 490 ++p1; ++p2;
6dbe3af9
KZ
491 }
492}