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() getopt32(argv, \
65 "A:N:abcdfhij:lot:*vxsS:w:+:", \
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} FIX_ALIASING;
215#if !ENABLE_LONG_OPTS
216enum { G_pseudo_offset = 0 };
217#endif
218#define G (*(struct globals*)bb_common_bufsiz1)
219#define INIT_G() do { \
220 setup_common_bufsiz(); \
221 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
222 G.bytes_per_block = 32; \
223} while (0)
224
225
226#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
227static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
228 [sizeof(char)] = CHAR,
229#if USHRT_MAX != UCHAR_MAX
230 [sizeof(short)] = SHORT,
231#endif
232#if UINT_MAX != USHRT_MAX
233 [sizeof(int)] = INT,
234#endif
235#if ULONG_MAX != UINT_MAX
236 [sizeof(long)] = LONG,
237#endif
238#if ULLONG_MAX != ULONG_MAX
239 [sizeof(ulonglong_t)] = LONG_LONG,
240#endif
241};
242
243#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
244static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
245
246 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
247 [sizeof(double)] = FLOAT_DOUBLE,
248 [sizeof(float)] = FLOAT_SINGLE
249};
250
251
252static unsigned
253gcd(unsigned u, unsigned v)
254{
255 unsigned t;
256 while (v != 0) {
257 t = u % v;
258 u = v;
259 v = t;
260 }
261 return u;
262}
263
264
265static unsigned
266lcm(unsigned u, unsigned v) {
267 unsigned t = gcd(u, v);
268 if (t == 0)
269 return 0;
270 return u * v / t;
271}
272
273static void
274print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
275{
276 while (n_bytes--) {
277 int tmp = *(signed char *) block;
278 printf(fmt_string, tmp);
279 block += sizeof(unsigned char);
280 }
281}
282
283static void
284print_char(size_t n_bytes, const char *block, const char *fmt_string)
285{
286 while (n_bytes--) {
287 unsigned tmp = *(unsigned char *) block;
288 printf(fmt_string, tmp);
289 block += sizeof(unsigned char);
290 }
291}
292
293static void
294print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
295{
296 n_bytes /= sizeof(signed short);
297 while (n_bytes--) {
298 int tmp = *(signed short *) block;
299 printf(fmt_string, tmp);
300 block += sizeof(unsigned short);
301 }
302}
303
304static void
305print_short(size_t n_bytes, const char *block, const char *fmt_string)
306{
307 n_bytes /= sizeof(unsigned short);
308 while (n_bytes--) {
309 unsigned tmp = *(unsigned short *) block;
310 printf(fmt_string, tmp);
311 block += sizeof(unsigned short);
312 }
313}
314
315static void
316print_int(size_t n_bytes, const char *block, const char *fmt_string)
317{
318 n_bytes /= sizeof(unsigned);
319 while (n_bytes--) {
320 unsigned tmp = *(unsigned *) block;
321 printf(fmt_string, tmp);
322 block += sizeof(unsigned);
323 }
324}
325
326#if UINT_MAX == ULONG_MAX
327# define print_long print_int
328#else
329static void
330print_long(size_t n_bytes, const char *block, const char *fmt_string)
331{
332 n_bytes /= sizeof(unsigned long);
333 while (n_bytes--) {
334 unsigned long tmp = *(unsigned long *) block;
335 printf(fmt_string, tmp);
336 block += sizeof(unsigned long);
337 }
338}
339#endif
340
341#if ULONG_MAX == ULLONG_MAX
342# define print_long_long print_long
343#else
344static void
345print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
346{
347 n_bytes /= sizeof(ulonglong_t);
348 while (n_bytes--) {
349 ulonglong_t tmp = *(ulonglong_t *) block;
350 printf(fmt_string, tmp);
351 block += sizeof(ulonglong_t);
352 }
353}
354#endif
355
356static void
357print_float(size_t n_bytes, const char *block, const char *fmt_string)
358{
359 n_bytes /= sizeof(float);
360 while (n_bytes--) {
361 float tmp = *(float *) block;
362 printf(fmt_string, tmp);
363 block += sizeof(float);
364 }
365}
366
367static void
368print_double(size_t n_bytes, const char *block, const char *fmt_string)
369{
370 n_bytes /= sizeof(double);
371 while (n_bytes--) {
372 double tmp = *(double *) block;
373 printf(fmt_string, tmp);
374 block += sizeof(double);
375 }
376}
377
378static void
379print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
380{
381 n_bytes /= sizeof(longdouble_t);
382 while (n_bytes--) {
383 longdouble_t tmp = *(longdouble_t *) block;
384 printf(fmt_string, tmp);
385 block += sizeof(longdouble_t);
386 }
387}
388
389
390
391
392
393static void
394print_named_ascii(size_t n_bytes, const char *block,
395 const char *unused_fmt_string UNUSED_PARAM)
396{
397
398 static const char charname[33][3] ALIGN1 = {
399 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
400 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
401 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
402 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
403 " sp"
404 };
405
406 char buf[12] = " x\0 xxx\0";
407
408
409
410
411
412 while (n_bytes--) {
413 unsigned masked_c = *(unsigned char *) block++;
414
415 masked_c &= 0x7f;
416 if (masked_c == 0x7f) {
417 fputs(" del", stdout);
418 continue;
419 }
420 if (masked_c > ' ') {
421 buf[3] = masked_c;
422 fputs(buf, stdout);
423 continue;
424 }
425
426 buf[6] = charname[masked_c][0];
427 buf[7] = charname[masked_c][1];
428 buf[8] = charname[masked_c][2];
429 fputs(buf+5, stdout);
430 }
431}
432
433static void
434print_ascii(size_t n_bytes, const char *block,
435 const char *unused_fmt_string UNUSED_PARAM)
436{
437
438 char buf[12] = " x\0 xxx\0";
439
440 while (n_bytes--) {
441 const char *s;
442 unsigned c = *(unsigned char *) block++;
443
444 if (ISPRINT(c)) {
445 buf[3] = c;
446 fputs(buf, stdout);
447 continue;
448 }
449 switch (c) {
450 case '\0':
451 s = " \\0";
452 break;
453 case '\007':
454 s = " \\a";
455 break;
456 case '\b':
457 s = " \\b";
458 break;
459 case '\f':
460 s = " \\f";
461 break;
462 case '\n':
463 s = " \\n";
464 break;
465 case '\r':
466 s = " \\r";
467 break;
468 case '\t':
469 s = " \\t";
470 break;
471 case '\v':
472 s = " \\v";
473 break;
474 default:
475 buf[6] = (c >> 6 & 3) + '0';
476 buf[7] = (c >> 3 & 7) + '0';
477 buf[8] = (c & 7) + '0';
478 s = buf + 5;
479 }
480 fputs(s, stdout);
481 }
482}
483
484
485
486
487
488
489
490
491static void
492open_next_file(void)
493{
494 while (1) {
495 if (!*G.file_list)
496 return;
497 G.in_stream = fopen_or_warn_stdin(*G.file_list++);
498 if (G.in_stream) {
499 break;
500 }
501 G.exit_code = 1;
502 }
503
504 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
505 setbuf(G.in_stream, NULL);
506}
507
508
509
510
511
512
513
514
515static void
516check_and_close(void)
517{
518 if (G.in_stream) {
519 if (ferror(G.in_stream)) {
520 bb_error_msg("%s: read error", (G.in_stream == stdin)
521 ? bb_msg_standard_input
522 : G.file_list[-1]
523 );
524 G.exit_code = 1;
525 }
526 fclose_if_not_stdin(G.in_stream);
527 G.in_stream = NULL;
528 }
529
530 if (ferror(stdout)) {
531 bb_error_msg_and_die(bb_msg_write_error);
532 }
533}
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549static NOINLINE const char *
550decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
551{
552 enum size_spec size_spec;
553 unsigned size;
554 enum output_format fmt;
555 const char *p;
556 char *end;
557 char *fmt_string = NULL;
558 void (*print_function) (size_t, const char *, const char *);
559 unsigned c;
560 unsigned field_width = 0;
561 int pos;
562
563 switch (*s) {
564 case 'd':
565 case 'o':
566 case 'u':
567 case 'x': {
568 static const char CSIL[] ALIGN1 = "CSIL";
569
570 c = *s++;
571 p = strchr(CSIL, *s);
572
573 if (!p || *p == '\0') {
574 size = sizeof(int);
575 if (isdigit(s[0])) {
576 size = bb_strtou(s, &end, 0);
577 if (errno == ERANGE
578 || MAX_INTEGRAL_TYPE_SIZE < size
579 || integral_type_size[size] == NO_SIZE
580 ) {
581 bb_error_msg_and_die("invalid type string '%s'; "
582 "%u-byte %s type is not supported",
583 s_orig, size, "integral");
584 }
585 s = end;
586 }
587 } else {
588 static const uint8_t CSIL_sizeof[4] = {
589 sizeof(char),
590 sizeof(short),
591 sizeof(int),
592 sizeof(long),
593 };
594 size = CSIL_sizeof[p - CSIL];
595 s++;
596 }
597
598#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
599 ((Spec) == LONG_LONG ? (Max_format) \
600 : ((Spec) == LONG ? (Long_format) : (Min_format)))
601
602#define FMT_BYTES_ALLOCATED 9
603 size_spec = integral_type_size[size];
604
605 {
606 static const char doux[] ALIGN1 = "doux";
607 static const char doux_fmt_letter[][4] = {
608 "lld", "llo", "llu", "llx"
609 };
610 static const enum output_format doux_fmt[] = {
611 SIGNED_DECIMAL,
612 OCTAL,
613 UNSIGNED_DECIMAL,
614 HEXADECIMAL,
615 };
616 static const uint8_t *const doux_bytes_to_XXX[] = {
617 bytes_to_signed_dec_digits,
618 bytes_to_oct_digits,
619 bytes_to_unsigned_dec_digits,
620 bytes_to_hex_digits,
621 };
622 static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
623 " %%%u%s",
624 " %%0%u%s",
625 " %%%u%s",
626 " %%0%u%s",
627 };
628
629 pos = strchr(doux, c) - doux;
630 fmt = doux_fmt[pos];
631 field_width = doux_bytes_to_XXX[pos][size];
632 p = doux_fmt_letter[pos] + 2;
633 if (size_spec == LONG) p--;
634 if (size_spec == LONG_LONG) p -= 2;
635 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
636 }
637
638 switch (size_spec) {
639 case CHAR:
640 print_function = (fmt == SIGNED_DECIMAL
641 ? print_s_char
642 : print_char);
643 break;
644 case SHORT:
645 print_function = (fmt == SIGNED_DECIMAL
646 ? print_s_short
647 : print_short);
648 break;
649 case INT:
650 print_function = print_int;
651 break;
652 case LONG:
653 print_function = print_long;
654 break;
655 default:
656 print_function = print_long_long;
657 break;
658 }
659 break;
660 }
661
662 case 'f': {
663 static const char FDL[] ALIGN1 = "FDL";
664
665 fmt = FLOATING_POINT;
666 ++s;
667 p = strchr(FDL, *s);
668 if (!p) {
669 size = sizeof(double);
670 if (isdigit(s[0])) {
671 size = bb_strtou(s, &end, 0);
672 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
673 || fp_type_size[size] == NO_SIZE
674 ) {
675 bb_error_msg_and_die("invalid type string '%s'; "
676 "%u-byte %s type is not supported",
677 s_orig, size, "floating point");
678 }
679 s = end;
680 }
681 } else {
682 static const uint8_t FDL_sizeof[] = {
683 sizeof(float),
684 sizeof(double),
685 sizeof(longdouble_t),
686 };
687
688 size = FDL_sizeof[p - FDL];
689 }
690
691 size_spec = fp_type_size[size];
692
693 switch (size_spec) {
694 case FLOAT_SINGLE:
695 print_function = print_float;
696 field_width = FLT_DIG + 8;
697
698 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
699 break;
700 case FLOAT_DOUBLE:
701 print_function = print_double;
702 field_width = DBL_DIG + 8;
703 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
704 break;
705 default:
706 print_function = print_long_double;
707 field_width = LDBL_DIG + 8;
708 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
709 break;
710 }
711 break;
712 }
713
714 case 'a':
715 ++s;
716 fmt = NAMED_CHARACTER;
717 size_spec = CHAR;
718 print_function = print_named_ascii;
719 field_width = 3;
720 break;
721 case 'c':
722 ++s;
723 fmt = CHARACTER;
724 size_spec = CHAR;
725 print_function = print_ascii;
726 field_width = 3;
727 break;
728 default:
729 bb_error_msg_and_die("invalid character '%c' "
730 "in type string '%s'", *s, s_orig);
731 }
732
733 tspec->size = size_spec;
734 tspec->fmt = fmt;
735 tspec->print_function = print_function;
736 tspec->fmt_string = fmt_string;
737
738 tspec->field_width = field_width;
739 tspec->hexl_mode_trailer = (*s == 'z');
740 if (tspec->hexl_mode_trailer)
741 s++;
742
743 return s;
744}
745
746
747
748
749
750static void
751decode_format_string(const char *s)
752{
753 const char *s_orig = s;
754
755 while (*s != '\0') {
756 struct tspec tspec;
757 const char *next;
758
759 next = decode_one_format(s_orig, s, &tspec);
760
761 assert(s != next);
762 s = next;
763 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
764 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
765 G.n_specs++;
766 }
767}
768
769
770
771
772
773
774
775
776static void
777skip(off_t n_skip)
778{
779 if (n_skip == 0)
780 return;
781
782 while (G.in_stream) {
783 struct stat file_stats;
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800 if (fstat(fileno(G.in_stream), &file_stats) == 0
801 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
802 ) {
803 if (file_stats.st_size < n_skip) {
804 n_skip -= file_stats.st_size;
805
806 } else {
807 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
808 G.exit_code = 1;
809 return;
810 }
811 } else {
812
813
814 char buf[1024];
815 size_t n_bytes_to_read = 1024;
816 size_t n_bytes_read;
817
818 while (n_skip > 0) {
819 if (n_skip < n_bytes_to_read)
820 n_bytes_to_read = n_skip;
821 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
822 n_skip -= n_bytes_read;
823 if (n_bytes_read != n_bytes_to_read)
824 break;
825 }
826 }
827 if (n_skip == 0)
828 return;
829
830 check_and_close();
831 open_next_file();
832 }
833
834 if (n_skip)
835 bb_error_msg_and_die("can't skip past end of combined input");
836}
837
838
839typedef void FN_format_address(off_t address, char c);
840
841static void
842format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
843{
844}
845
846static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
847
848#define address_base_char address_fmt[sizeof(address_fmt)-3]
849
850#define address_pad_len_char address_fmt[2]
851
852static void
853format_address_std(off_t address, char c)
854{
855
856 address_fmt[sizeof(address_fmt)-2] = c;
857 printf(address_fmt, address);
858}
859
860#if ENABLE_LONG_OPTS
861
862static void
863format_address_paren(off_t address, char c)
864{
865 putchar('(');
866 format_address_std(address, ')');
867 if (c) putchar(c);
868}
869
870static void
871format_address_label(off_t address, char c)
872{
873 format_address_std(address, ' ');
874 format_address_paren(address + G_pseudo_offset, c);
875}
876#endif
877
878static void
879dump_hexl_mode_trailer(size_t n_bytes, const char *block)
880{
881 fputs(" >", stdout);
882 while (n_bytes--) {
883 unsigned c = *(unsigned char *) block++;
884 c = (ISPRINT(c) ? c : '.');
885 putchar(c);
886 }
887 putchar('<');
888}
889
890
891
892
893
894
895
896
897
898
899
900
901static void
902write_block(off_t current_offset, size_t n_bytes,
903 const char *prev_block, const char *curr_block)
904{
905 unsigned i;
906
907 if (!(option_mask32 & OPT_v)
908 && G.not_first
909 && n_bytes == G.bytes_per_block
910 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
911 ) {
912 if (G.prev_pair_equal) {
913
914
915 } else {
916 puts("*");
917 G.prev_pair_equal = 1;
918 }
919 } else {
920 G.not_first = 1;
921 G.prev_pair_equal = 0;
922 for (i = 0; i < G.n_specs; i++) {
923 if (i == 0)
924 G.format_address(current_offset, '\0');
925 else
926 printf("%*s", address_pad_len_char - '0', "");
927 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
928 if (G.spec[i].hexl_mode_trailer) {
929
930 unsigned datum_width = width_bytes[G.spec[i].size];
931 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
932 unsigned field_width = G.spec[i].field_width + 1;
933 printf("%*s", blank_fields * field_width, "");
934 dump_hexl_mode_trailer(n_bytes, curr_block);
935 }
936 putchar('\n');
937 }
938 }
939}
940
941static void
942read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
943{
944 assert(0 < n && n <= G.bytes_per_block);
945
946 *n_bytes_in_buffer = 0;
947
948 if (n == 0)
949 return;
950
951 while (G.in_stream != NULL) {
952 size_t n_needed;
953 size_t n_read;
954
955 n_needed = n - *n_bytes_in_buffer;
956 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
957 *n_bytes_in_buffer += n_read;
958 if (n_read == n_needed)
959 break;
960
961 check_and_close();
962 open_next_file();
963 }
964}
965
966
967
968
969static int
970get_lcm(void)
971{
972 size_t i;
973 int l_c_m = 1;
974
975 for (i = 0; i < G.n_specs; i++)
976 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
977 return l_c_m;
978}
979
980
981
982
983
984
985
986
987
988
989
990static void
991dump(off_t current_offset, off_t end_offset)
992{
993 char *block[2];
994 int idx;
995 size_t n_bytes_read;
996
997 block[0] = xmalloc(2 * G.bytes_per_block);
998 block[1] = block[0] + G.bytes_per_block;
999
1000 idx = 0;
1001 if (option_mask32 & OPT_N) {
1002 while (1) {
1003 size_t n_needed;
1004 if (current_offset >= end_offset) {
1005 n_bytes_read = 0;
1006 break;
1007 }
1008 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
1009 read_block(n_needed, block[idx], &n_bytes_read);
1010 if (n_bytes_read < G.bytes_per_block)
1011 break;
1012 assert(n_bytes_read == G.bytes_per_block);
1013 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1014 current_offset += n_bytes_read;
1015 idx ^= 1;
1016 }
1017 } else {
1018 while (1) {
1019 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1020 if (n_bytes_read < G.bytes_per_block)
1021 break;
1022 assert(n_bytes_read == G.bytes_per_block);
1023 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1024 current_offset += n_bytes_read;
1025 idx ^= 1;
1026 }
1027 }
1028
1029 if (n_bytes_read > 0) {
1030 int l_c_m;
1031 size_t bytes_to_write;
1032
1033 l_c_m = get_lcm();
1034
1035
1036
1037 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1038
1039 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1040 write_block(current_offset, bytes_to_write,
1041 block[idx ^ 1], block[idx]);
1042 current_offset += n_bytes_read;
1043 }
1044
1045 G.format_address(current_offset, '\n');
1046
1047 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
1048 check_and_close();
1049
1050 free(block[0]);
1051}
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073static void
1074dump_strings(off_t address, off_t end_offset)
1075{
1076 unsigned bufsize = MAX(100, G.string_min);
1077 unsigned char *buf = xmalloc(bufsize);
1078
1079 while (1) {
1080 size_t i;
1081 int c;
1082
1083
1084 tryline:
1085 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
1086 break;
1087 i = 0;
1088 while (!(option_mask32 & OPT_N) || address < end_offset) {
1089 if (i == bufsize) {
1090 bufsize += bufsize/8;
1091 buf = xrealloc(buf, bufsize);
1092 }
1093
1094 while (G.in_stream) {
1095 c = fgetc(G.in_stream);
1096 if (c != EOF)
1097 goto got_char;
1098 check_and_close();
1099 open_next_file();
1100 }
1101
1102 goto ret;
1103 got_char:
1104 address++;
1105 if (!c)
1106 break;
1107 if (!ISPRINT(c))
1108 goto tryline;
1109 buf[i++] = c;
1110 }
1111
1112 if (i < G.string_min)
1113 goto tryline;
1114
1115
1116 buf[i] = 0;
1117 G.format_address(address - i - 1, ' ');
1118
1119 for (i = 0; (c = buf[i]); i++) {
1120 switch (c) {
1121 case '\007': fputs("\\a", stdout); break;
1122 case '\b': fputs("\\b", stdout); break;
1123 case '\f': fputs("\\f", stdout); break;
1124 case '\n': fputs("\\n", stdout); break;
1125 case '\r': fputs("\\r", stdout); break;
1126 case '\t': fputs("\\t", stdout); break;
1127 case '\v': fputs("\\v", stdout); break;
1128 default: putchar(c);
1129 }
1130 }
1131 putchar('\n');
1132 }
1133
1134
1135
1136 check_and_close();
1137 ret:
1138 free(buf);
1139}
1140
1141#if ENABLE_LONG_OPTS
1142
1143
1144
1145static int
1146parse_old_offset(const char *s, off_t *offset)
1147{
1148 static const struct suffix_mult Bb[] = {
1149 { "B", 1024 },
1150 { "b", 512 },
1151 { "", 0 }
1152 };
1153 char *p;
1154 int radix;
1155
1156
1157 if (s[0] == '+') ++s;
1158 if (!isdigit(s[0])) return 0;
1159
1160
1161
1162
1163 p = strchr(s, '.');
1164 radix = 8;
1165 if (p) {
1166 p[0] = '\0';
1167 radix = 10;
1168 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1169 radix = 16;
1170
1171 *offset = xstrtooff_sfx(s, radix, Bb);
1172 if (p) p[0] = '.';
1173
1174 return (*offset >= 0);
1175}
1176#endif
1177
1178int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1179int od_main(int argc UNUSED_PARAM, char **argv)
1180{
1181#if ENABLE_LONG_OPTS
1182 static const char od_longopts[] ALIGN1 =
1183 "skip-bytes\0" Required_argument "j"
1184 "address-radix\0" Required_argument "A"
1185 "read-bytes\0" Required_argument "N"
1186 "format\0" Required_argument "t"
1187 "output-duplicates\0" No_argument "v"
1188
1189
1190
1191 "strings\0" Optional_argument "S"
1192 "width\0" Optional_argument "w"
1193 "traditional\0" No_argument "\xff"
1194 ;
1195#endif
1196 const char *str_A, *str_N, *str_j, *str_S = "3";
1197 llist_t *lst_t = NULL;
1198 unsigned opt;
1199 int l_c_m;
1200
1201 off_t n_bytes_to_skip = 0;
1202
1203 off_t end_offset = 0;
1204
1205 off_t max_bytes_to_format = 0;
1206
1207 INIT_G();
1208
1209
1210 G.format_address = format_address_std;
1211 address_base_char = 'o';
1212 address_pad_len_char = '7';
1213
1214
1215#if ENABLE_LONG_OPTS
1216 applet_long_options = od_longopts;
1217#endif
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_error_msg_and_die("the last two arguments must be offsets");
1312 }
1313 } else {
1314 bb_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_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 for (i = 0; i < G.n_specs; i++) {
1377 printf("%d: fmt=\"%s\" width=%d\n",
1378 i, spec[i].fmt_string, width_bytes[spec[i].size]);
1379 }
1380#endif
1381
1382 if (option_mask32 & OPT_S)
1383 dump_strings(n_bytes_to_skip, end_offset);
1384 else
1385 dump(n_bytes_to_skip, end_offset);
1386
1387 if (fclose(stdin))
1388 bb_perror_msg_and_die(bb_msg_standard_input);
1389
1390 return G.exit_code;
1391}
1392