od.c (21036B)
1 /* 2 * od - octal dump 3 * 4 * Gunnar Ritter, Freiburg i. Br., Germany, December 2002. 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 #if defined (SUS) 36 static const char sccsid[] USED = "@(#)od_sus.sl 1.26 (gritter) 5/29/05"; 37 #else 38 static const char sccsid[] USED = "@(#)od.sl 1.26 (gritter) 5/29/05"; 39 #endif 40 41 #include <unistd.h> 42 #include <stdio.h> 43 #include <string.h> 44 #include <stdlib.h> 45 #include <errno.h> 46 #include <libgen.h> 47 #include <inttypes.h> 48 #include <locale.h> 49 #include <ctype.h> 50 #include <wctype.h> 51 #include <wchar.h> 52 #include <limits.h> 53 #include "asciitype.h" 54 #include "atoll.h" 55 56 #ifdef __GLIBC__ 57 #ifdef _IO_getc_unlocked 58 #undef getc 59 #define getc(f) _IO_getc_unlocked(f) 60 #endif /* _IO_getc_unlocked */ 61 #ifdef _IO_putc_unlocked 62 #undef putc 63 #define putc(c, f) _IO_putc_unlocked(c, f) 64 #endif /* _IO_putc_unlocked */ 65 #endif /* __GLIBC__ */ 66 67 enum { 68 BLOCK = 16 69 }; 70 71 /* 72 * An input block. 73 */ 74 union block { 75 char b_c[BLOCK]; 76 int16_t b_16[8]; 77 int32_t b_32[4]; 78 int64_t b_64[2]; 79 float b_f[4]; 80 double b_d[2]; 81 }; 82 83 /* 84 * Format type as given with the -t option. 85 */ 86 struct type { 87 struct type *t_nxt; /* next type */ 88 const char *t_prf; /* format string */ 89 int t_rst; /* rest of multibyte character */ 90 char t_cnt; /* word size */ 91 char t_fmt; /* format character */ 92 char t_pad; /* space padding length */ 93 char t_000; /* currently unused */ 94 }; 95 96 /* 97 * An input buffer. 98 */ 99 struct buffer { 100 union block bu_blk; /* input data */ 101 int bu_cnt; /* valid bytes in input data */ 102 }; 103 104 /* 105 * Maps -t format to printf strings. 106 */ 107 static const struct { 108 char p_cnt; 109 char p_fmt; 110 char p_pad; 111 char p_000; 112 const char *p_prf; 113 } prf[] = { 114 { 4, 'f', 1, 0, " %14.7e" }, 115 { 8, 'f', 10, 0, " %21.14le" }, 116 { 1, 'd', 0, 0, " %3d", }, 117 { 2, 'd', 0, 0, "\205\212", }, 118 { 4, 'd', 4, 0, "\12\212", }, 119 { 8, 'd', 10, 0, "\24\212", }, 120 { 1, 'o', 0, 0, "\3\10" }, 121 { 2, 'o', 1, 0, "\6\10" }, 122 { 4, 'o', 4, 0, "\13\10" }, 123 { 8, 'o', 9, 0, "\26\10" }, 124 { 1, 'u', 0, 0, "\3\12" }, 125 { 2, 'u', 2, 0, "\5\12" }, 126 { 4, 'u', 5, 0, "\12\12" }, 127 { 8, 'u', 11, 0, "\24\12" }, 128 { 1, 'x', 1, 0, "\2\20" }, 129 { 2, 'x', 3, 0, "\4\20" }, 130 { 4, 'x', 7, 0, "\10\20" }, 131 { 8, 'x', 15, 0, "\20\20" }, 132 { 1, 'a', 0, 0, "" }, 133 { 1, 'c', 0, 0, "" }, 134 { 1, '\0', 0, 0, "" }, 135 { 0, 0, 0, 0, NULL } 136 }; 137 138 static unsigned errcnt; /* count of errors */ 139 static char *progname; /* argv[0] to main() */ 140 static int offset_base = 8;/* base of offset to be printed */ 141 static int offset_oflo = 07777777; /* max offs. in regular width */ 142 static long long skip; /* skip bytes of input */ 143 static long long limit = -1; /* print no more bytes than limit */ 144 static long long total; /* total bytes of input */ 145 static long long offset; /* offset to print */ 146 static int vflag; /* print all lines */ 147 static int Cflag; /* Cray -C option */ 148 static char **files; /* files to read */ 149 static const char *skipstr; /* skip format string for error msg */ 150 static FILE *curfile; /* current file */ 151 static struct type *types; /* output formats */ 152 static int mb_cur_max; /* MB_CUR_MAX */ 153 static int hadinput; /* did actually read from a file */ 154 static int stretch; /* stretch output columns */ 155 static int expensive; /* need to compare output lines */ 156 157 /* 158 * For -t a. 159 */ 160 static const char *const ctab_a[] = { 161 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", 162 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si", 163 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", 164 "can", " em", "sub", "esc", " fs", " gs", " rs", " us", 165 " sp" 166 }; 167 168 /* 169 * For -c. 170 */ 171 static const char *const ctab_0[] = { 172 " \\0", "001", "002", "003", "004", "005", "006", "007", 173 " \\b", " \\t", " \\n", "013", " \\f", " \\r", "016", "017", 174 "020", "021", "022", "023", "024", "025", "026", "027", 175 "030", "031", "032", "033", "034", "035", "036", "037", 176 " " 177 }; 178 179 /* 180 * For -t c. 181 */ 182 static const char *const ctab_c[] = { 183 " \\0", "001", "002", "003", "004", "005", "006", " \\a", 184 " \\b", " \\t", " \\n", " \\v", " \\f", " \\r", "016", "017", 185 "020", "021", "022", "023", "024", "025", "026", "027", 186 "030", "031", "032", "033", "034", "035", "036", "037", 187 " " 188 }; 189 190 /******************************* HELPERS ********************************/ 191 static void * 192 scalloc(size_t nmemb, size_t size) 193 { 194 void *p; 195 196 if ((p = calloc(nmemb, size)) == NULL) { 197 write(2, "No storage\n", 11); 198 exit(077); 199 } 200 return p; 201 } 202 203 static void * 204 srealloc(void *vp, size_t nbytes) 205 { 206 void *p; 207 208 if ((p = realloc(vp, nbytes)) == NULL) { 209 write(2, "No storage\n", 11); 210 exit(077); 211 } 212 return p; 213 } 214 215 /*static void * 216 smalloc(size_t nbytes) 217 { 218 return srealloc(NULL, nbytes); 219 }*/ 220 221 /******************************* EXECUTION ********************************/ 222 /* 223 * Return the next file in the argument list, or NULL if there are 224 * no further files. 225 */ 226 static FILE * 227 nextfile(void) 228 { 229 FILE *fp; 230 231 if (curfile && curfile != stdin) 232 fclose(curfile); 233 do { 234 if (files == NULL || files[0] == NULL) 235 return NULL; 236 if (files[0][0] == '-' && files[0][1] == '\0') { 237 fp = stdin; 238 if (limit >= 0) 239 setvbuf(stdin, NULL, _IONBF, 0); 240 } else { 241 if ((fp = fopen(files[0], "r")) == NULL) { 242 fprintf(stderr, "%s: cannot open %s\n", 243 progname, files[0]); 244 errcnt |= 1; 245 } 246 } 247 files++; 248 } while (fp == NULL); 249 if (hadinput == 0 && fp != NULL) 250 hadinput++; 251 return fp; 252 } 253 254 /* 255 * Skip bytes of input. 256 */ 257 static void 258 doskip(void) 259 { 260 while (skip > 0) { 261 if (curfile == NULL || getc(curfile) == EOF) { 262 if ((curfile = nextfile()) == NULL) { 263 fprintf(stderr, "%s: %s is too large.\n", 264 progname, skipstr); 265 exit(2); 266 } 267 continue; 268 } 269 total++; 270 skip--; 271 } 272 if (limit >= 0) 273 limit += total; 274 } 275 276 /* 277 * Fill an input buffer. 278 */ 279 static int 280 fill(struct buffer *bp) 281 { 282 int c, i; 283 284 i = 0; 285 while (i < sizeof bp->bu_blk && (limit <= 0 || total < limit)) { 286 if (curfile == NULL || (c = getc(curfile)) == EOF) { 287 if ((curfile = nextfile()) == NULL) 288 break; 289 continue; 290 } 291 bp->bu_blk.b_c[i++] = (char)c; 292 total++; 293 } 294 bp->bu_cnt = i; 295 while (i < sizeof bp->bu_blk) 296 bp->bu_blk.b_c[i++] = '\0'; 297 return bp->bu_cnt; 298 } 299 300 /* 301 * Print a value to the passed buffer. As 64-bit arithmethics requires 302 * more than twice the time of 32-bit arithmetics on 32-bit platforms, 303 * generate different function sets for int, long, and long long. 304 */ 305 #define digit(T, type) static size_t \ 306 T ## digit(char *buf, int size, int base, unsigned type n) \ 307 { \ 308 char *cp; \ 309 int d; \ 310 \ 311 if (size == 0) \ 312 return 0; \ 313 cp = buf + T ## digit(buf, size - 1, base, n / base); \ 314 *cp = (d = n % base) > 9 ? d - 10 + 'a' : d + '0'; \ 315 return cp - buf + 1; \ 316 } 317 318 #define number(T, type) static size_t \ 319 T ## number(char *buf, const char *fmt, unsigned type n) \ 320 { \ 321 int size = fmt[0] & 0377, base = fmt[1] & 0377; \ 322 int add = 1; \ 323 \ 324 buf[0] = ' '; \ 325 if (size & 0200) { \ 326 size &= 0177; \ 327 buf[add++] = ' '; \ 328 } \ 329 if (base & 0200) { \ 330 base &= 0177; \ 331 if ((type)n < 0) { \ 332 buf[add] = '-'; \ 333 n = 0 - (type)n; \ 334 } else \ 335 buf[add] = ' '; \ 336 add++; \ 337 } \ 338 return T ## digit(&buf[add], size, base, n) + add; \ 339 } 340 341 #define mkfuncs(T, type) digit(T, type) number(T, type) 342 343 mkfuncs(i, int) 344 mkfuncs(l, long) 345 mkfuncs(ll, long long) 346 347 /* 348 * Print the offset at the start of each row. 349 */ 350 static void 351 prna(long long addr, int c) 352 { 353 unsigned long long a; 354 char buf[30]; 355 int m, n, s; 356 357 if (offset_base != 0) { 358 if (addr <= offset_oflo) { 359 /* 360 * Address fits in 7 characters and is preceded 361 * by '0' characters. 362 */ 363 if (addr > UINT_MAX) 364 n = lldigit(buf, 7, offset_base, addr); 365 else 366 n = idigit(buf, 7, offset_base, addr); 367 for (m = 0; m < n; m++) 368 putc(buf[m], stdout); 369 } else { 370 /* 371 * Precompute the length of the address in 372 * characters if possible (speed improvement). 373 */ 374 switch (offset_base) { 375 case 8: 376 a = addr; 377 for (s = 0; a != 0; s++) 378 a >>= 3; 379 break; 380 case 16: 381 a = addr; 382 for (s = 0; a != 0; s++) 383 a >>= 4; 384 break; 385 default: 386 s = sizeof buf; 387 } 388 if (addr > UINT_MAX) 389 n = lldigit(buf, s, offset_base, addr); 390 else 391 n = idigit(buf, s, offset_base, addr); 392 for (m = 0; buf[m] == '0'; m++); 393 while (m < n) { 394 putc(buf[m], stdout); 395 m++; 396 } 397 } 398 } 399 if (c != '\0') 400 putc(c, stdout); 401 } 402 403 /* 404 * Print a number of output lines, each preceded by the offset column. 405 */ 406 static void 407 prnt(long long addr, const char *s) 408 { 409 int lc = 0; 410 411 do { 412 if (lc++ == 0) 413 prna(addr, '\0'); 414 else 415 fputs(" ", stdout); 416 do 417 putc(*s, stdout); 418 while (*s++ != '\n'); 419 } while (*s != '\0'); 420 } 421 422 /* 423 * Append a string to a group of output lines, or flush if s == NULL. 424 */ 425 static void 426 put(const char *s) 427 { 428 static char *ob, *Ob; 429 static size_t os, Os, ol; 430 static int eq; 431 432 if (s == NULL) { 433 if (Ob && !vflag && expensive && strcmp(ob, Ob) == 0) { 434 if (eq++ == 0) 435 printf("*\n"); 436 } else { 437 prnt(offset, ob); 438 if (ol + 1 > Os) 439 Ob = srealloc(Ob, Os = ol + 1); 440 strcpy(Ob, ob); 441 eq = 0; 442 } 443 ol = 0; 444 } else { 445 size_t l = strlen(s); 446 447 if (ol + l + 1 >= os) 448 ob = srealloc(ob, os = ol + l + 1); 449 strcpy(&ob[ol], s); 450 ol += l; 451 } 452 } 453 454 /* 455 * Format the data within the buffers according to tp. 456 */ 457 static void 458 format(struct type *tp, struct buffer *b1, struct buffer *b2) 459 { 460 char buf[200]; 461 int i, j, n, l = 0; 462 463 switch (tp->t_fmt) { 464 case 'a': 465 case '\0': 466 case 'c': 467 for (i = 0; i < b1->bu_cnt; i++) { 468 int c = b1->bu_blk.b_c[i] & 0377; 469 470 if (tp->t_fmt == 'a') 471 c &= 0177; 472 if (tp->t_rst) { 473 strcpy(&buf[l], " **"); 474 tp->t_rst--; 475 l += 4; 476 } else if (tp->t_fmt != 'a' && c > 040 && 477 mb_cur_max > 1) { 478 char mb[MB_LEN_MAX]; 479 struct buffer *bp; 480 int m, n; 481 wchar_t wc; 482 483 m = i; 484 bp = b1; 485 for (n = 0; n < mb_cur_max; n++) { 486 mb[n] = bp->bu_blk.b_c[m++]; 487 if (m >= bp->bu_cnt) { 488 if (bp == b1) { 489 bp = b2; 490 m = 0; 491 } else 492 break; 493 } 494 } 495 mb[n] = '\0'; 496 if ((n = mbtowc(&wc, mb, mb_cur_max)) <= 0 497 || !iswprint(wc)) 498 goto spec; 499 m = wcwidth(wc); 500 do 501 buf[l++] = ' '; 502 while (++m < 4); 503 for (m = 0; m < n; m++) 504 buf[l++] = mb[m]; 505 if (n > 1) 506 tp->t_rst = n - 1; 507 } else if (c > 040 && isprint(c)) { 508 buf[l++] = ' '; 509 buf[l++] = ' '; 510 buf[l++] = ' '; 511 buf[l++] = c; 512 } else { 513 spec: if (c <= 040) { 514 buf[l] = ' '; 515 switch (tp->t_fmt) { 516 case 'a': 517 strcpy(&buf[l+1], ctab_a[c]); 518 break; 519 case '\0': 520 strcpy(&buf[l+1], ctab_0[c]); 521 break; 522 case 'c': 523 strcpy(&buf[l+1], ctab_c[c]); 524 break; 525 } 526 l += 4; 527 } else if (tp->t_fmt == 'a' && c == '\177') { 528 strcpy(&buf[l], " del"); 529 l += 4; 530 } else 531 l += inumber(&buf[l], "\3\10", c); 532 } 533 } 534 break; 535 case 'f': 536 case 'd': 537 case 'o': 538 case 'u': 539 case 'x': 540 for (i = 0, n = 0; 541 i < BLOCK / tp->t_cnt && n < b1->bu_cnt; 542 i++, n += tp->t_cnt) { 543 if (stretch) { 544 for (j = 0; j < tp->t_pad + stretch - 1; j++) 545 buf[l++] = ' '; 546 } 547 if (tp->t_fmt == 'f') { 548 switch (tp->t_cnt) { 549 case 4: 550 l += sprintf(&buf[l], tp->t_prf, 551 b1->bu_blk.b_f[i]); 552 break; 553 case 8: 554 l += sprintf(&buf[l], tp->t_prf, 555 b1->bu_blk.b_d[i]); 556 break; 557 } 558 } else { 559 switch (tp->t_cnt) { 560 case 1: 561 if (tp->t_fmt == 'd') 562 l += sprintf(&buf[l], tp->t_prf, 563 b1->bu_blk.b_c[i]); 564 else 565 l += inumber(&buf[l], tp->t_prf, 566 b1->bu_blk.b_c[i]&0377); 567 break; 568 case 2: 569 if (tp->t_fmt == 'd') 570 l += inumber(&buf[l], tp->t_prf, 571 b1->bu_blk.b_16[i]); 572 else 573 l += inumber(&buf[l], tp->t_prf, 574 b1->bu_blk.b_16[i] & 0177777U); 575 break; 576 case 4: 577 if (tp->t_fmt == 'd') 578 l += lnumber(&buf[l], tp->t_prf, 579 b1->bu_blk.b_32[i]); 580 else 581 l += lnumber(&buf[l], tp->t_prf, 582 b1->bu_blk.b_32[i] & 583 037777777777UL); 584 break; 585 case 8: 586 if (tp->t_fmt == 'd') 587 l+= llnumber(&buf[l], tp->t_prf, 588 b1->bu_blk.b_64[i]); 589 else 590 l+= llnumber(&buf[l], tp->t_prf, 591 b1->bu_blk.b_64[i] & 592 01777777777777777777777ULL); 593 break; 594 } 595 } 596 } 597 } 598 if (Cflag && b1->bu_cnt > 0) { 599 static int max; 600 int c; 601 if (max == 0) 602 max = l * (BLOCK/tp->t_cnt) / 603 ((b1->bu_cnt+tp->t_cnt-1) / tp->t_cnt); 604 while (l < max) 605 buf[l++] = ' '; 606 buf[l++] = ' '; 607 for (i = 0; i < b1->bu_cnt || i % 8; i++) { 608 c = i < b1->bu_cnt ? b1->bu_blk.b_c[i] & 0377 : '.'; 609 buf[l++] = isprint(c) ? c : '.'; 610 } 611 } 612 buf[l++] = '\n'; 613 buf[l] = '\0'; 614 put(buf); 615 } 616 617 /* 618 * Main execution loop. Two input buffers are necessary because multibyte 619 * characters for the -c option do not always end at a buffer boundary. 620 */ 621 static void 622 od(void) 623 { 624 struct buffer b1, b2, *bp, *bq; 625 struct type *tp; 626 int star = 0; 627 628 offset = total; 629 fill(bp = &b1); 630 fill(bq = &b2); 631 if (hadinput == 0) 632 return; 633 do { 634 if (star == 0) { 635 for (tp = types; tp; tp = tp->t_nxt) 636 format(tp, bp, bq); 637 put(NULL); 638 } 639 offset += bp->bu_cnt; 640 bp = (bp == &b1 ? &b2 : &b1); 641 bq = (bq == &b1 ? &b2 : &b1); 642 /* 643 * If no multibyte characters are to be printed, identical 644 * input blocks always lead to identical output lines. It 645 * is thus not necessary to format them for comparison; 646 * comparing at this point saves a lot of time for files 647 * that contain many identical lines. 648 */ 649 if (!vflag && !expensive && bp->bu_cnt && 650 bp->bu_cnt == bq->bu_cnt && 651 memcmp(bp->bu_blk.b_c, bq->bu_blk.b_c, 652 bp->bu_cnt) == 0) { 653 if (star == 0) 654 printf("*\n"); 655 star = 1; 656 } else 657 star = 0; 658 } while (fill(bq) > 0 || bp->bu_cnt > 0); 659 if (total > 0) 660 prna(total, '\n'); 661 } 662 663 /*************************** OPTION SCANNING *****************************/ 664 static void 665 usage(void) 666 { 667 fprintf(stderr, "usage: %s [-bcdDfFoOsSvxX] [file] [[+]offset[.][b]]\n", 668 progname); 669 exit(2); 670 } 671 672 static void 673 setfiles(char **av) 674 { 675 if (*av) 676 files = av; 677 else { 678 curfile = stdin; 679 hadinput = 1; 680 if (limit >= 0) 681 setvbuf(stdin, NULL, _IONBF, 0); 682 } 683 } 684 685 static void 686 invarg(int c) 687 { 688 fprintf(stderr, "%s: invalid argument to option -%c\n", progname, c); 689 usage(); 690 } 691 692 /* 693 * Compute output column alignment. 694 */ 695 static void 696 align(void) 697 { 698 struct type *tp, *tq; 699 700 for (tp = types; tp && tp->t_nxt; tp = tp->t_nxt) { 701 tq = tp->t_nxt; 702 703 if (tp->t_pad != tq->t_pad) { 704 stretch = 1; 705 break; 706 } 707 } 708 } 709 710 /* 711 * Add an element to the list of types. 712 */ 713 static void 714 addtype(char fmt, char cnt) 715 { 716 struct type *tp, *tq; 717 int i; 718 719 tp = scalloc(1, sizeof *tp); 720 tp->t_fmt = fmt; 721 tp->t_cnt = cnt; 722 for (i = 0; prf[i].p_prf; i++) { 723 if (prf[i].p_cnt == cnt && prf[i].p_fmt == fmt) { 724 tp->t_prf = prf[i].p_prf; 725 tp->t_pad = prf[i].p_pad; 726 tp->t_000 = prf[i].p_000; 727 break; 728 } 729 } 730 if (types) { 731 for (tq = types; tq->t_nxt; tq = tq->t_nxt); 732 tq->t_nxt = tp; 733 } else 734 types = tp; 735 } 736 737 /* 738 * Handle the argument to -t. 739 */ 740 static int 741 settype(const char *s) 742 { 743 char fmt, cnt; 744 745 if (s == NULL) { 746 expensive = mb_cur_max > 1; 747 addtype('\0', 1); 748 return 0; 749 } 750 while (*s) { 751 switch (fmt = *s++) { 752 case 'c': 753 expensive = mb_cur_max > 1; 754 /*FALLTHRU*/ 755 case 'a': 756 addtype(fmt, 1); 757 break; 758 case 'f': 759 switch (*s) { 760 case 'F': 761 case '4': 762 cnt = 4; 763 s++; 764 break; 765 case 'D': 766 case 'L': 767 case '8': 768 cnt = 8; 769 s++; 770 break; 771 default: 772 cnt = 8; 773 } 774 addtype(fmt, cnt); 775 break; 776 case 'd': 777 case 'o': 778 case 'u': 779 case 'x': 780 switch (*s) { 781 case '1': 782 cnt = 1; 783 s++; 784 break; 785 case 'C': 786 cnt = sizeof (char); 787 s++; 788 break; 789 case '2': 790 cnt = 2; 791 s++; 792 break; 793 case 'S': 794 cnt = sizeof (short); 795 s++; 796 break; 797 case '4': 798 cnt = 4; 799 s++; 800 break; 801 case 'I': 802 cnt = sizeof (int); 803 s++; 804 break; 805 case '8': 806 cnt = 8; 807 s++; 808 break; 809 case 'L': 810 cnt = sizeof (long); 811 s++; 812 break; 813 default: 814 cnt = sizeof (int); 815 } 816 addtype(fmt, cnt); 817 break; 818 default: 819 return -1; 820 } 821 } 822 return 0; 823 } 824 825 /* 826 * Handle a traditional offset argument. 827 */ 828 static int 829 setoffset(const char *s) 830 { 831 long long o; 832 const char *sp; 833 int base = 8; 834 int mult = 1; 835 836 skipstr = s; 837 if (*s == '+') 838 s++; 839 for (sp = s; digitchar(*sp & 0377); sp++); 840 if (sp > s) { 841 if (*sp == '.') { 842 base = 10; 843 sp++; 844 } 845 if (*sp == 'b' || *sp == 'B') { 846 mult = 512; 847 sp++; 848 } 849 if (*sp != '\0') 850 return -1; 851 } else 852 return -1; 853 o = strtoll(s, NULL, base); 854 skip = o * mult; 855 return 0; 856 } 857 858 /* 859 * Handle the argument to -j. 860 */ 861 static int 862 setskip(const char *s) 863 { 864 const char *sp = NULL; 865 long long o; 866 int base = 10; 867 int mult = 1; 868 869 skipstr = s; 870 if (s[0] == '0' && s[1]) { 871 s++; 872 if (*s == 'x' || *s == 'X') { 873 s++; 874 base = 16; 875 } else 876 base = 8; 877 } 878 switch (base) { 879 case 8: 880 for (sp = s; octalchar(*sp & 0377); sp++); 881 break; 882 case 10: 883 for (sp = s; digitchar(*sp & 0377); sp++); 884 break; 885 case 16: 886 for (sp = s; digitchar(*sp & 0377) || 887 *sp == 'a' || *sp == 'A' || 888 *sp == 'b' || *sp == 'B' || 889 *sp == 'c' || *sp == 'C' || 890 *sp == 'd' || *sp == 'D' || 891 *sp == 'e' || *sp == 'E' || 892 *sp == 'f' || *sp == 'F'; 893 sp++); 894 break; 895 } 896 if (sp > s) { 897 switch (*sp) { 898 case 'b': 899 mult = 512; 900 sp++; 901 break; 902 case 'k': 903 mult = 1024; 904 sp++; 905 break; 906 case 'm': 907 mult = 1048576; 908 sp++; 909 break; 910 case '\0': 911 break; 912 default: 913 return -1; 914 } 915 if (*sp != '\0') 916 return -1; 917 } else 918 return -1; 919 o = strtoull(s, NULL, base); 920 skip = o * mult; 921 return 0; 922 } 923 924 /* 925 * Handle the argument to -N. 926 */ 927 static int 928 setlimit(const char *s) 929 { 930 long long o; 931 char *x; 932 int base = 10; 933 934 if (*s == '0') { 935 s++; 936 if (*s == 'x' || *s == 'X') { 937 s++; 938 base = 16; 939 } else 940 base = 8; 941 } 942 o = strtoll(s, &x, base); 943 if (*x != '\0') 944 return -1; 945 limit = o; 946 return 0; 947 } 948 949 int 950 main(int argc, char **argv) 951 { 952 const char optstring[] = ":A:bcCdDfFj:N:oOsSt:vxX"; 953 int i, newopt = 0;; 954 955 setlocale(LC_CTYPE, ""); 956 mb_cur_max = MB_CUR_MAX; 957 if (sizeof (union block) != BLOCK || mb_cur_max > BLOCK) 958 abort(); 959 progname = basename(argv[0]); 960 #ifdef __GLIBC__ 961 putenv("POSIXLY_CORRECT=1"); 962 #endif 963 while ((i = getopt(argc, argv, optstring)) != EOF) { 964 switch (i) { 965 case 'A': 966 switch (optarg[0]) { 967 case 'd': 968 offset_base = 10; 969 offset_oflo = 9999999; 970 break; 971 case 'o': 972 offset_base = 8; 973 offset_oflo = 07777777; 974 break; 975 case 'x': 976 offset_base = 16; 977 offset_oflo = 0xfffffff; 978 break; 979 case 'n': 980 offset_base = 0; 981 break; 982 default: 983 invarg(i); 984 } 985 if (optarg[1] != '\0') 986 invarg(i); 987 newopt = 1; 988 break; 989 case 'b': 990 settype("o1"); 991 break; 992 case 'c': 993 settype(NULL); 994 break; 995 case 'd': 996 settype("u2"); 997 break; 998 case 'D': 999 settype("u4"); 1000 break; 1001 case 'f': 1002 settype("fF"); 1003 break; 1004 case 'F': 1005 settype("fD"); 1006 break; 1007 case 'j': 1008 if (setskip(optarg) < 0) 1009 invarg(i); 1010 newopt = 1; 1011 break; 1012 case 'N': 1013 if (setlimit(optarg) < 0) 1014 invarg(i); 1015 newopt = 1; 1016 break; 1017 case 'o': 1018 settype("o2"); 1019 break; 1020 case 'O': 1021 settype("o4"); 1022 break; 1023 case 's': 1024 settype("d2"); 1025 break; 1026 case 'S': 1027 settype("d4"); 1028 break; 1029 case 't': 1030 if (settype(optarg) < 0) 1031 invarg('t'); 1032 newopt = 1; 1033 break; 1034 case 'v': 1035 vflag = 1; 1036 break; 1037 case 'x': 1038 settype("x2"); 1039 break; 1040 case 'X': 1041 settype("x4"); 1042 break; 1043 case ':': 1044 fprintf(stderr, 1045 "%s: option requires an argument -- %c\n", 1046 progname, optopt); 1047 usage(); 1048 case 'C': 1049 Cflag = 1; 1050 break; 1051 case '?': 1052 fprintf(stderr, "%s: bad flag -%c\n", 1053 progname, optopt); 1054 /*FALLTHRU*/ 1055 default: 1056 usage(); 1057 } 1058 } 1059 if (newopt == 0 && ((optind>=argc-2 && argc &&argv[argc-1][0] == '+') || 1060 #ifndef SUS 1061 (optind>=argc-2 && argc && 1062 #else /* SUS */ 1063 (optind == argc-1 && 1064 #endif /* SUS */ 1065 digitchar(argv[argc-1][0] & 0377))) && 1066 setoffset(argv[argc-1]) >= 0) { 1067 argc--; 1068 argv[argc] = NULL; 1069 } 1070 setfiles(argc ? &argv[optind] : &argv[0]); 1071 if (types == NULL) 1072 settype("oS"); 1073 align(); 1074 if (skip > 0) 1075 doskip(); 1076 od(); 1077 return errcnt; 1078 }