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 }