1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include "common_bufsiz.h"
24#define assert(a) ((void)0)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41enum {
42 OPT_A = 1 << 0,
43 OPT_N = 1 << 1,
44 OPT_a = 1 << 2,
45 OPT_b = 1 << 3,
46 OPT_c = 1 << 4,
47 OPT_d = 1 << 5,
48 OPT_D = 1 << 6,
49 OPT_f = 1 << 7,
50 OPT_h = 1 << 8,
51 OPT_H = 1 << 9,
52 OPT_i = 1 << 10,
53 OPT_I = 1 << 11,
54 OPT_j = 1 << 12,
55 OPT_l = 1 << 13,
56 OPT_L = 1 << 14,
57 OPT_o = 1 << 15,
58 OPT_O = 1 << 16,
59 OPT_B = 1 << 17,
60 OPT_t = 1 << 18,
61
62
63
64 OPT_v = 1 << 19,
65 OPT_x = 1 << 20,
66 OPT_X = 1 << 21,
67 OPT_s = 1 << 22,
68 OPT_S = 1 << 23,
69 OPT_w = 1 << 24,
70 OPT_traditional = (1 << 25) * ENABLE_LONG_OPTS,
71};
72
73#define OD_GETOPT32() getopt32long(argv, \
74 "A:N:abcdDfhHiIj:lLoOBt:*vxXsS:w:+:", od_longopts, \
75 \
76 \
77 \
78 \
79 &str_A, &str_N, &str_j, &lst_t, &str_S, &G.bytes_per_block)
80
81
82
83#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f)
84
85typedef long double longdouble_t;
86typedef unsigned long long ulonglong_t;
87typedef long long llong;
88
89#if ENABLE_LFS
90# define xstrtooff_sfx xstrtoull_sfx
91#else
92# define xstrtooff_sfx xstrtoul_sfx
93#endif
94
95
96#define DEFAULT_BYTES_PER_BLOCK 16
97
98
99#ifndef FLT_DIG
100# define FLT_DIG 7
101#endif
102
103
104#ifndef DBL_DIG
105# define DBL_DIG 15
106#endif
107
108
109#ifndef LDBL_DIG
110# define LDBL_DIG DBL_DIG
111#endif
112
113enum size_spec {
114 NO_SIZE,
115 CHAR,
116 SHORT,
117 INT,
118 LONG,
119 LONG_LONG,
120 FLOAT_SINGLE,
121 FLOAT_DOUBLE,
122 FLOAT_LONG_DOUBLE,
123 N_SIZE_SPECS
124};
125
126enum output_format {
127 SIGNED_DECIMAL,
128 UNSIGNED_DECIMAL,
129 OCTAL,
130 HEXADECIMAL,
131 FLOATING_POINT,
132 NAMED_CHARACTER,
133 CHARACTER
134};
135
136
137
138struct tspec {
139 enum output_format fmt;
140 enum size_spec size;
141 void (*print_function) (size_t, const char *, const char *);
142 char *fmt_string;
143 int hexl_mode_trailer;
144 int field_width;
145};
146
147
148
149
150
151
152
153
154
155
156
157static const uint8_t bytes_to_oct_digits[] ALIGN1 =
158{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
159
160static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 =
161{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
162
163static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 =
164{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
165
166static const uint8_t bytes_to_hex_digits[] ALIGN1 =
167{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
168
169
170static const signed char width_bytes[] ALIGN1 = {
171 -1,
172 sizeof(char),
173 sizeof(short),
174 sizeof(int),
175 sizeof(long),
176 sizeof(ulonglong_t),
177 sizeof(float),
178 sizeof(double),
179 sizeof(longdouble_t)
180};
181
182
183struct ERR_width_bytes_has_bad_size {
184 char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
185};
186
187struct globals {
188 smallint exit_code;
189
190 unsigned string_min;
191
192
193 unsigned n_specs;
194 struct tspec *spec;
195
196
197
198 void (*format_address)(off_t, char);
199
200
201
202#if ENABLE_LONG_OPTS
203 off_t pseudo_offset;
204# define G_pseudo_offset G.pseudo_offset
205#endif
206
207
208
209
210
211
212
213 unsigned bytes_per_block;
214
215
216 const char *const *file_list;
217
218
219 FILE *in_stream;
220
221 bool not_first;
222 bool prev_pair_equal;
223
224 char address_fmt[sizeof("%0n"OFF_FMT"xc")];
225} FIX_ALIASING;
226
227#define address_base_char G.address_fmt[sizeof(G.address_fmt)-3]
228
229#define address_pad_len_char G.address_fmt[2]
230
231#if !ENABLE_LONG_OPTS
232enum { G_pseudo_offset = 0 };
233#endif
234#define G (*(struct globals*)bb_common_bufsiz1)
235#define INIT_G() do { \
236 setup_common_bufsiz(); \
237 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
238 G.bytes_per_block = 32; \
239 strcpy(G.address_fmt, "%0n"OFF_FMT"xc"); \
240} while (0)
241
242
243#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
244static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
245 [sizeof(char)] = CHAR,
246#if USHRT_MAX != UCHAR_MAX
247 [sizeof(short)] = SHORT,
248#endif
249#if UINT_MAX != USHRT_MAX
250 [sizeof(int)] = INT,
251#endif
252#if ULONG_MAX != UINT_MAX
253 [sizeof(long)] = LONG,
254#endif
255#if ULLONG_MAX != ULONG_MAX
256 [sizeof(ulonglong_t)] = LONG_LONG,
257#endif
258};
259
260#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
261static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
262
263 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
264 [sizeof(double)] = FLOAT_DOUBLE,
265 [sizeof(float)] = FLOAT_SINGLE
266};
267
268
269static unsigned
270gcd(unsigned u, unsigned v)
271{
272 unsigned t;
273 while (v != 0) {
274 t = u % v;
275 u = v;
276 v = t;
277 }
278 return u;
279}
280
281
282static unsigned
283lcm(unsigned u, unsigned v) {
284 unsigned t = gcd(u, v);
285 if (t == 0)
286 return 0;
287 return u * v / t;
288}
289
290static void
291print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
292{
293 while (n_bytes--) {
294 int tmp = *(signed char *) block;
295 printf(fmt_string, tmp);
296 block += sizeof(unsigned char);
297 }
298}
299
300static void
301print_char(size_t n_bytes, const char *block, const char *fmt_string)
302{
303 while (n_bytes--) {
304 unsigned tmp = *(unsigned char *) block;
305 printf(fmt_string, tmp);
306 block += sizeof(unsigned char);
307 }
308}
309
310static void
311print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
312{
313 n_bytes /= sizeof(signed short);
314 while (n_bytes--) {
315 int tmp = *(signed short *) block;
316 printf(fmt_string, tmp);
317 block += sizeof(unsigned short);
318 }
319}
320
321static void
322print_short(size_t n_bytes, const char *block, const char *fmt_string)
323{
324 n_bytes /= sizeof(unsigned short);
325 while (n_bytes--) {
326 unsigned tmp = *(unsigned short *) block;
327 printf(fmt_string, tmp);
328 block += sizeof(unsigned short);
329 }
330}
331
332static void
333print_int(size_t n_bytes, const char *block, const char *fmt_string)
334{
335 n_bytes /= sizeof(unsigned);
336 while (n_bytes--) {
337 unsigned tmp = *(unsigned *) block;
338 printf(fmt_string, tmp);
339 block += sizeof(unsigned);
340 }
341}
342
343#if UINT_MAX == ULONG_MAX
344# define print_long print_int
345#else
346static void
347print_long(size_t n_bytes, const char *block, const char *fmt_string)
348{
349 n_bytes /= sizeof(unsigned long);
350 while (n_bytes--) {
351 unsigned long tmp = *(unsigned long *) block;
352 printf(fmt_string, tmp);
353 block += sizeof(unsigned long);
354 }
355}
356#endif
357
358#if ULONG_MAX == ULLONG_MAX
359# define print_long_long print_long
360#else
361static void
362print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
363{
364 n_bytes /= sizeof(ulonglong_t);
365 while (n_bytes--) {
366 ulonglong_t tmp = *(ulonglong_t *) block;
367 printf(fmt_string, tmp);
368 block += sizeof(ulonglong_t);
369 }
370}
371#endif
372
373static void
374print_float(size_t n_bytes, const char *block, const char *fmt_string)
375{
376 n_bytes /= sizeof(float);
377 while (n_bytes--) {
378 float tmp = *(float *) block;
379 printf(fmt_string, tmp);
380 block += sizeof(float);
381 }
382}
383
384static void
385print_double(size_t n_bytes, const char *block, const char *fmt_string)
386{
387 n_bytes /= sizeof(double);
388 while (n_bytes--) {
389 double tmp = *(double *) block;
390 printf(fmt_string, tmp);
391 block += sizeof(double);
392 }
393}
394
395static void
396print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
397{
398 n_bytes /= sizeof(longdouble_t);
399 while (n_bytes--) {
400 longdouble_t tmp = *(longdouble_t *) block;
401 printf(fmt_string, tmp);
402 block += sizeof(longdouble_t);
403 }
404}
405
406
407
408
409
410static void
411print_named_ascii(size_t n_bytes, const char *block,
412 const char *unused_fmt_string UNUSED_PARAM)
413{
414
415 static const char charname[33][3] ALIGN1 = {
416 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
417 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
418 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
419 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
420 " sp"
421 };
422
423 char buf[12] = " x\0 xxx\0";
424
425
426
427
428
429 while (n_bytes--) {
430 unsigned masked_c = *(unsigned char *) block++;
431
432 masked_c &= 0x7f;
433 if (masked_c == 0x7f) {
434 fputs_stdout(" del");
435 continue;
436 }
437 if (masked_c > ' ') {
438 buf[3] = masked_c;
439 fputs_stdout(buf);
440 continue;
441 }
442
443 buf[6] = charname[masked_c][0];
444 buf[7] = charname[masked_c][1];
445 buf[8] = charname[masked_c][2];
446 fputs_stdout(buf+5);
447 }
448}
449
450static void
451print_ascii(size_t n_bytes, const char *block,
452 const char *unused_fmt_string UNUSED_PARAM)
453{
454
455 char buf[12] = " x\0 xxx\0";
456
457 while (n_bytes--) {
458 const char *s;
459 unsigned c = *(unsigned char *) block++;
460
461 if (ISPRINT(c)) {
462 buf[3] = c;
463 fputs_stdout(buf);
464 continue;
465 }
466 switch (c) {
467 case '\0':
468 s = " \\0";
469 break;
470 case '\007':
471 s = " \\a";
472 break;
473 case '\b':
474 s = " \\b";
475 break;
476 case '\f':
477 s = " \\f";
478 break;
479 case '\n':
480 s = " \\n";
481 break;
482 case '\r':
483 s = " \\r";
484 break;
485 case '\t':
486 s = " \\t";
487 break;
488 case '\v':
489 s = " \\v";
490 break;
491 default:
492 buf[6] = (c >> 6 & 3) + '0';
493 buf[7] = (c >> 3 & 7) + '0';
494 buf[8] = (c & 7) + '0';
495 s = buf + 5;
496 }
497 fputs_stdout(s);
498 }
499}
500
501
502
503
504
505
506
507
508static void
509open_next_file(void)
510{
511 while (1) {
512 if (!*G.file_list)
513 return;
514 G.in_stream = fopen_or_warn_stdin(*G.file_list++);
515 if (G.in_stream) {
516 break;
517 }
518 G.exit_code = 1;
519 }
520
521 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
522 setbuf(G.in_stream, NULL);
523}
524
525
526
527
528
529
530
531
532static void
533check_and_close(void)
534{
535 if (G.in_stream) {
536 if (ferror(G.in_stream)) {
537 bb_error_msg("%s: read error", (G.in_stream == stdin)
538 ? bb_msg_standard_input
539 : G.file_list[-1]
540 );
541 G.exit_code = 1;
542 }
543 fclose_if_not_stdin(G.in_stream);
544 G.in_stream = NULL;
545 }
546
547 if (ferror(stdout)) {
548 bb_simple_error_msg_and_die(bb_msg_write_error);
549 }
550}
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566static NOINLINE const char *
567decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
568{
569 enum size_spec size_spec;
570 unsigned size;
571 enum output_format fmt;
572 const char *p;
573 char *end;
574 char *fmt_string = NULL;
575 void (*print_function) (size_t, const char *, const char *);
576 unsigned c;
577 unsigned field_width = 0;
578 int pos;
579
580 switch (*s) {
581 case 'd':
582 case 'o':
583 case 'u':
584 case 'x': {
585 static const char CSIL[] ALIGN1 = "CSIL";
586
587 c = *s++;
588 p = strchr(CSIL, *s);
589
590 if (!p || *p == '\0') {
591 size = sizeof(int);
592 if (isdigit(s[0])) {
593 size = bb_strtou(s, &end, 0);
594 if (errno == ERANGE
595 || MAX_INTEGRAL_TYPE_SIZE < size
596 || integral_type_size[size] == NO_SIZE
597 ) {
598 bb_error_msg_and_die("invalid type string '%s'; "
599 "%u-byte %s type is not supported",
600 s_orig, size, "integral");
601 }
602 s = end;
603 }
604 } else {
605 static const uint8_t CSIL_sizeof[4] = {
606 sizeof(char),
607 sizeof(short),
608 sizeof(int),
609 sizeof(long),
610 };
611 size = CSIL_sizeof[p - CSIL];
612 s++;
613 }
614
615#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
616 ((Spec) == LONG_LONG ? (Max_format) \
617 : ((Spec) == LONG ? (Long_format) : (Min_format)))
618
619#define FMT_BYTES_ALLOCATED 9
620 size_spec = integral_type_size[size];
621
622 {
623 static const char doux[] ALIGN1 = "doux";
624 static const char doux_fmt_letter[][4] = {
625 "lld", "llo", "llu", "llx"
626 };
627 static const enum output_format doux_fmt[] = {
628 SIGNED_DECIMAL,
629 OCTAL,
630 UNSIGNED_DECIMAL,
631 HEXADECIMAL,
632 };
633 static const uint8_t *const doux_bytes_to_XXX[] = {
634 bytes_to_signed_dec_digits,
635 bytes_to_oct_digits,
636 bytes_to_unsigned_dec_digits,
637 bytes_to_hex_digits,
638 };
639 static const char doux_fmtstring[][sizeof(" %%0%u%s")] ALIGN1 = {
640 " %%%u%s",
641 " %%0%u%s",
642 " %%%u%s",
643 " %%0%u%s",
644 };
645
646 pos = strchr(doux, c) - doux;
647 fmt = doux_fmt[pos];
648 field_width = doux_bytes_to_XXX[pos][size];
649 p = doux_fmt_letter[pos] + 2;
650 if (size_spec == LONG) p--;
651 if (size_spec == LONG_LONG) p -= 2;
652 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
653 }
654
655 switch (size_spec) {
656 case CHAR:
657 print_function = (fmt == SIGNED_DECIMAL
658 ? print_s_char
659 : print_char);
660 break;
661 case SHORT:
662 print_function = (fmt == SIGNED_DECIMAL
663 ? print_s_short
664 : print_short);
665 break;
666 case INT:
667 print_function = print_int;
668 break;
669 case LONG:
670 print_function = print_long;
671 break;
672 default:
673 print_function = print_long_long;
674 break;
675 }
676 break;
677 }
678
679 case 'f': {
680 static const char FDL[] ALIGN1 = "FDL";
681
682 fmt = FLOATING_POINT;
683 ++s;
684 p = strchr(FDL, *s);
685 if (!p || *p == '\0') {
686 size = sizeof(double);
687 if (isdigit(s[0])) {
688 size = bb_strtou(s, &end, 0);
689 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
690 || fp_type_size[size] == NO_SIZE
691 ) {
692 bb_error_msg_and_die("invalid type string '%s'; "
693 "%u-byte %s type is not supported",
694 s_orig, size, "floating point");
695 }
696 s = end;
697 }
698 } else {
699 static const uint8_t FDL_sizeof[] = {
700 sizeof(float),
701 sizeof(double),
702 sizeof(longdouble_t),
703 };
704
705 size = FDL_sizeof[p - FDL];
706 s++;
707 }
708
709 size_spec = fp_type_size[size];
710
711 switch (size_spec) {
712 case FLOAT_SINGLE:
713 print_function = print_float;
714 field_width = FLT_DIG + 8;
715
716 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
717 break;
718 case FLOAT_DOUBLE:
719 print_function = print_double;
720 field_width = DBL_DIG + 8;
721 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
722 break;
723 default:
724 print_function = print_long_double;
725 field_width = LDBL_DIG + 8;
726 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
727 break;
728 }
729 break;
730 }
731
732 case 'a':
733 ++s;
734 fmt = NAMED_CHARACTER;
735 size_spec = CHAR;
736 print_function = print_named_ascii;
737 field_width = 3;
738 break;
739 case 'c':
740 ++s;
741 fmt = CHARACTER;
742 size_spec = CHAR;
743 print_function = print_ascii;
744 field_width = 3;
745 break;
746 default:
747 bb_error_msg_and_die("invalid character '%c' "
748 "in type string '%s'", *s, s_orig);
749 }
750
751 tspec->size = size_spec;
752 tspec->fmt = fmt;
753 tspec->print_function = print_function;
754 tspec->fmt_string = fmt_string;
755
756 tspec->field_width = field_width;
757 tspec->hexl_mode_trailer = (*s == 'z');
758 if (tspec->hexl_mode_trailer)
759 s++;
760
761 return s;
762}
763
764
765
766
767
768static void
769decode_format_string(const char *s)
770{
771 const char *s_orig = s;
772
773 while (*s != '\0') {
774 struct tspec tspec;
775 const char *next;
776
777 next = decode_one_format(s_orig, s, &tspec);
778
779 assert(s != next);
780 s = next;
781 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
782 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
783 G.n_specs++;
784 }
785}
786
787
788
789
790
791
792
793
794static void
795skip(off_t n_skip)
796{
797 if (n_skip == 0)
798 return;
799
800 while (G.in_stream) {
801 struct stat file_stats;
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818 if (fstat(fileno(G.in_stream), &file_stats) == 0
819 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
820 ) {
821 if (file_stats.st_size < n_skip) {
822 n_skip -= file_stats.st_size;
823
824 } else {
825 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
826 G.exit_code = 1;
827 return;
828 }
829 } else {
830
831
832 char buf[1024];
833 size_t n_bytes_to_read = 1024;
834 size_t n_bytes_read;
835
836 while (n_skip > 0) {
837 if (n_skip < n_bytes_to_read)
838 n_bytes_to_read = n_skip;
839 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
840 n_skip -= n_bytes_read;
841 if (n_bytes_read != n_bytes_to_read)
842 break;
843 }
844 }
845 if (n_skip == 0)
846 return;
847
848 check_and_close();
849 open_next_file();
850 }
851
852 if (n_skip)
853 bb_simple_error_msg_and_die("can't skip past end of combined input");
854}
855
856
857typedef void FN_format_address(off_t address, char c);
858
859static void
860format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
861{
862}
863
864static void
865format_address_std(off_t address, char c)
866{
867
868 G.address_fmt[sizeof(G.address_fmt)-2] = c;
869 printf(G.address_fmt, address);
870}
871
872#if ENABLE_LONG_OPTS
873
874static void
875format_address_paren(off_t address, char c)
876{
877 putchar('(');
878 format_address_std(address, ')');
879 if (c) putchar(c);
880}
881
882static void
883format_address_label(off_t address, char c)
884{
885 format_address_std(address, ' ');
886 format_address_paren(address + G_pseudo_offset, c);
887}
888#endif
889
890static void
891dump_hexl_mode_trailer(size_t n_bytes, const char *block)
892{
893 fputs_stdout(" >");
894 while (n_bytes--) {
895 unsigned c = *(unsigned char *) block++;
896 c = (ISPRINT(c) ? c : '.');
897 putchar(c);
898 }
899 putchar('<');
900}
901
902
903
904
905
906
907
908
909
910
911
912
913static void
914write_block(off_t current_offset, size_t n_bytes,
915 const char *prev_block, const char *curr_block)
916{
917 unsigned i;
918
919 if (!(option_mask32 & OPT_v)
920 && G.not_first
921 && n_bytes == G.bytes_per_block
922 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
923 ) {
924 if (G.prev_pair_equal) {
925
926
927 } else {
928 puts("*");
929 G.prev_pair_equal = 1;
930 }
931 } else {
932 G.not_first = 1;
933 G.prev_pair_equal = 0;
934 for (i = 0; i < G.n_specs; i++) {
935 if (i == 0)
936 G.format_address(current_offset, '\0');
937 else
938 printf("%*s", address_pad_len_char - '0', "");
939 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
940 if (G.spec[i].hexl_mode_trailer) {
941
942 unsigned datum_width = width_bytes[G.spec[i].size];
943 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
944 unsigned field_width = G.spec[i].field_width + 1;
945 printf("%*s", blank_fields * field_width, "");
946 dump_hexl_mode_trailer(n_bytes, curr_block);
947 }
948 putchar('\n');
949 }
950 }
951}
952
953static void
954read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
955{
956 assert(0 < n && n <= G.bytes_per_block);
957
958 *n_bytes_in_buffer = 0;
959
960 if (n == 0)
961 return;
962
963 while (G.in_stream != NULL) {
964 size_t n_needed;
965 size_t n_read;
966
967 n_needed = n - *n_bytes_in_buffer;
968 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
969 *n_bytes_in_buffer += n_read;
970 if (n_read == n_needed)
971 break;
972
973 check_and_close();
974 open_next_file();
975 }
976}
977
978
979
980
981static int
982get_lcm(void)
983{
984 size_t i;
985 int l_c_m = 1;
986
987 for (i = 0; i < G.n_specs; i++)
988 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
989 return l_c_m;
990}
991
992
993
994
995
996
997
998
999
1000
1001
1002static void
1003dump(off_t current_offset, off_t end_offset)
1004{
1005 char *block[2];
1006 int idx;
1007 size_t n_bytes_read;
1008
1009 block[0] = xmalloc(2 * G.bytes_per_block);
1010 block[1] = block[0] + G.bytes_per_block;
1011
1012 idx = 0;
1013 if (option_mask32 & OPT_N) {
1014 while (1) {
1015 size_t n_needed;
1016 if (current_offset >= end_offset) {
1017 n_bytes_read = 0;
1018 break;
1019 }
1020 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
1021 read_block(n_needed, block[idx], &n_bytes_read);
1022 if (n_bytes_read < G.bytes_per_block)
1023 break;
1024 assert(n_bytes_read == G.bytes_per_block);
1025 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1026 current_offset += n_bytes_read;
1027 idx ^= 1;
1028 }
1029 } else {
1030 while (1) {
1031 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1032 if (n_bytes_read < G.bytes_per_block)
1033 break;
1034 assert(n_bytes_read == G.bytes_per_block);
1035 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1036 current_offset += n_bytes_read;
1037 idx ^= 1;
1038 }
1039 }
1040
1041 if (n_bytes_read > 0) {
1042 int l_c_m;
1043 size_t bytes_to_write;
1044
1045 l_c_m = get_lcm();
1046
1047
1048
1049 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1050
1051 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1052 write_block(current_offset, bytes_to_write,
1053 block[idx ^ 1], block[idx]);
1054 current_offset += n_bytes_read;
1055 }
1056
1057 G.format_address(current_offset, '\n');
1058
1059 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
1060 check_and_close();
1061
1062 free(block[0]);
1063}
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085static void
1086dump_strings(off_t address, off_t end_offset)
1087{
1088 unsigned bufsize = MAX(100, G.string_min);
1089 unsigned char *buf = xmalloc(bufsize);
1090
1091 while (1) {
1092 size_t i;
1093 int c;
1094
1095
1096 tryline:
1097 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
1098 break;
1099 i = 0;
1100 while (!(option_mask32 & OPT_N) || address < end_offset) {
1101 if (i == bufsize) {
1102 bufsize += bufsize/8;
1103 buf = xrealloc(buf, bufsize);
1104 }
1105
1106 while (G.in_stream) {
1107 c = fgetc(G.in_stream);
1108 if (c != EOF)
1109 goto got_char;
1110 check_and_close();
1111 open_next_file();
1112 }
1113
1114 goto ret;
1115 got_char:
1116 address++;
1117 if (!c)
1118 break;
1119 if (!ISPRINT(c))
1120 goto tryline;
1121 buf[i++] = c;
1122 }
1123
1124 if (i < G.string_min)
1125 goto tryline;
1126
1127
1128 buf[i] = 0;
1129 G.format_address(address - i - 1, ' ');
1130
1131 for (i = 0; (c = buf[i]); i++) {
1132 switch (c) {
1133 case '\007': fputs_stdout("\\a"); break;
1134 case '\b': fputs_stdout("\\b"); break;
1135 case '\f': fputs_stdout("\\f"); break;
1136 case '\n': fputs_stdout("\\n"); break;
1137 case '\r': fputs_stdout("\\r"); break;
1138 case '\t': fputs_stdout("\\t"); break;
1139 case '\v': fputs_stdout("\\v"); break;
1140 default: putchar(c);
1141 }
1142 }
1143 putchar('\n');
1144 }
1145
1146
1147
1148 check_and_close();
1149 ret:
1150 free(buf);
1151}
1152
1153#if ENABLE_LONG_OPTS
1154
1155
1156
1157static int
1158parse_old_offset(const char *s, off_t *offset)
1159{
1160 static const struct suffix_mult Bb[] ALIGN_SUFFIX = {
1161 { "B", 1024 },
1162 { "b", 512 },
1163 { "", 0 }
1164 };
1165 char *p;
1166 int radix;
1167
1168
1169 if (s[0] == '+') ++s;
1170 if (!isdigit(s[0])) return 0;
1171
1172
1173
1174
1175 p = strchr(s, '.');
1176 radix = 8;
1177 if (p) {
1178 p[0] = '\0';
1179 radix = 10;
1180 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1181 radix = 16;
1182
1183 *offset = xstrtooff_sfx(s, radix, Bb);
1184 if (p) p[0] = '.';
1185
1186 return (*offset >= 0);
1187}
1188#endif
1189
1190int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1191int od_main(int argc UNUSED_PARAM, char **argv)
1192{
1193#if ENABLE_LONG_OPTS
1194 static const char od_longopts[] ALIGN1 =
1195 "skip-bytes\0" Required_argument "j"
1196 "address-radix\0" Required_argument "A"
1197 "read-bytes\0" Required_argument "N"
1198 "format\0" Required_argument "t"
1199 "output-duplicates\0" No_argument "v"
1200
1201
1202
1203 "strings\0" Optional_argument "S"
1204 "width\0" Optional_argument "w"
1205 "traditional\0" No_argument "\xff"
1206 ;
1207#endif
1208 const char *str_A, *str_N, *str_j, *str_S = "3";
1209 llist_t *lst_t = NULL;
1210 unsigned opt;
1211 int l_c_m;
1212
1213 off_t n_bytes_to_skip = 0;
1214
1215 off_t end_offset = 0;
1216
1217 off_t max_bytes_to_format = 0;
1218
1219 INIT_G();
1220
1221
1222 G.format_address = format_address_std;
1223 address_base_char = 'o';
1224 address_pad_len_char = '7';
1225
1226
1227 opt = OD_GETOPT32();
1228 argv += optind;
1229 if (opt & OPT_A) {
1230 static const char doxn[] ALIGN1 = "doxn";
1231 static const char doxn_address_base_char[] ALIGN1 = {
1232 'u', 'o', 'x',
1233 };
1234 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
1235 '7', '7', '6',
1236 };
1237 char *p;
1238 int pos;
1239 p = strchr(doxn, str_A[0]);
1240 if (!p)
1241 bb_error_msg_and_die("bad output address radix "
1242 "'%c' (must be [doxn])", str_A[0]);
1243 pos = p - doxn;
1244 if (pos == 3) G.format_address = format_address_none;
1245 address_base_char = doxn_address_base_char[pos];
1246 address_pad_len_char = doxn_address_pad_len_char[pos];
1247 }
1248 if (opt & OPT_N) {
1249 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
1250 }
1251
1252 if (opt & OPT_a) decode_format_string("a");
1253 if (opt & OPT_b) decode_format_string("oC");
1254 if (opt & OPT_c) decode_format_string("c");
1255 if (opt & OPT_d) decode_format_string("u2");
1256 if (opt & OPT_D) decode_format_string("uI");
1257 if (opt & OPT_f) decode_format_string("fF");
1258 if (opt & (OPT_h|OPT_x)) decode_format_string("x2");
1259 if (opt & (OPT_H|OPT_X)) decode_format_string("xI");
1260
1261#if ULONG_MAX > 0xffffffff
1262 if (opt & OPT_i) decode_format_string("dI");
1263 if (opt & (OPT_I|OPT_l|OPT_L)) decode_format_string("dL");
1264#else
1265
1266 if (opt & (OPT_i|OPT_I|OPT_l|OPT_L)) decode_format_string("dI");
1267#endif
1268 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
1269 if (opt & (OPT_o|OPT_B)) decode_format_string("o2");
1270 if (opt & OPT_O) decode_format_string("oI");
1271 while (lst_t) {
1272 decode_format_string(llist_pop(&lst_t));
1273 }
1274 if (opt & OPT_s) decode_format_string("d2");
1275 if (opt & OPT_S) {
1276 G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
1277 }
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292#if ENABLE_LONG_OPTS
1293 if (opt & OPT_traditional) {
1294 if (argv[0]) {
1295 off_t pseudo_start = -1;
1296 off_t o1, o2;
1297
1298 if (!argv[1]) {
1299 if (parse_old_offset(argv[0], &o1)) {
1300
1301 n_bytes_to_skip = o1;
1302 argv++;
1303 }
1304
1305 } else if (!argv[2]) {
1306 if (parse_old_offset(argv[0], &o1)
1307 && parse_old_offset(argv[1], &o2)
1308 ) {
1309
1310 n_bytes_to_skip = o1;
1311 pseudo_start = o2;
1312 argv += 2;
1313 } else if (parse_old_offset(argv[1], &o2)) {
1314
1315 n_bytes_to_skip = o2;
1316 argv[1] = NULL;
1317 } else {
1318 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1319 }
1320 } else if (!argv[3]) {
1321 if (parse_old_offset(argv[1], &o1)
1322 && parse_old_offset(argv[2], &o2)
1323 ) {
1324
1325 n_bytes_to_skip = o1;
1326 pseudo_start = o2;
1327 argv[1] = NULL;
1328 } else {
1329 bb_simple_error_msg_and_die("the last two arguments must be offsets");
1330 }
1331 } else {
1332 bb_simple_error_msg_and_die("too many arguments");
1333 }
1334
1335 if (pseudo_start >= 0) {
1336 if (G.format_address == format_address_none) {
1337 address_base_char = 'o';
1338 address_pad_len_char = '7';
1339 G.format_address = format_address_paren;
1340 } else {
1341 G.format_address = format_address_label;
1342 }
1343 G_pseudo_offset = pseudo_start - n_bytes_to_skip;
1344 }
1345 }
1346
1347 }
1348#endif
1349
1350 if (option_mask32 & OPT_N) {
1351 end_offset = n_bytes_to_skip + max_bytes_to_format;
1352 if (end_offset < n_bytes_to_skip)
1353 bb_simple_error_msg_and_die("SKIP + SIZE is too large");
1354 }
1355
1356 if (G.n_specs == 0) {
1357 decode_format_string("o2");
1358
1359 }
1360
1361
1362
1363
1364 G.file_list = bb_argv_dash;
1365 if (argv[0]) {
1366
1367
1368 G.file_list = (char const *const *) argv;
1369 }
1370
1371
1372 open_next_file();
1373
1374 skip(n_bytes_to_skip);
1375 if (!G.in_stream)
1376 return EXIT_FAILURE;
1377
1378
1379 l_c_m = get_lcm();
1380
1381 if (opt & OPT_w) {
1382 if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) {
1383 bb_error_msg("warning: invalid width %u; using %d instead",
1384 (unsigned)G.bytes_per_block, l_c_m);
1385 G.bytes_per_block = l_c_m;
1386 }
1387 } else {
1388 G.bytes_per_block = l_c_m;
1389 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
1390 G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
1391 }
1392
1393#ifdef DEBUG
1394 {
1395 int i;
1396 for (i = 0; i < G.n_specs; i++) {
1397 printf("%d: fmt='%s' width=%d\n",
1398 i, G.spec[i].fmt_string,
1399 width_bytes[G.spec[i].size]);
1400 }
1401 }
1402#endif
1403
1404 if (option_mask32 & OPT_S)
1405 dump_strings(n_bytes_to_skip, end_offset);
1406 else
1407 dump(n_bytes_to_skip, end_offset);
1408
1409 if (fclose(stdin))
1410 bb_simple_perror_msg_and_die(bb_msg_standard_input);
1411
1412 return G.exit_code;
1413}
1414