od: code shrink, fix "od --traditional FILE"

function                                             old     new   delta
parse_old_offset                                     107     125     +18
packed_usage                                       28715   28691     -24
od_main                                             2312    2275     -37

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2011-05-21 17:43:06 +02:00
parent 232ebaa568
commit 5c10fa5c24
3 changed files with 121 additions and 121 deletions

View File

@ -11,11 +11,12 @@
* Original copyright notice is retained at the end of this file. * Original copyright notice is retained at the end of this file.
*/ */
//usage:#if !ENABLE_DESKTOP
//usage:#define od_trivial_usage //usage:#define od_trivial_usage
//usage: "[-aBbcDdeFfHhIiLlOovXx] " IF_DESKTOP("[-t TYPE] ") "[FILE]" //usage: "[-aBbcDdeFfHhIiLlOovXx] [FILE]"
//usage:#define od_full_usage "\n\n" //usage:#define od_full_usage "\n\n"
//usage: "Write an unambiguous representation, octal bytes by default, of FILE\n" //usage: "Print FILE (or stdin) unambiguously, as octal bytes by default"
//usage: "(or stdin) to stdout" //usage:#endif
#include "libbb.h" #include "libbb.h"
#if ENABLE_DESKTOP #if ENABLE_DESKTOP

View File

