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