aboutsummaryrefslogtreecommitdiff
path: root/coreutils/od_bloaty.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/od_bloaty.c')
-rw-r--r--coreutils/od_bloaty.c443
1 files changed, 199 insertions, 244 deletions
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index 4c6b64d5e..8013f483c 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -13,48 +13,64 @@
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation, 15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 17 */
18/* Written by Jim Meyering. */ 18/* Written by Jim Meyering. */
19/* Busyboxed by Denys Vlasenko, based on od.c from coreutils-5.2.1 */
19 20
20/* Busyboxed by Denys Vlasenko
21
22Based on od.c from coreutils-5.2.1
23Top bloat sources:
24 21
2500000073 t parse_old_offset 22/* #include "libbb.h" - done in od.c */
260000007b t get_lcm 23#define assert(a) ((void)0)
2700000090 r long_options
2800000092 t print_named_ascii
29000000bf t print_ascii
3000000168 t write_block
3100000366 t decode_format_string
3200000a71 T od_main
33
34Tested for compat with coreutils 6.3
35using this script. Minor differences fixed.
36 24
37#!/bin/sh
38echo STD
39time /path/to/coreutils/od \
40...params... \
41>std
42echo Exit code $?
43echo BBOX
44time ./busybox od \
45...params... \
46>bbox
47echo Exit code $?
48diff -u -a std bbox >bbox.diff || { echo Different!; sleep 1; }
49 25
50*/ 26//usage:#if ENABLE_DESKTOP
27//usage:#define od_trivial_usage
28//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE...]"
29// We don't support:
30// ... [FILE] [[+]OFFSET[.][b]]
31// Support is buggy for:
32// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]]
33
34//usage:#define od_full_usage "\n\n"
35//usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default"
36//usage:#endif
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 /* When zero and two or more consecutive blocks are equal, format
53 only the first block and output an asterisk alone on the following
54 line to indicate that identical blocks have been elided: */
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};
51 62
52#include "libbb.h" 63#define OD_GETOPT32() getopt32(argv, \
64 "A:N:abcdfhij:lot:vxsS:w::", \
65 /* -w with optional param */ \
66 /* -S was -s and also had optional parameter */ \
67 /* but in coreutils 6.3 it was renamed and now has */ \
68 /* _mandatory_ parameter */ \
69 &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block)
53 70
54#define assert(a) ((void)0)
55 71
56/* Check for 0x7f is a coreutils 6.3 addition */ 72/* Check for 0x7f is a coreutils 6.3 addition */
57#define ISPRINT(c) (((c)>=' ') && (c) != 0x7f) 73#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f)
58 74
59typedef long double longdouble_t; 75typedef long double longdouble_t;
60typedef unsigned long long ulonglong_t; 76typedef unsigned long long ulonglong_t;
@@ -165,17 +181,9 @@ struct ERR_width_bytes_has_bad_size {
165 char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1]; 181 char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
166}; 182};
167 183
168static smallint flag_dump_strings; 184static smallint exit_code;
169/* Non-zero if an old-style 'pseudo-address' was specified. */
170static smallint flag_pseudo_start;
171static smallint limit_bytes_to_format;
172/* When zero and two or more consecutive blocks are equal, format
173 only the first block and output an asterisk alone on the following
174 line to indicate that identical blocks have been elided. */
175static smallint verbose;
176static smallint ioerror;
177 185
178static size_t string_min; 186static unsigned string_min;
179 187
180/* An array of specs describing how to format each input block. */ 188/* An array of specs describing how to format each input block. */
181static size_t n_specs; 189static size_t n_specs;
@@ -186,7 +194,11 @@ static struct tspec *spec;
186static void (*format_address)(off_t, char); 194static void (*format_address)(off_t, char);
187/* The difference between the old-style pseudo starting address and 195/* The difference between the old-style pseudo starting address and
188 the number of bytes to skip. */ 196 the number of bytes to skip. */
197#if ENABLE_LONG_OPTS
189static off_t pseudo_offset; 198static off_t pseudo_offset;
199#else
200enum { pseudo_offset = 0 };
201#endif
190/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all 202/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
191 input is formatted. */ 203 input is formatted. */
192 204
@@ -221,7 +233,7 @@ static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1
221 233
222#define MAX_FP_TYPE_SIZE sizeof(longdouble_t) 234#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
223static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = { 235static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
224 /* gcc seems to allow repeated indexes. Last one stays */ 236 /* gcc seems to allow repeated indexes. Last one wins */
225 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE, 237 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
226 [sizeof(double)] = FLOAT_DOUBLE, 238 [sizeof(double)] = FLOAT_DOUBLE,
227 [sizeof(float)] = FLOAT_SINGLE 239 [sizeof(float)] = FLOAT_SINGLE
@@ -383,7 +395,7 @@ print_named_ascii(size_t n_bytes, const char *block,
383 }; 395 };
384 // buf[N] pos: 01234 56789 396 // buf[N] pos: 01234 56789
385 char buf[12] = " x\0 0xx\0"; 397 char buf[12] = " x\0 0xx\0";
386 // actually " x\0 xxx\0", but I want to share the string with below. 398 // actually " x\0 xxx\0", but want to share string with print_ascii.
387 // [12] because we take three 32bit stack slots anyway, and 399 // [12] because we take three 32bit stack slots anyway, and
388 // gcc is too dumb to initialize with constant stores, 400 // gcc is too dumb to initialize with constant stores,
389 // it copies initializer from rodata. Oh well. 401 // it copies initializer from rodata. Oh well.
@@ -479,10 +491,10 @@ open_next_file(void)
479 if (in_stream) { 491 if (in_stream) {
480 break; 492 break;
481 } 493 }
482 ioerror = 1; 494 exit_code = 1;
483 } 495 }
484 496
485 if (limit_bytes_to_format && !flag_dump_strings) 497 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
486 setbuf(in_stream, NULL); 498 setbuf(in_stream, NULL);
487} 499}
488 500
@@ -502,15 +514,14 @@ check_and_close(void)
502 ? bb_msg_standard_input 514 ? bb_msg_standard_input
503 : file_list[-1] 515 : file_list[-1]
504 ); 516 );
505 ioerror = 1; 517 exit_code = 1;
506 } 518 }
507 fclose_if_not_stdin(in_stream); 519 fclose_if_not_stdin(in_stream);
508 in_stream = NULL; 520 in_stream = NULL;
509 } 521 }
510 522
511 if (ferror(stdout)) { 523 if (ferror(stdout)) {
512 bb_error_msg(bb_msg_write_error); 524 bb_error_msg_and_die(bb_msg_write_error);
513 ioerror = 1;
514 } 525 }
515} 526}
516 527
@@ -542,7 +553,6 @@ decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
542 unsigned field_width = 0; 553 unsigned field_width = 0;
543 int pos; 554 int pos;
544 555
545
546 switch (*s) { 556 switch (*s) {
547 case 'd': 557 case 'd':
548 case 'o': 558 case 'o':
@@ -788,7 +798,7 @@ skip(off_t n_skip)
788 /* take "check & close / open_next" route */ 798 /* take "check & close / open_next" route */
789 } else { 799 } else {
790 if (fseeko(in_stream, n_skip, SEEK_CUR) != 0) 800 if (fseeko(in_stream, n_skip, SEEK_CUR) != 0)
791 ioerror = 1; 801 exit_code = 1;
792 return; 802 return;
793 } 803 }
794 } else { 804 } else {
@@ -889,7 +899,8 @@ write_block(off_t current_offset, size_t n_bytes,
889 static char prev_pair_equal = 0; 899 static char prev_pair_equal = 0;
890 size_t i; 900 size_t i;
891 901
892 if (!verbose && !first 902 if (!(option_mask32 & OPT_v)
903 && !first
893 && n_bytes == bytes_per_block 904 && n_bytes == bytes_per_block
894 && memcmp(prev_block, curr_block, bytes_per_block) == 0 905 && memcmp(prev_block, curr_block, bytes_per_block) == 0
895 ) { 906 ) {
@@ -911,9 +922,9 @@ write_block(off_t current_offset, size_t n_bytes,
911 (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string); 922 (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string);
912 if (spec[i].hexl_mode_trailer) { 923 if (spec[i].hexl_mode_trailer) {
913 /* space-pad out to full line width, then dump the trailer */ 924 /* space-pad out to full line width, then dump the trailer */
914 int datum_width = width_bytes[spec[i].size]; 925 unsigned datum_width = width_bytes[spec[i].size];
915 int blank_fields = (bytes_per_block - n_bytes) / datum_width; 926 unsigned blank_fields = (bytes_per_block - n_bytes) / datum_width;
916 int field_width = spec[i].field_width + 1; 927 unsigned field_width = spec[i].field_width + 1;
917 printf("%*s", blank_fields * field_width, ""); 928 printf("%*s", blank_fields * field_width, "");
918 dump_hexl_mode_trailer(n_bytes, curr_block); 929 dump_hexl_mode_trailer(n_bytes, curr_block);
919 } 930 }
@@ -961,42 +972,6 @@ get_lcm(void)
961 return l_c_m; 972 return l_c_m;
962} 973}
963 974
964#if ENABLE_LONG_OPTS
965/* If S is a valid traditional offset specification with an optional
966 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
967
968static int
969parse_old_offset(const char *s, off_t *offset)
970{
971 static const struct suffix_mult Bb[] = {
972 { "B", 1024 },
973 { "b", 512 },
974 { "", 0 }
975 };
976 char *p;
977 int radix;
978
979 /* Skip over any leading '+'. */
980 if (s[0] == '+') ++s;
981
982 /* Determine the radix we'll use to interpret S. If there is a '.',
983 * it's decimal, otherwise, if the string begins with '0X'or '0x',
984 * it's hexadecimal, else octal. */
985 p = strchr(s, '.');
986 radix = 8;
987 if (p) {
988 p[0] = '\0'; /* cheating */
989 radix = 10;
990 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
991 radix = 16;
992
993 *offset = xstrtooff_sfx(s, radix, Bb);
994 if (p) p[0] = '.';
995
996 return (*offset >= 0);
997}
998#endif
999
1000/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the 975/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
1001 formatted block to standard output, and repeat until the specified 976 formatted block to standard output, and repeat until the specified
1002 maximum number of bytes has been read or until all input has been 977 maximum number of bytes has been read or until all input has been
@@ -1014,27 +989,25 @@ dump(off_t current_offset, off_t end_offset)
1014 int idx; 989 int idx;
1015 size_t n_bytes_read; 990 size_t n_bytes_read;
1016 991
1017 block[0] = xmalloc(2*bytes_per_block); 992 block[0] = xmalloc(2 * bytes_per_block);
1018 block[1] = block[0] + bytes_per_block; 993 block[1] = block[0] + bytes_per_block;
1019 994
1020 idx = 0; 995 idx = 0;
1021 if (limit_bytes_to_format) { 996 if (option_mask32 & OPT_N) {
1022 while (1) { 997 while (1) {
1023 size_t n_needed; 998 size_t n_needed;
1024 if (current_offset >= end_offset) { 999 if (current_offset >= end_offset) {
1025 n_bytes_read = 0; 1000 n_bytes_read = 0;
1026 break; 1001 break;
1027 } 1002 }
1028 n_needed = MIN(end_offset - current_offset, 1003 n_needed = MIN(end_offset - current_offset, (off_t) bytes_per_block);
1029 (off_t) bytes_per_block);
1030 read_block(n_needed, block[idx], &n_bytes_read); 1004 read_block(n_needed, block[idx], &n_bytes_read);
1031 if (n_bytes_read < bytes_per_block) 1005 if (n_bytes_read < bytes_per_block)
1032 break; 1006 break;
1033 assert(n_bytes_read == bytes_per_block); 1007 assert(n_bytes_read == bytes_per_block);
1034 write_block(current_offset, n_bytes_read, 1008 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1035 block[!idx], block[idx]);
1036 current_offset += n_bytes_read; 1009 current_offset += n_bytes_read;
1037 idx = !idx; 1010 idx ^= 1;
1038 } 1011 }
1039 } else { 1012 } else {
1040 while (1) { 1013 while (1) {
@@ -1042,10 +1015,9 @@ dump(off_t current_offset, off_t end_offset)
1042 if (n_bytes_read < bytes_per_block) 1015 if (n_bytes_read < bytes_per_block)
1043 break; 1016 break;
1044 assert(n_bytes_read == bytes_per_block); 1017 assert(n_bytes_read == bytes_per_block);
1045 write_block(current_offset, n_bytes_read, 1018 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1046 block[!idx], block[idx]);
1047 current_offset += n_bytes_read; 1019 current_offset += n_bytes_read;
1048 idx = !idx; 1020 idx ^= 1;
1049 } 1021 }
1050 } 1022 }
1051 1023
@@ -1061,41 +1033,18 @@ dump(off_t current_offset, off_t end_offset)
1061 1033
1062 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read); 1034 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1063 write_block(current_offset, bytes_to_write, 1035 write_block(current_offset, bytes_to_write,
1064 block[!idx], block[idx]); 1036 block[idx ^ 1], block[idx]);
1065 current_offset += n_bytes_read; 1037 current_offset += n_bytes_read;
1066 } 1038 }
1067 1039
1068 format_address(current_offset, '\n'); 1040 format_address(current_offset, '\n');
1069 1041
1070 if (limit_bytes_to_format && current_offset >= end_offset) 1042 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
1071 check_and_close(); 1043 check_and_close();
1072 1044
1073 free(block[0]); 1045 free(block[0]);
1074} 1046}
1075 1047
1076/* Read a single byte into *C from the concatenation of the input files
1077 named in the global array FILE_LIST. On the first call to this
1078 function, the global variable IN_STREAM is expected to be an open
1079 stream associated with the input file INPUT_FILENAME. If IN_STREAM
1080 is at end-of-file, close it and update the global variables IN_STREAM
1081 and INPUT_FILENAME so they correspond to the next file in the list.
1082 Then try to read a byte from the newly opened file. Repeat if
1083 necessary until EOF is reached for the last file in FILE_LIST, then
1084 set *C to EOF and return. Subsequent calls do likewise. */
1085
1086static void
1087read_char(int *c)
1088{
1089 while (in_stream) { /* !EOF */
1090 *c = fgetc(in_stream);
1091 if (*c != EOF)
1092 return;
1093 check_and_close();
1094 open_next_file();
1095 }
1096 *c = EOF;
1097}
1098
1099/* Read N bytes into BLOCK from the concatenation of the input files 1048/* Read N bytes into BLOCK from the concatenation of the input files
1100 named in the global array FILE_LIST. On the first call to this 1049 named in the global array FILE_LIST. On the first call to this
1101 function, the global variable IN_STREAM is expected to be an open 1050 function, the global variable IN_STREAM is expected to be an open
@@ -1119,8 +1068,8 @@ read_char(int *c)
1119static void 1068static void
1120dump_strings(off_t address, off_t end_offset) 1069dump_strings(off_t address, off_t end_offset)
1121{ 1070{
1122 size_t bufsize = MAX(100, string_min); 1071 unsigned bufsize = MAX(100, string_min);
1123 char *buf = xmalloc(bufsize); 1072 unsigned char *buf = xmalloc(bufsize);
1124 1073
1125 while (1) { 1074 while (1) {
1126 size_t i; 1075 size_t i;
@@ -1128,19 +1077,25 @@ dump_strings(off_t address, off_t end_offset)
1128 1077
1129 /* See if the next 'string_min' chars are all printing chars. */ 1078 /* See if the next 'string_min' chars are all printing chars. */
1130 tryline: 1079 tryline:
1131 if (limit_bytes_to_format && (end_offset - string_min <= address)) 1080 if ((option_mask32 & OPT_N) && (end_offset - string_min <= address))
1132 break; 1081 break;
1133 i = 0; 1082 i = 0;
1134 while (!limit_bytes_to_format || address < end_offset) { 1083 while (!(option_mask32 & OPT_N) || address < end_offset) {
1135 if (i == bufsize) { 1084 if (i == bufsize) {
1136 bufsize += bufsize/8; 1085 bufsize += bufsize/8;
1137 buf = xrealloc(buf, bufsize); 1086 buf = xrealloc(buf, bufsize);
1138 } 1087 }
1139 read_char(&c); 1088
1140 if (c < 0) { /* EOF */ 1089 while (in_stream) { /* !EOF */
1141 free(buf); 1090 c = fgetc(in_stream);
1142 return; 1091 if (c != EOF)
1092 goto got_char;
1093 check_and_close();
1094 open_next_file();
1143 } 1095 }
1096 /* EOF */
1097 goto ret;
1098 got_char:
1144 address++; 1099 address++;
1145 if (!c) 1100 if (!c)
1146 break; 1101 break;
@@ -1152,8 +1107,7 @@ dump_strings(off_t address, off_t end_offset)
1152 if (i < string_min) /* Too short! */ 1107 if (i < string_min) /* Too short! */
1153 goto tryline; 1108 goto tryline;
1154 1109
1155 /* If we get here, the string is all printable and NUL-terminated, 1110 /* If we get here, the string is all printable and NUL-terminated */
1156 * so print it. It is all in 'buf' and 'i' is its length. */
1157 buf[i] = 0; 1111 buf[i] = 0;
1158 format_address(address - i - 1, ' '); 1112 format_address(address - i - 1, ' ');
1159 1113
@@ -1174,13 +1128,50 @@ dump_strings(off_t address, off_t end_offset)
1174 1128
1175 /* We reach this point only if we search through 1129 /* We reach this point only if we search through
1176 (max_bytes_to_format - string_min) bytes before reaching EOF. */ 1130 (max_bytes_to_format - string_min) bytes before reaching EOF. */
1131 check_and_close();
1132 ret:
1177 free(buf); 1133 free(buf);
1134}
1178 1135
1179 check_and_close(); 1136#if ENABLE_LONG_OPTS
1137/* If S is a valid traditional offset specification with an optional
1138 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1139
1140static int
1141parse_old_offset(const char *s, off_t *offset)
1142{
1143 static const struct suffix_mult Bb[] = {
1144 { "B", 1024 },
1145 { "b", 512 },
1146 { "", 0 }
1147 };
1148 char *p;
1149 int radix;
1150
1151 /* Skip over any leading '+'. */
1152 if (s[0] == '+') ++s;
1153 if (!isdigit(s[0])) return 0; /* not a number */
1154
1155 /* Determine the radix we'll use to interpret S. If there is a '.',
1156 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1157 * it's hexadecimal, else octal. */
1158 p = strchr(s, '.');
1159 radix = 8;
1160 if (p) {
1161 p[0] = '\0'; /* cheating */
1162 radix = 10;
1163 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1164 radix = 16;
1165
1166 *offset = xstrtooff_sfx(s, radix, Bb);
1167 if (p) p[0] = '.';
1168
1169 return (*offset >= 0);
1180} 1170}
1171#endif
1181 1172
1182int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1173int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1183int od_main(int argc, char **argv) 1174int od_main(int argc UNUSED_PARAM, char **argv)
1184{ 1175{
1185 static const struct suffix_mult bkm[] = { 1176 static const struct suffix_mult bkm[] = {
1186 { "b", 512 }, 1177 { "b", 512 },
@@ -1188,27 +1179,6 @@ int od_main(int argc, char **argv)
1188 { "m", 1024*1024 }, 1179 { "m", 1024*1024 },
1189 { "", 0 } 1180 { "", 0 }
1190 }; 1181 };
1191 enum {
1192 OPT_A = 1 << 0,
1193 OPT_N = 1 << 1,
1194 OPT_a = 1 << 2,
1195 OPT_b = 1 << 3,
1196 OPT_c = 1 << 4,
1197 OPT_d = 1 << 5,
1198 OPT_f = 1 << 6,
1199 OPT_h = 1 << 7,
1200 OPT_i = 1 << 8,
1201 OPT_j = 1 << 9,
1202 OPT_l = 1 << 10,
1203 OPT_o = 1 << 11,
1204 OPT_t = 1 << 12,
1205 OPT_v = 1 << 13,
1206 OPT_x = 1 << 14,
1207 OPT_s = 1 << 15,
1208 OPT_S = 1 << 16,
1209 OPT_w = 1 << 17,
1210 OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS,
1211 };
1212#if ENABLE_LONG_OPTS 1182#if ENABLE_LONG_OPTS
1213 static const char od_longopts[] ALIGN1 = 1183 static const char od_longopts[] ALIGN1 =
1214 "skip-bytes\0" Required_argument "j" 1184 "skip-bytes\0" Required_argument "j"
@@ -1216,18 +1186,18 @@ int od_main(int argc, char **argv)
1216 "read-bytes\0" Required_argument "N" 1186 "read-bytes\0" Required_argument "N"
1217 "format\0" Required_argument "t" 1187 "format\0" Required_argument "t"
1218 "output-duplicates\0" No_argument "v" 1188 "output-duplicates\0" No_argument "v"
1189 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1190 * that is, NUM is mandatory for -S but optional for --strings!
1191 */
1219 "strings\0" Optional_argument "S" 1192 "strings\0" Optional_argument "S"
1220 "width\0" Optional_argument "w" 1193 "width\0" Optional_argument "w"
1221 "traditional\0" No_argument "\xff" 1194 "traditional\0" No_argument "\xff"
1222 ; 1195 ;
1223#endif 1196#endif
1224 char *str_A, *str_N, *str_j, *str_S; 1197 const char *str_A, *str_N, *str_j, *str_S = "3";
1225 llist_t *lst_t = NULL; 1198 llist_t *lst_t = NULL;
1226 unsigned opt; 1199 unsigned opt;
1227 int l_c_m; 1200 int l_c_m;
1228 /* The old-style 'pseudo starting address' to be printed in parentheses
1229 after any true address. */
1230 off_t pseudo_start = pseudo_start; // for gcc
1231 /* The number of input bytes to skip before formatting and writing. */ 1201 /* The number of input bytes to skip before formatting and writing. */
1232 off_t n_bytes_to_skip = 0; 1202 off_t n_bytes_to_skip = 0;
1233 /* The offset of the first byte after the last byte to be formatted. */ 1203 /* The offset of the first byte after the last byte to be formatted. */
@@ -1239,20 +1209,13 @@ int od_main(int argc, char **argv)
1239 format_address = format_address_std; 1209 format_address = format_address_std;
1240 address_base_char = 'o'; 1210 address_base_char = 'o';
1241 address_pad_len_char = '7'; 1211 address_pad_len_char = '7';
1242 /* flag_dump_strings = 0; - already is */
1243 1212
1244 /* Parse command line */ 1213 /* Parse command line */
1245 opt_complementary = "w+:t::"; /* -w N, -t is a list */ 1214 opt_complementary = "w+:t::"; /* -w N, -t is a list */
1246#if ENABLE_LONG_OPTS 1215#if ENABLE_LONG_OPTS
1247 applet_long_options = od_longopts; 1216 applet_long_options = od_longopts;
1248#endif 1217#endif
1249 opt = getopt32(argv, "A:N:abcdfhij:lot:vxsS:" 1218 opt = OD_GETOPT32();
1250 "w::", // -w with optional param
1251 // -S was -s and also had optional parameter
1252 // but in coreutils 6.3 it was renamed and now has
1253 // _mandatory_ parameter
1254 &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block);
1255 argc -= optind;
1256 argv += optind; 1219 argv += optind;
1257 if (opt & OPT_A) { 1220 if (opt & OPT_A) {
1258 static const char doxn[] ALIGN1 = "doxn"; 1221 static const char doxn[] ALIGN1 = "doxn";
@@ -1274,7 +1237,6 @@ int od_main(int argc, char **argv)
1274 address_pad_len_char = doxn_address_pad_len_char[pos]; 1237 address_pad_len_char = doxn_address_pad_len_char[pos];
1275 } 1238 }
1276 if (opt & OPT_N) { 1239 if (opt & OPT_N) {
1277 limit_bytes_to_format = 1;
1278 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm); 1240 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm);
1279 } 1241 }
1280 if (opt & OPT_a) decode_format_string("a"); 1242 if (opt & OPT_a) decode_format_string("a");
@@ -1287,28 +1249,23 @@ int od_main(int argc, char **argv)
1287 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm); 1249 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm);
1288 if (opt & OPT_l) decode_format_string("d4"); 1250 if (opt & OPT_l) decode_format_string("d4");
1289 if (opt & OPT_o) decode_format_string("o2"); 1251 if (opt & OPT_o) decode_format_string("o2");
1290 //if (opt & OPT_t)...
1291 while (lst_t) { 1252 while (lst_t) {
1292 decode_format_string(llist_pop(&lst_t)); 1253 decode_format_string(llist_pop(&lst_t));
1293 } 1254 }
1294 if (opt & OPT_v) verbose = 1;
1295 if (opt & OPT_x) decode_format_string("x2"); 1255 if (opt & OPT_x) decode_format_string("x2");
1296 if (opt & OPT_s) decode_format_string("d2"); 1256 if (opt & OPT_s) decode_format_string("d2");
1297 if (opt & OPT_S) { 1257 if (opt & OPT_S) {
1298 string_min = 3;
1299 string_min = xstrtou_sfx(str_S, 0, bkm); 1258 string_min = xstrtou_sfx(str_S, 0, bkm);
1300 flag_dump_strings = 1;
1301 } 1259 }
1302 //if (opt & OPT_w)...
1303 //if (opt & OPT_traditional)...
1304 1260
1305 if (flag_dump_strings && n_specs > 0) 1261 // Bloat:
1306 bb_error_msg_and_die("no type may be specified when dumping strings"); 1262 //if ((option_mask32 & OPT_S) && n_specs > 0)
1263 // bb_error_msg_and_die("no type may be specified when dumping strings");
1307 1264
1308 /* If the --traditional option is used, there may be from 1265 /* If the --traditional option is used, there may be from
1309 * 0 to 3 remaining command line arguments; handle each case 1266 * 0 to 3 remaining command line arguments; handle each case
1310 * separately. 1267 * separately.
1311 * od [file] [[+]offset[.][b] [[+]label[.][b]]] 1268 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
1312 * The offset and pseudo_start have the same syntax. 1269 * The offset and pseudo_start have the same syntax.
1313 * 1270 *
1314 * FIXME: POSIX 1003.1-2001 with XSI requires support for the 1271 * FIXME: POSIX 1003.1-2001 with XSI requires support for the
@@ -1316,93 +1273,91 @@ int od_main(int argc, char **argv)
1316 1273
1317#if ENABLE_LONG_OPTS 1274#if ENABLE_LONG_OPTS
1318 if (opt & OPT_traditional) { 1275 if (opt & OPT_traditional) {
1319 off_t o1, o2; 1276 if (argv[0]) {
1320 1277 off_t pseudo_start = -1;
1321 if (argc == 1) { 1278 off_t o1, o2;
1322 if (parse_old_offset(argv[0], &o1)) { 1279
1323 n_bytes_to_skip = o1; 1280 if (!argv[1]) { /* one arg */
1324 --argc; 1281 if (parse_old_offset(argv[0], &o1)) {
1325 ++argv; 1282 /* od --traditional OFFSET */
1326 } 1283 n_bytes_to_skip = o1;
1327 } else if (argc == 2) { 1284 argv++;
1328 if (parse_old_offset(argv[0], &o1) 1285 }
1329 && parse_old_offset(argv[1], &o2) 1286 /* od --traditional FILE */
1330 ) { 1287 } else if (!argv[2]) { /* two args */
1331 n_bytes_to_skip = o1; 1288 if (parse_old_offset(argv[0], &o1)
1332 flag_pseudo_start = 1; 1289 && parse_old_offset(argv[1], &o2)
1333 pseudo_start = o2; 1290 ) {
1334 argv += 2; 1291 /* od --traditional OFFSET LABEL */
1335 argc -= 2; 1292 n_bytes_to_skip = o1;
1336 } else if (parse_old_offset(argv[1], &o2)) { 1293 pseudo_start = o2;
1337 n_bytes_to_skip = o2; 1294 argv += 2;
1338 --argc; 1295 } else if (parse_old_offset(argv[1], &o2)) {
1339 argv[1] = argv[0]; 1296 /* od --traditional FILE OFFSET */
1340 ++argv; 1297 n_bytes_to_skip = o2;
1341 } else { 1298 argv[1] = NULL;
1342 bb_error_msg_and_die("invalid second operand " 1299 } else {
1343 "in compatibility mode '%s'", argv[1]); 1300 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1344 } 1301 }
1345 } else if (argc == 3) { 1302 } else if (!argv[3]) { /* three args */
1346 if (parse_old_offset(argv[1], &o1) 1303 if (parse_old_offset(argv[1], &o1)
1347 && parse_old_offset(argv[2], &o2) 1304 && parse_old_offset(argv[2], &o2)
1348 ) { 1305 ) {
1349 n_bytes_to_skip = o1; 1306 /* od --traditional FILE OFFSET LABEL */
1350 flag_pseudo_start = 1; 1307 n_bytes_to_skip = o1;
1351 pseudo_start = o2; 1308 pseudo_start = o2;
1352 argv[2] = argv[0]; 1309 argv[1] = NULL;
1353 argv += 2; 1310 } else {
1354 argc -= 2; 1311 bb_error_msg_and_die("the last two arguments must be offsets");
1355 } else { 1312 }
1356 bb_error_msg_and_die("in compatibility mode " 1313 } else { /* >3 args */
1357 "the last two arguments must be offsets"); 1314 bb_error_msg_and_die("too many arguments");
1358 } 1315 }
1359 } else if (argc > 3) {
1360 bb_error_msg_and_die("compatibility mode supports "
1361 "at most three arguments");
1362 }
1363 1316
1364 if (flag_pseudo_start) { 1317 if (pseudo_start >= 0) {
1365 if (format_address == format_address_none) { 1318 if (format_address == format_address_none) {
1366 address_base_char = 'o'; 1319 address_base_char = 'o';
1367 address_pad_len_char = '7'; 1320 address_pad_len_char = '7';
1368 format_address = format_address_paren; 1321 format_address = format_address_paren;
1369 } else 1322 } else {
1370 format_address = format_address_label; 1323 format_address = format_address_label;
1324 }
1325 pseudo_offset = pseudo_start - n_bytes_to_skip;
1326 }
1371 } 1327 }
1328 /* else: od --traditional (without args) */
1372 } 1329 }
1373#endif 1330#endif
1374 1331
1375 if (limit_bytes_to_format) { 1332 if (option_mask32 & OPT_N) {
1376 end_offset = n_bytes_to_skip + max_bytes_to_format; 1333 end_offset = n_bytes_to_skip + max_bytes_to_format;
1377 if (end_offset < n_bytes_to_skip) 1334 if (end_offset < n_bytes_to_skip)
1378 bb_error_msg_and_die("skip-bytes + read-bytes is too large"); 1335 bb_error_msg_and_die("SKIP + SIZE is too large");
1379 } 1336 }
1380 1337
1381 if (n_specs == 0) { 1338 if (n_specs == 0) {
1382 decode_format_string("o2"); 1339 decode_format_string("o2");
1383 n_specs = 1; 1340 /*n_specs = 1; - done by decode_format_string */
1384 } 1341 }
1385 1342
1386 /* If no files were listed on the command line, 1343 /* If no files were listed on the command line,
1387 set the global pointer FILE_LIST so that it 1344 set the global pointer FILE_LIST so that it
1388 references the null-terminated list of one name: "-". */ 1345 references the null-terminated list of one name: "-". */
1389 file_list = bb_argv_dash; 1346 file_list = bb_argv_dash;
1390 if (argc > 0) { 1347 if (argv[0]) {
1391 /* Set the global pointer FILE_LIST so that it 1348 /* Set the global pointer FILE_LIST so that it
1392 references the first file-argument on the command-line. */ 1349 references the first file-argument on the command-line. */
1393 file_list = (char const *const *) argv; 1350 file_list = (char const *const *) argv;
1394 } 1351 }
1395 1352
1396 /* open the first input file */ 1353 /* Open the first input file */
1397 open_next_file(); 1354 open_next_file();
1398 /* skip over any unwanted header bytes */ 1355 /* Skip over any unwanted header bytes */
1399 skip(n_bytes_to_skip); 1356 skip(n_bytes_to_skip);
1400 if (!in_stream) 1357 if (!in_stream)
1401 return EXIT_FAILURE; 1358 return EXIT_FAILURE;
1402 1359
1403 pseudo_offset = (flag_pseudo_start ? pseudo_start - n_bytes_to_skip : 0); 1360 /* Compute output block length */
1404
1405 /* Compute output block length. */
1406 l_c_m = get_lcm(); 1361 l_c_m = get_lcm();
1407 1362
1408 if (opt & OPT_w) { /* -w: width */ 1363 if (opt & OPT_w) { /* -w: width */
@@ -1424,13 +1379,13 @@ int od_main(int argc, char **argv)
1424 } 1379 }
1425#endif 1380#endif
1426 1381
1427 if (flag_dump_strings) 1382 if (option_mask32 & OPT_S)
1428 dump_strings(n_bytes_to_skip, end_offset); 1383 dump_strings(n_bytes_to_skip, end_offset);
1429 else 1384 else
1430 dump(n_bytes_to_skip, end_offset); 1385 dump(n_bytes_to_skip, end_offset);
1431 1386
1432 if (fclose(stdin) == EOF) 1387 if (fclose(stdin))
1433 bb_perror_msg_and_die(bb_msg_standard_input); 1388 bb_perror_msg_and_die(bb_msg_standard_input);
1434 1389
1435 return ioerror; 1390 return exit_code;
1436} 1391}