hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

hd.c (13271B)


      1 /*
      2  * hd - display files in hexadecimal format
      3  *
      4  * Gunnar Ritter, Freiburg i. Br., Germany, September 2003.
      5  */
      6 /*
      7  * Copyright (c) 2003 Gunnar Ritter
      8  *
      9  * This software is provided 'as-is', without any express or implied
     10  * warranty. In no event will the authors be held liable for any damages
     11  * arising from the use of this software.
     12  *
     13  * Permission is granted to anyone to use this software for any purpose,
     14  * including commercial applications, and to alter it and redistribute
     15  * it freely, subject to the following restrictions:
     16  *
     17  * 1. The origin of this software must not be misrepresented; you must not
     18  *    claim that you wrote the original software. If you use this software
     19  *    in a product, an acknowledgment in the product documentation would be
     20  *    appreciated but is not required.
     21  *
     22  * 2. Altered source versions must be plainly marked as such, and must not be
     23  *    misrepresented as being the original software.
     24  *
     25  * 3. This notice may not be removed or altered from any source distribution.
     26  */
     27 
     28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
     29 #define	USED	__attribute__ ((used))
     30 #elif defined __GNUC__
     31 #define	USED	__attribute__ ((unused))
     32 #else
     33 #define	USED
     34 #endif
     35 static const char sccsid[] USED = "@(#)hd.sl	1.12 (gritter) 5/29/05";
     36 
     37 #include <sys/types.h>
     38 #include <stdio.h>
     39 #include <unistd.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <libgen.h>
     43 #include <stdarg.h>
     44 #include <locale.h>
     45 #include <ctype.h>
     46 #include <wctype.h>
     47 #include <wchar.h>
     48 #include <inttypes.h>
     49 #include <limits.h>
     50 #include "atoll.h"
     51 #include "mbtowi.h"
     52 
     53 #ifdef	__GLIBC__
     54 #ifdef	_IO_getc_unlocked
     55 #undef	getc
     56 #define	getc(f)		_IO_getc_unlocked(f)
     57 #endif
     58 #ifdef	_IO_putc_unlocked
     59 #undef	putchar
     60 #define	putchar(c)	_IO_putc_unlocked(c, stdout)
     61 #endif
     62 #endif	/* __GLIBC__ */
     63 
     64 enum	base {
     65 	BASE_0 = 00,
     66 	BASE_X = 01,
     67 	BASE_D = 02,
     68 	BASE_O = 04
     69 };
     70 
     71 union	block {
     72 	int8_t	b_c[16];
     73 	int16_t	b_w[8];
     74 	int32_t	b_l[4];
     75 };
     76 
     77 static const struct fm {
     78 	int	f_fmt;
     79 	enum base	f_base;
     80 	char	f_width;
     81 	char	f_align[3];
     82 	const char	*f_prf;
     83 } ofmt[] = {
     84 	{ 'b', BASE_X,  2, {2,5,11}, "%02x" },
     85 	{ 'b', BASE_D,  3, {3,7,15}, "%3u" },
     86 	{ 'b', BASE_O,  3, {3,7,15}, "%03o" },
     87 	{ 'c', BASE_X,  2, {2,5,11}, "%02x" },
     88 	{ 'c', BASE_D,  3, {3,7,15}, "%3u" },
     89 	{ 'c', BASE_O,  3, {3,7,15}, "%03o" },
     90 	{ 'w', BASE_X,  4, {0,4, 9}, "%04x" },
     91 	{ 'w', BASE_D,  5, {0,5,11}, "%5u" },
     92 	{ 'w', BASE_O,  6, {0,6,13}, "%06o" },
     93 	{ 'l', BASE_X,  8, {0,0, 8}, "%08lx" },
     94 	{ 'l', BASE_D, 10, {0,0,10}, "%10lu" },
     95 	{ 'l', BASE_O, 11, {0,0,11}, "%011lo" },
     96 	{   0, BASE_0,  0, {0,0, 0}, NULL }
     97 };
     98 
     99 static int		Aflag;	/* print ASCII at right */
    100 static enum base	aflag;	/* address format specifier */
    101 static enum base	bflag;	/* byte format specifier */
    102 static enum base	cflag;	/* print ASCII at center */
    103 static enum base	lflag;	/* long (32 bit) format specifier */
    104 static long long	nflag;	/* number of bytes to process */
    105 static long long	sflag;	/* start offset */
    106 static int		tflag;	/* print text file */
    107 static int		vflag;	/* no '*' for identical lines */
    108 static enum base	wflag;	/* word (16 bit) format specifier */
    109 static char		align[3];
    110 static const char	*progname;
    111 static int		status;
    112 static int		mb_cur_max;
    113 
    114 static void		usage(void);
    115 static void		flag(int);
    116 static void		base(enum base, enum base *);
    117 static long long	count(const char *);
    118 static void		usage(void);
    119 static void		diag(const char *, ...);
    120 static void		hd(FILE *);
    121 static void		prna(long long);
    122 static void		prnb(union block *, int);
    123 static void		line(union block *, int, int, enum base, int);
    124 static const struct fm	*getfmt(int, enum base);
    125 static void		getalign(void);
    126 static void		prnt(FILE *, long long);
    127 static void		prnc(int);
    128 static char		*wcget(FILE *fp, wint_t *wc, int *len);
    129 
    130 int
    131 main(int argc, char **argv)
    132 {
    133 	FILE	*fp;
    134 	int	i, j;
    135 
    136 	progname = basename(argv[0]);
    137 	setlocale(LC_CTYPE, "");
    138 	mb_cur_max = MB_CUR_MAX;
    139 	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
    140 		switch (argv[i][1]) {
    141 		case 's':
    142 			if (argv[i][2])
    143 				sflag = count(&argv[i][2]);
    144 			else if (++i < argc)
    145 				sflag = count(argv[i]);
    146 			else
    147 				usage();
    148 			break;
    149 		case 'n':
    150 			if (argv[i][2])
    151 				nflag = count(&argv[i][2]);
    152 			else if (++i < argc)
    153 				nflag = count(argv[i]);
    154 			else
    155 				usage();
    156 			break;
    157 		default:
    158 			for (j = 1; argv[i][j]; j++)
    159 				flag(argv[i][j]&0377);
    160 			flag(0);
    161 		}
    162 	}
    163 	if (tflag && (Aflag|bflag|cflag|lflag|wflag))
    164 		diag("-t flag overrides other flags");
    165 	if ((Aflag|bflag|cflag|lflag|wflag) == 0)
    166 		Aflag = 1;
    167 	if ((bflag|cflag|lflag|wflag) == 0)
    168 		bflag = BASE_X;
    169 	getalign();
    170 	if (i < argc) {
    171 		j = i+1 < argc;
    172 		do {
    173 			if (access(argv[i], R_OK) < 0) {
    174 				diag("cannot access %s", argv[i]);
    175 				continue;
    176 			}
    177 			if ((fp = fopen(argv[i], "r")) == NULL) {
    178 				diag("open of %s failed", argv[i]);
    179 				continue;
    180 			}
    181 			if (j)
    182 				printf("%s:\n", argv[i]);
    183 			hd(fp);
    184 			fclose(fp);
    185 			if (i+1 < argc)
    186 				printf("\n");
    187 		} while (++i < argc);
    188 	} else
    189 		hd(stdin);
    190 	return status;
    191 }
    192 
    193 static void
    194 flag(int c)
    195 {
    196 	static enum base	*basep;
    197 
    198 	switch (c) {
    199 	case '\0':
    200 		if (basep && basep != &aflag && *basep == BASE_0)
    201 			*basep |= BASE_O|BASE_D|BASE_X;
    202 		basep = NULL;
    203 		break;
    204 	case 'a':
    205 		basep = &aflag;
    206 		break;
    207 	case 'b':
    208 		basep = &bflag;
    209 		break;
    210 	case 'w':
    211 		basep = &wflag;
    212 		break;
    213 	case 'l':
    214 		basep = &lflag;
    215 		break;
    216 	case 'c':
    217 		basep = &cflag;
    218 		break;
    219 	case 'A':
    220 		Aflag = 1;
    221 		break;
    222 	case 'x':
    223 		base(BASE_X, basep);
    224 		break;
    225 	case 'd':
    226 		base(BASE_D, basep);
    227 		break;
    228 	case 'o':
    229 		base(BASE_O, basep);
    230 		break;
    231 	case 't':
    232 		tflag = 1;
    233 		break;
    234 	case 'v':
    235 		vflag = 1;
    236 		break;
    237 	default:
    238 		usage();
    239 	}
    240 }
    241 
    242 static void
    243 base(enum base b, enum base *basep)
    244 {
    245 	if (basep) {
    246 		if (basep == &aflag)
    247 			*basep = b;
    248 		else
    249 			*basep |= b;
    250 	} else {
    251 		if (aflag == BASE_0)
    252 			aflag |= b;
    253 		cflag |= b;
    254 		bflag |= b;
    255 		wflag |= b;
    256 		lflag |= b;
    257 	}
    258 }
    259 
    260 static long long
    261 count(const char *s)
    262 {
    263 	long long	c;
    264 	int	bs = 10;
    265 	char	*x;
    266 
    267 	if (s[0] == '0' && s[1] == 'x') {
    268 		bs = 16;
    269 		s += 2;
    270 	} else if (s[0] == '0') {
    271 		bs = 8;
    272 		s++;
    273 	}
    274 	c = strtoll(s, &x, bs);
    275 	s = x;
    276 	if (*s == '*')
    277 		s++;
    278 	switch (*s) {
    279 	case 'w':
    280 		c *= 2;
    281 		s++;
    282 		break;
    283 	case 'l':
    284 		c *= 4;
    285 		s++;
    286 		break;
    287 	case 'b':
    288 		c *= 512;
    289 		s++;
    290 		break;
    291 	case 'k':
    292 		c *= 1024;
    293 		s++;
    294 		break;
    295 	}
    296 	if (*s) {
    297 		diag("bad count/offset value");
    298 		exit(3);
    299 	}
    300 	return c;
    301 }
    302 
    303 static void
    304 usage(void)
    305 {
    306 	fprintf(stderr, "usage: %s [-acbwlAxdo] [-t] [-s offset[*][wlbk]] "
    307 			"[-n count[*][wlbk]] [file] ...\n",
    308 			progname);
    309 	exit(2);
    310 }
    311 
    312 static void
    313 diag(const char *fmt, ...)
    314 {
    315 	va_list	ap;
    316 
    317 	fprintf(stderr, "%s: ", progname);
    318 	va_start(ap, fmt);
    319 	vfprintf(stderr, fmt, ap);
    320 	va_end(ap);
    321 	fprintf(stderr, "\n");
    322 	status |= 1;
    323 }
    324 
    325 static void
    326 hd(FILE *fp)
    327 {
    328 	long long	of = 0, rd = 0;
    329 	union block	b, ob;
    330 	size_t	n, m, on = 0;
    331 	int	star = 0;
    332 
    333 	if (sflag)
    334 		while (of < sflag) {
    335 			getc(fp);
    336 			of++;
    337 		}
    338 	if (tflag) {
    339 		prnt(fp, of);
    340 		return;
    341 	}
    342 	do {
    343 		if (nflag == 0 || rd + sizeof b.b_c < nflag)
    344 			m = sizeof b.b_c;
    345 		else
    346 			m = nflag - rd;
    347 		if ((n = fread(b.b_c, 1, m, fp)) > 0) {
    348 			if (!vflag && n==on && memcmp(b.b_c, ob.b_c, n) == 0) {
    349 				if (star == 0)
    350 					printf("*\n");
    351 				star = 1;
    352 			} else {
    353 				star = 0;
    354 				prna(of);
    355 				if (n < sizeof b.b_c)
    356 					memset(&b.b_c[n], 0, sizeof b.b_c - n);
    357 				prnb(&b, n);
    358 			}
    359 		}
    360 		rd += n;
    361 		of += n;
    362 		on = n;
    363 		ob = b;
    364 	} while (n == m && (nflag == 0 || rd < nflag));
    365 	prna(of);
    366 	putchar('\n');
    367 }
    368 
    369 static void
    370 prna(long long n)
    371 {
    372 	switch (aflag) {
    373 	case BASE_O:
    374 		printf("%06llo", n);
    375 		break;
    376 	case BASE_D:
    377 		printf("%05llu", n);
    378 		break;
    379 	case BASE_0:
    380 	case BASE_X:
    381 		printf("%04llx", n);
    382 		break;
    383 	}
    384 }
    385 
    386 static void
    387 prnb(union block *bp, int n)
    388 {
    389 	int	cnt = 0;
    390 
    391 	if (cflag&BASE_X)
    392 		line(bp, n, 'c', BASE_X, cnt++);
    393 	if (cflag&BASE_D)
    394 		line(bp, n, 'c', BASE_D, cnt++);
    395 	if (cflag&BASE_O)
    396 		line(bp, n, 'c', BASE_O, cnt++);
    397 	if (bflag&BASE_X)
    398 		line(bp, n, 'b', BASE_X, cnt++);
    399 	if (bflag&BASE_D)
    400 		line(bp, n, 'b', BASE_D, cnt++);
    401 	if (bflag&BASE_O)
    402 		line(bp, n, 'b', BASE_O, cnt++);
    403 	if (wflag&BASE_X)
    404 		line(bp, n, 'w', BASE_X, cnt++);
    405 	if (wflag&BASE_D)
    406 		line(bp, n, 'w', BASE_D, cnt++);
    407 	if (wflag&BASE_O)
    408 		line(bp, n, 'w', BASE_O, cnt++);
    409 	if (lflag&BASE_X)
    410 		line(bp, n, 'l', BASE_X, cnt++);
    411 	if (lflag&BASE_D)
    412 		line(bp, n, 'l', BASE_D, cnt++);
    413 	if (lflag&BASE_O)
    414 		line(bp, n, 'l', BASE_O, cnt++);
    415 }
    416 
    417 static void
    418 line(union block *bp, int n, int fmt, enum base base, int cnt)
    419 {
    420 	int	c, i, j, k, col = 0;
    421 	const char	*cp;
    422 	const struct fm	*fmp;
    423 
    424 	putchar('\t');
    425 	i = 0;
    426 	switch (fmt) {
    427 	case 'l':
    428 		fmp = getfmt('l', base);
    429 		for (j = i/4; j < (n>>2); j++, i += 4) {
    430 			if (col > 0) {
    431 				putchar(' ');
    432 				col++;
    433 			}
    434 			if (i == 8) {
    435 				putchar(' ');
    436 				col++;
    437 			}
    438 			for (k = fmp->f_width; k < align[2]; k++) {
    439 				putchar(' ');
    440 				col++;
    441 			}
    442 			col += printf(fmp->f_prf,(long)(bp->b_l[j]&0xffffffff));
    443 		}
    444 		if (i == n)
    445 			break;
    446 		/*FALLTHRU*/
    447 	case 'w':
    448 		fmp = getfmt('w', base);
    449 		for (j = i/2; j < (n>>1); j++, i += 2) {
    450 			if (col > 0) {
    451 				putchar(' ');
    452 				col++;
    453 			}
    454 			if (i == 8) {
    455 				putchar(' ');
    456 				col++;
    457 			}
    458 			for (k = fmp->f_width; k < align[1]; k++) {
    459 				putchar(' ');
    460 				col++;
    461 			}
    462 			col += printf(fmp->f_prf, (int)(bp->b_w[j]&0177777));
    463 		}
    464 		if (i == n)
    465 			break;
    466 		/*FALLTHRU*/
    467 	case 'b':
    468 		fmp = getfmt('b', base);
    469 		for (j = i; j < n; j++, i++) {
    470 			if (col > 0) {
    471 				putchar(' ');
    472 				col++;
    473 			}
    474 			if (i == 8) {
    475 				putchar(' ');
    476 				col++;
    477 			}
    478 			for (k = fmp->f_width; k < align[0]; k++) {
    479 				putchar(' ');
    480 				col++;
    481 			}
    482 			col += printf(fmp->f_prf, bp->b_c[j]&0377);
    483 		}
    484 		break;
    485 	case 'c':
    486 		fmp = getfmt('c', base);
    487 		for (i = 0; i < n; i++) {
    488 			if (col > 0) {
    489 				putchar(' ');
    490 				col++;
    491 			}
    492 			if (i == 8) {
    493 				putchar(' ');
    494 				col++;
    495 			}
    496 			for (k = fmp->f_width; k < align[0]; k++) {
    497 				putchar(' ');
    498 				col++;
    499 			}
    500 			c = bp->b_c[i]&0377;
    501 			cp = NULL;
    502 			if (c == '\b')
    503 				cp = "\\b";
    504 			else if (c == '\t')
    505 				cp = "\\t";
    506 			else if (c == '\n')
    507 				cp = "\\n";
    508 			else if (c == '\f')
    509 				cp = "\\f";
    510 			else if (c == '\r')
    511 				cp = "\\r";
    512 			else if (!isprint(c)) {
    513 				col += printf(fmp->f_prf, c);
    514 			} else {
    515 				if (base != BASE_X) {
    516 					putchar(' ');
    517 					col++;
    518 				}
    519 				col += printf(" %c", c);
    520 			}
    521 			if (cp) {
    522 				if (base != BASE_X) {
    523 					putchar(' ');
    524 					col++;
    525 				}
    526 				printf(cp);
    527 			}
    528 		}
    529 		break;
    530 	}
    531 	if (cnt == 0 && Aflag) {
    532 		while (col++ < 51)
    533 			putchar(' ');
    534 		for (i = 0; i < n; i++) {
    535 			if ((bp->b_c[i]&0340) == 0 || bp->b_c[i] == 0177 ||
    536 					!isprint(bp->b_c[i]&0377))
    537 				putchar('.');
    538 			else
    539 				putchar(bp->b_c[i]&0377);
    540 		}
    541 	}
    542 	putchar('\n');
    543 }
    544 
    545 static const struct fm *
    546 getfmt(int fmt, enum base base)
    547 {
    548 	int	i;
    549 
    550 	for (i = 0; ofmt[i].f_fmt; i++)
    551 		if (ofmt[i].f_fmt == fmt && ofmt[i].f_base == base)
    552 			return &ofmt[i];
    553 	return NULL;
    554 }
    555 
    556 static void
    557 getalign(void)
    558 {
    559 	int	i, j;
    560 	enum base	*basep;
    561 
    562 	for (i = 0; ofmt[i].f_fmt; i++) {
    563 		switch (ofmt[i].f_fmt) {
    564 		case 'b':
    565 			basep = &bflag;
    566 			break;
    567 		case 'c':
    568 			basep = &cflag;
    569 			break;
    570 		case 'w':
    571 			basep = &wflag;
    572 			break;
    573 		case 'l':
    574 			basep = &lflag;
    575 			break;
    576 		default:
    577 			basep = NULL;
    578 		}
    579 		if (basep && *basep & ofmt[i].f_base)
    580 			for (j = 0; j < sizeof align; j++)
    581 				if (ofmt[i].f_align[j] > align[j])
    582 					align[j] = ofmt[i].f_align[j];
    583 	}
    584 }
    585 
    586 static void
    587 prnt(FILE *fp, long long of)
    588 {
    589 	wint_t	wc;
    590 	char	b, *mb;
    591 	int	c, lastc = '\n', n;
    592 	long long	rd = 0;
    593 
    594 	while ((nflag == 0 || rd < nflag)) {
    595 		if (mb_cur_max > 1) {
    596 			if ((mb = wcget(fp, &wc, &n)) == NULL)
    597 				break;
    598 		} else {
    599 			if ((c = getc(fp)) == EOF)
    600 				break;
    601 			b = wc = c;
    602 			mb = &b;
    603 			n = 1;
    604 		}
    605 		if (lastc == '\n') {
    606 			prna(of);
    607 			putchar('\t');
    608 		}
    609 		of += n, rd += n;
    610 		if (n == 1) {
    611 			c = *mb&0377;
    612 			lastc = c;
    613 			if (wc != WEOF && isprint(c) && c != '\\' &&
    614 					c != '^' && c != '~')
    615 				putchar(c);
    616 			else
    617 				prnc(c);
    618 			if (lastc == '\n')
    619 				putchar('\n');
    620 		} else {
    621 			lastc = c = EOF;
    622 			if (wc != WEOF && iswprint(wc))
    623 				while (n--) {
    624 					putchar(*mb&0377);
    625 					mb++;
    626 				}
    627 			else
    628 				while (n--) {
    629 					prnc(*mb&0377);
    630 					mb++;
    631 				}
    632 		}
    633 	}
    634 	if (lastc != '\n')
    635 		putchar('\n');
    636 	prna(of);
    637 	putchar('\n');
    638 }
    639 
    640 static void
    641 prnc(int c)
    642 {
    643 	if (c == 0177 || c == 0377) {
    644 		printf("\\%o", c);
    645 		return;
    646 	}
    647 	if (c & 0200) {
    648 		putchar('~');
    649 		c &= 0177;
    650 	}
    651 	if (c < 040) {
    652 		putchar('^');
    653 		c |= 0100;
    654 	}
    655 	if (c == '\\' || c == '~' || c == '^')
    656 		putchar('\\');
    657 	putchar(c);
    658 }
    659 
    660 static char *
    661 wcget(FILE *fp, wint_t *wc, int *len)
    662 {
    663 	static char	mbuf[MB_LEN_MAX+1];
    664 	static char	*mcur, *mend;
    665 	static int	incompl;
    666 	size_t	rest;
    667 	int	c, i, n;
    668 
    669 	i = 0;
    670 	rest = mend - mcur;
    671 	if (rest && mcur > mbuf) {
    672 		do
    673 			mbuf[i] = mcur[i];
    674 		while (i++, --rest);
    675 	} else if (incompl) {
    676 		incompl = 0;
    677 		*wc = WEOF;
    678 		mend = mcur = NULL;
    679 		return NULL;
    680 	}
    681 	if (i == 0) {
    682 		c = getc(fp);
    683 		if (c == EOF) {
    684 			*wc = WEOF;
    685 			mend = mcur = NULL;
    686 			return NULL;
    687 		}
    688 		mbuf[i++] = c;
    689 	}
    690 	if (mbuf[0] & 0200) {
    691 		while (mbuf[i-1] != '\n' && i < mb_cur_max &&
    692 				incompl == 0) {
    693 			c = getc(fp);
    694 			if (c != EOF)
    695 				mbuf[i++] = c;
    696 			else
    697 				incompl = 1;
    698 		}
    699 		n = mbtowi(wc, mbuf, i);
    700 		if (n < 0) {
    701 			*len = 1;
    702 			*wc = WEOF;
    703 		} else if (n == 0) {
    704 			*len = 1;
    705 			*wc = '\0';
    706 		} else
    707 			*len = n;
    708 	} else {
    709 		*wc = mbuf[0];
    710 		*len = n = 1;
    711 	}
    712 	mcur = &mbuf[*len];
    713 	mend = &mcur[i - *len];
    714 	return mbuf;
    715 }