@ -13,43 +13,24 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Written by Jim Meyering. */ /* Written by Jim Meyering. */
/* Busyboxed by Denys Vlasenko, based on od.c from coreutils-5.2.1 */
/* Busyboxed by Denys Vlasenko //usage:#if ENABLE_DESKTOP
//usage:#define od_trivial_usage
//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE...]"
// We don't support:
// ... [FILE] [[+]OFFSET[.][b]]
// Support is buggy for:
// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]]
Based on od.c from coreutils-5.2.1 //usage:#define od_full_usage "\n\n"
Top bloat sources: //usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default"
//usage:#endif
00000073 t parse_old_offset /* #include "libbb.h" - done in od.c */
0000007b t get_lcm
00000090 r long_options
00000092 t print_named_ascii
000000bf t print_ascii
00000168 t write_block
00000366 t decode_format_string
00000a71 T od_main
Tested for compat with coreutils 6.3
using this script. Minor differences fixed.
#!/bin/sh
echo STD
time /path/to/coreutils/od \
...params... \
>std
echo Exit code $?
echo BBOX
time ./busybox od \
...params... \
>bbox
echo Exit code $?
diff -u -a std bbox >bbox.diff || { echo Different!; sleep 1; }
*/
#include "libbb.h"
#define assert(a) ((void)0) #define assert(a) ((void)0)
@ -214,7 +195,7 @@ static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1
#define MAX_FP_TYPE_SIZE sizeof(longdouble_t) #define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = { static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
/* gcc seems to allow repeated indexes. Last one stays */ /* gcc seems to allow repeated indexes. Last one wins */
[sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE, [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
[sizeof(double)] = FLOAT_DOUBLE, [sizeof(double)] = FLOAT_DOUBLE,
[sizeof(float)] = FLOAT_SINGLE [sizeof(float)] = FLOAT_SINGLE
@ -376,7 +357,7 @@ print_named_ascii(size_t n_bytes, const char *block,
}; };
// buf[N] pos: 01234 56789 // buf[N] pos: 01234 56789
char buf[12] = " x\0 0xx\0"; char buf[12] = " x\0 0xx\0";
// actually " x\0 xxx\0", but I want to share the string with below. // actually " x\0 xxx\0", but want to share string with print_ascii.
// [12] because we take three 32bit stack slots anyway, and // [12] because we take three 32bit stack slots anyway, and
// gcc is too dumb to initialize with constant stores, // gcc is too dumb to initialize with constant stores,
// it copies initializer from rodata. Oh well. // it copies initializer from rodata. Oh well.
@ -954,42 +935,6 @@ get_lcm(void)
return l_c_m; return l_c_m;
} }
#if ENABLE_LONG_OPTS
/* If S is a valid traditional offset specification with an optional
leading '+' return nonzero and set *OFFSET to the offset it denotes. */
static int
parse_old_offset(const char *s, off_t *offset)
{
static const struct suffix_mult Bb[] = {
{ "B", 1024 },
{ "b", 512 },
{ "", 0 }
};
char *p;
int radix;
/* Skip over any leading '+'. */
if (s[0] == '+') ++s;
/* Determine the radix we'll use to interpret S. If there is a '.',
* it's decimal, otherwise, if the string begins with '0X'or '0x',
* it's hexadecimal, else octal. */
p = strchr(s, '.');
radix = 8;
if (p) {
p[0] = '\0'; /* cheating */
radix = 10;
} else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
radix = 16;
*offset = xstrtooff_sfx(s, radix, Bb);
if (p) p[0] = '.';
return (*offset >= 0);
}
#endif
/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the /* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
formatted block to standard output, and repeat until the specified formatted block to standard output, and repeat until the specified
maximum number of bytes has been read or until all input has been maximum number of bytes has been read or until all input has been
@ -1172,8 +1117,45 @@ dump_strings(off_t address, off_t end_offset)
check_and_close(); check_and_close();
} }
#if ENABLE_LONG_OPTS
/* If S is a valid traditional offset specification with an optional
leading '+' return nonzero and set *OFFSET to the offset it denotes. */
static int
parse_old_offset(const char *s, off_t *offset)
{
static const struct suffix_mult Bb[] = {
{ "B", 1024 },
{ "b", 512 },
{ "", 0 }
};
char *p;
int radix;
/* Skip over any leading '+'. */
if (s[0] == '+') ++s;
if (!isdigit(s[0])) return 0; /* not a number */
/* Determine the radix we'll use to interpret S. If there is a '.',
* it's decimal, otherwise, if the string begins with '0X'or '0x',
* it's hexadecimal, else octal. */
p = strchr(s, '.');
radix = 8;
if (p) {
p[0] = '\0'; /* cheating */
radix = 10;
} else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
radix = 16;
*offset = xstrtooff_sfx(s, radix, Bb);
if (p) p[0] = '.';
return (*offset >= 0);
}
#endif
int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int od_main(int argc, char **argv) int od_main(int argc UNUSED_PARAM, char **argv)
{ {
static const struct suffix_mult bkm[] = { static const struct suffix_mult bkm[] = {
{ "b", 512 }, { "b", 512 },
@ -1245,7 +1227,6 @@ int od_main(int argc, char **argv)
// but in coreutils 6.3 it was renamed and now has // but in coreutils 6.3 it was renamed and now has
// _mandatory_ parameter // _mandatory_ parameter
&str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block); &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block);
argc -= optind;
argv += optind; argv += optind;
if (opt & OPT_A) { if (opt & OPT_A) {
static const char doxn[] ALIGN1 = "doxn"; static const char doxn[] ALIGN1 = "doxn";
@ -1288,7 +1269,6 @@ int od_main(int argc, char **argv)
if (opt & OPT_x) decode_format_string("x2"); if (opt & OPT_x) decode_format_string("x2");
if (opt & OPT_s) decode_format_string("d2"); if (opt & OPT_s) decode_format_string("d2");
if (opt & OPT_S) { if (opt & OPT_S) {
string_min = 3;
string_min = xstrtou_sfx(str_S, 0, bkm); string_min = xstrtou_sfx(str_S, 0, bkm);
flag_dump_strings = 1; flag_dump_strings = 1;
} }
@ -1301,7 +1281,7 @@ int od_main(int argc, char **argv)
/* If the --traditional option is used, there may be from /* If the --traditional option is used, there may be from
* 0 to 3 remaining command line arguments; handle each case * 0 to 3 remaining command line arguments; handle each case
* separately. * separately.
* od [file] [[+]offset[.][b] [[+]label[.][b]]] * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
* The offset and pseudo_start have the same syntax. * The offset and pseudo_start have the same syntax.
* *
* FIXME: POSIX 1003.1-2001 with XSI requires support for the * FIXME: POSIX 1003.1-2001 with XSI requires support for the
@ -1311,48 +1291,47 @@ int od_main(int argc, char **argv)
if (opt & OPT_traditional) { if (opt & OPT_traditional) {
off_t o1, o2; off_t o1, o2;
if (argc == 1) { if (argv[0]) {
if (parse_old_offset(argv[0], &o1)) { if (!argv[1]) { /* one arg */
n_bytes_to_skip = o1; if (parse_old_offset(argv[0], &o1)) {
--argc; /* od --traditional OFFSET */
++argv; n_bytes_to_skip = o1;
argv++;
}
/* od --traditional FILE */
} else if (!argv[2]) { /* two args */
if (parse_old_offset(argv[0], &o1)
&& parse_old_offset(argv[1], &o2)
) {
/* od --traditional OFFSET LABEL */
n_bytes_to_skip = o1;
flag_pseudo_start = 1;
pseudo_start = o2;
argv += 2;
} else if (parse_old_offset(argv[1], &o2)) {
/* od --traditional FILE OFFSET */
n_bytes_to_skip = o2;
argv[1] = NULL;
} else {
bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
}
} else if (!argv[3]) { /* three args */
if (parse_old_offset(argv[1], &o1)
&& parse_old_offset(argv[2], &o2)
) {
/* od --traditional FILE OFFSET LABEL */
n_bytes_to_skip = o1;
flag_pseudo_start = 1;
pseudo_start = o2;
argv[1] = NULL;
} else {
bb_error_msg_and_die("the last two arguments must be offsets");
}
} else { /* >3 args */
bb_error_msg_and_die("too many arguments");
} }
} else if (argc == 2) {
if (parse_old_offset(argv[0], &o1)
&& parse_old_offset(argv[1], &o2)
) {
n_bytes_to_skip = o1;
flag_pseudo_start = 1;
pseudo_start = o2;
argv += 2;
argc -= 2;
} else if (parse_old_offset(argv[1], &o2)) {
n_bytes_to_skip = o2;
--argc;
argv[1] = argv[0];
++argv;
} else {
bb_error_msg_and_die("invalid second operand "
"in compatibility mode '%s'", argv[1]);
}
} else if (argc == 3) {
if (parse_old_offset(argv[1], &o1)
&& parse_old_offset(argv[2], &o2)
) {
n_bytes_to_skip = o1;
flag_pseudo_start = 1;
pseudo_start = o2;
argv[2] = argv[0];
argv += 2;
argc -= 2;
} else {
bb_error_msg_and_die("in compatibility mode "
"the last two arguments must be offsets");
}
} else if (argc > 3) {
bb_error_msg_and_die("compatibility mode supports "
"at most three arguments");
} }
/* else: od --traditional (without args) */
if (flag_pseudo_start) { if (flag_pseudo_start) {
if (format_address == format_address_none) { if (format_address == format_address_none) {
@ -1368,7 +1347,7 @@ int od_main(int argc, char **argv)
if (limit_bytes_to_format) { if (limit_bytes_to_format) {
end_offset = n_bytes_to_skip + max_bytes_to_format; end_offset = n_bytes_to_skip + max_bytes_to_format;
if (end_offset < n_bytes_to_skip) if (end_offset < n_bytes_to_skip)
bb_error_msg_and_die("skip-bytes + read-bytes is too large"); bb_error_msg_and_die("SKIP + SIZE is too large");
} }
if (n_specs == 0) { if (n_specs == 0) {
@ -1380,7 +1359,7 @@ int od_main(int argc, char **argv)
set the global pointer FILE_LIST so that it set the global pointer FILE_LIST so that it
references the null-terminated list of one name: "-". */ references the null-terminated list of one name: "-". */
file_list = bb_argv_dash; file_list = bb_argv_dash;
if (argc > 0) { if (argv[0]) {
/* Set the global pointer FILE_LIST so that it /* Set the global pointer FILE_LIST so that it
references the first file-argument on the command-line. */ references the first file-argument on the command-line. */
file_list = (char const *const *) argv; file_list = (char const *const *) argv;

View File

@ -4,7 +4,7 @@
. ./testing.sh . ./testing.sh
# testing "test name" "options" "expected result" "file input" "stdin" # testing "test name" "commands" "expected result" "file input" "stdin"
optional DESKTOP optional DESKTOP
testing "od -b" \ testing "od -b" \
@ -16,4 +16,24 @@ testing "od -b" \
"" "HELLO" "" "HELLO"
SKIP= SKIP=
optional DESKTOP
testing "od -b --traditional" \
"od -b --traditional" \
"\
0000000 110 105 114 114 117
0000005
" \
"" "HELLO"
SKIP=
optional DESKTOP
testing "od -b --traditional FILE" \
"od -b --traditional input" \
"\
0000000 110 105 114 114 117
0000005
" \
"HELLO" ""
SKIP=
exit $FAILCOUNT exit $FAILCOUNT