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