od: get rid of (almost all) statics

function                                             old     new   delta
od_main                                             2565    2600     +35
check_and_close                                      113     115      +2
static.prev_pair_equal                                 1       -      -1
static.first                                           1       -      -1
exit_code                                              1       -      -1
string_min                                             4       -      -4
n_specs                                                4       -      -4
in_stream                                              4       -      -4
format_address                                         4       -      -4
file_list                                              4       -      -4
bytes_per_block                                        4       -      -4
get_lcm                                              120     115      -5
pseudo_offset                                          8       -      -8
------------------------------------------------------------------------------
(add/remove: 0/10 grow/shrink: 2/1 up/down: 37/-40)            Total: -3 bytes
   text	   data	    bss	    dec	    hex	filename
 938487	    932	  17392	 956811	  e998b	busybox_old
 938519	    924	  17360	 956803	  e9983	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko
2015-10-19 02:51:56 +02:00
parent c4fb8c6ad5
commit f3d58a29be

View File

@ -66,7 +66,7 @@ enum {
/* -S was -s and also had optional parameter */ \ /* -S was -s and also had optional parameter */ \
/* 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, &G.bytes_per_block)
/* Check for 0x7f is a coreutils 6.3 addition */ /* Check for 0x7f is a coreutils 6.3 addition */
@ -174,38 +174,52 @@ struct ERR_width_bytes_has_bad_size {
char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1]; char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
}; };
static smallint exit_code; struct globals {
smallint exit_code;
static unsigned string_min; unsigned string_min;
/* An array of specs describing how to format each input block. */ /* An array of specs describing how to format each input block. */
static size_t n_specs; unsigned n_specs;
static struct tspec *spec; struct tspec *spec;
/* Function that accepts an address and an optional following char, /* Function that accepts an address and an optional following char,
and prints the address and char to stdout. */ and prints the address and char to stdout. */
static void (*format_address)(off_t, char); void (*format_address)(off_t, char);
/* The difference between the old-style pseudo starting address and
the number of bytes to skip. */ /* The difference between the old-style pseudo starting address and
the number of bytes to skip. */
#if ENABLE_LONG_OPTS #if ENABLE_LONG_OPTS
static off_t pseudo_offset; off_t pseudo_offset;
#else # define G_pseudo_offset G.pseudo_offset
enum { pseudo_offset = 0 };
#endif #endif
/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
input is formatted. */ input is formatted. */
/* The number of input bytes formatted per output line. It must be /* The number of input bytes formatted per output line. It must be
a multiple of the least common multiple of the sizes associated with a multiple of the least common multiple of the sizes associated with
the specified output types. It should be as large as possible, but the specified output types. It should be as large as possible, but
no larger than 16 -- unless specified with the -w option. */ no larger than 16 -- unless specified with the -w option. */
static unsigned bytes_per_block = 32; /* have to use unsigned, not size_t */ unsigned bytes_per_block; /* have to use unsigned, not size_t */
/* A NULL-terminated list of the file-arguments from the command line. */ /* A NULL-terminated list of the file-arguments from the command line. */
static const char *const *file_list; const char *const *file_list;
/* The input stream associated with the current file. */
FILE *in_stream;
bool not_first;
bool prev_pair_equal;
} FIX_ALIASING;
#if !ENABLE_LONG_OPTS
enum { G_pseudo_offset = 0 };
#endif
#define G (*(struct globals*)&bb_common_bufsiz1)
#define INIT_G() do { \
BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
G.bytes_per_block = 32; \
} while (0)
/* The input stream associated with the current file. */
static FILE *in_stream;
#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t) #define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = { static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
@ -476,17 +490,17 @@ static void
open_next_file(void) open_next_file(void)
{ {
while (1) { while (1) {
if (!*file_list) if (!*G.file_list)
return; return;
in_stream = fopen_or_warn_stdin(*file_list++); G.in_stream = fopen_or_warn_stdin(*G.file_list++);
if (in_stream) { if (G.in_stream) {
break; break;
} }
exit_code = 1; G.exit_code = 1;
} }
if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N) if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
setbuf(in_stream, NULL); setbuf(G.in_stream, NULL);
} }
/* Test whether there have been errors on in_stream, and close it if /* Test whether there have been errors on in_stream, and close it if
@ -499,16 +513,16 @@ open_next_file(void)
static void static void
check_and_close(void) check_and_close(void)
{ {
if (in_stream) { if (G.in_stream) {
if (ferror(in_stream)) { if (ferror(G.in_stream)) {
bb_error_msg("%s: read error", (in_stream == stdin) bb_error_msg("%s: read error", (G.in_stream == stdin)
? bb_msg_standard_input ? bb_msg_standard_input
: file_list[-1] : G.file_list[-1]
); );
exit_code = 1; G.exit_code = 1;
} }
fclose_if_not_stdin(in_stream); fclose_if_not_stdin(G.in_stream);
in_stream = NULL; G.in_stream = NULL;
} }
if (ferror(stdout)) { if (ferror(stdout)) {
@ -744,9 +758,9 @@ decode_format_string(const char *s)
assert(s != next); assert(s != next);
s = next; s = next;
spec = xrealloc_vector(spec, 4, n_specs); G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
memcpy(&spec[n_specs], &tspec, sizeof(spec[0])); memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
n_specs++; G.n_specs++;
} }
} }
@ -763,7 +777,7 @@ skip(off_t n_skip)
if (n_skip == 0) if (n_skip == 0)
return; return;
while (in_stream) { /* !EOF */ while (G.in_stream) { /* !EOF */
struct stat file_stats; struct stat file_stats;
/* First try seeking. For large offsets, this extra work is /* First try seeking. For large offsets, this extra work is
@ -781,15 +795,15 @@ skip(off_t n_skip)
If the number of bytes left to skip is at least If the number of bytes left to skip is at least
as large as the size of the current file, we can as large as the size of the current file, we can
decrement n_skip and go on to the next file. */ decrement n_skip and go on to the next file. */
if (fstat(fileno(in_stream), &file_stats) == 0 if (fstat(fileno(G.in_stream), &file_stats) == 0
&& S_ISREG(file_stats.st_mode) && file_stats.st_size > 0 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
) { ) {
if (file_stats.st_size < n_skip) { if (file_stats.st_size < n_skip) {
n_skip -= file_stats.st_size; n_skip -= file_stats.st_size;
/* take "check & close / open_next" route */ /* take "check & close / open_next" route */
} else { } else {
if (fseeko(in_stream, n_skip, SEEK_CUR) != 0) if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
exit_code = 1; G.exit_code = 1;
return; return;
} }
} else { } else {
@ -802,7 +816,7 @@ skip(off_t n_skip)
while (n_skip > 0) { while (n_skip > 0) {
if (n_skip < n_bytes_to_read) if (n_skip < n_bytes_to_read)
n_bytes_to_read = n_skip; n_bytes_to_read = n_skip;
n_bytes_read = fread(buf, 1, n_bytes_to_read, in_stream); n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
n_skip -= n_bytes_read; n_skip -= n_bytes_read;
if (n_bytes_read != n_bytes_to_read) if (n_bytes_read != n_bytes_to_read)
break; /* EOF on this file or error */ break; /* EOF on this file or error */
@ -855,7 +869,7 @@ static void
format_address_label(off_t address, char c) format_address_label(off_t address, char c)
{ {
format_address_std(address, ' '); format_address_std(address, ' ');
format_address_paren(address + pseudo_offset, c); format_address_paren(address + G_pseudo_offset, c);
} }
#endif #endif
@ -886,36 +900,34 @@ static void
write_block(off_t current_offset, size_t n_bytes, write_block(off_t current_offset, size_t n_bytes,
const char *prev_block, const char *curr_block) const char *prev_block, const char *curr_block)
{ {
static char first = 1; unsigned i;
static char prev_pair_equal = 0;
size_t i;
if (!(option_mask32 & OPT_v) if (!(option_mask32 & OPT_v)
&& !first && G.not_first
&& n_bytes == bytes_per_block && n_bytes == G.bytes_per_block
&& memcmp(prev_block, curr_block, bytes_per_block) == 0 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
) { ) {
if (prev_pair_equal) { if (G.prev_pair_equal) {
/* The two preceding blocks were equal, and the current /* The two preceding blocks were equal, and the current
block is the same as the last one, so print nothing. */ block is the same as the last one, so print nothing. */
} else { } else {
puts("*"); puts("*");
prev_pair_equal = 1; G.prev_pair_equal = 1;
} }
} else { } else {
first = 0; G.not_first = 1;
prev_pair_equal = 0; G.prev_pair_equal = 0;
for (i = 0; i < n_specs; i++) { for (i = 0; i < G.n_specs; i++) {
if (i == 0) if (i == 0)
format_address(current_offset, '\0'); G.format_address(current_offset, '\0');
else else
printf("%*s", address_pad_len_char - '0', ""); printf("%*s", address_pad_len_char - '0', "");
(*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string); (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
if (spec[i].hexl_mode_trailer) { if (G.spec[i].hexl_mode_trailer) {
/* space-pad out to full line width, then dump the trailer */ /* space-pad out to full line width, then dump the trailer */
unsigned datum_width = width_bytes[spec[i].size]; unsigned datum_width = width_bytes[G.spec[i].size];
unsigned blank_fields = (bytes_per_block - n_bytes) / datum_width; unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
unsigned field_width = spec[i].field_width + 1; unsigned field_width = G.spec[i].field_width + 1;
printf("%*s", blank_fields * field_width, ""); printf("%*s", blank_fields * field_width, "");
dump_hexl_mode_trailer(n_bytes, curr_block); dump_hexl_mode_trailer(n_bytes, curr_block);
} }
@ -927,19 +939,19 @@ write_block(off_t current_offset, size_t n_bytes,
static void static void
read_block(size_t n, char *block, size_t *n_bytes_in_buffer) read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
{ {
assert(0 < n && n <= bytes_per_block); assert(0 < n && n <= G.bytes_per_block);
*n_bytes_in_buffer = 0; *n_bytes_in_buffer = 0;
if (n == 0) if (n == 0)
return; return;
while (in_stream != NULL) { /* EOF. */ while (G.in_stream != NULL) { /* EOF. */
size_t n_needed; size_t n_needed;
size_t n_read; size_t n_read;
n_needed = n - *n_bytes_in_buffer; n_needed = n - *n_bytes_in_buffer;
n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, in_stream); n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
*n_bytes_in_buffer += n_read; *n_bytes_in_buffer += n_read;
if (n_read == n_needed) if (n_read == n_needed)
break; break;
@ -958,8 +970,8 @@ get_lcm(void)
size_t i; size_t i;
int l_c_m = 1; int l_c_m = 1;
for (i = 0; i < n_specs; i++) for (i = 0; i < G.n_specs; i++)
l_c_m = lcm(l_c_m, width_bytes[(int) spec[i].size]); l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
return l_c_m; return l_c_m;
} }
@ -980,8 +992,8 @@ dump(off_t current_offset, off_t end_offset)
int idx; int idx;
size_t n_bytes_read; size_t n_bytes_read;
block[0] = xmalloc(2 * bytes_per_block); block[0] = xmalloc(2 * G.bytes_per_block);
block[1] = block[0] + bytes_per_block; block[1] = block[0] + G.bytes_per_block;
idx = 0; idx = 0;
if (option_mask32 & OPT_N) { if (option_mask32 & OPT_N) {
@ -991,21 +1003,21 @@ dump(off_t current_offset, off_t end_offset)
n_bytes_read = 0; n_bytes_read = 0;
break; break;
} }
n_needed = MIN(end_offset - current_offset, (off_t) bytes_per_block); n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
read_block(n_needed, block[idx], &n_bytes_read); read_block(n_needed, block[idx], &n_bytes_read);
if (n_bytes_read < bytes_per_block) if (n_bytes_read < G.bytes_per_block)
break; break;
assert(n_bytes_read == bytes_per_block); assert(n_bytes_read == G.bytes_per_block);
write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
current_offset += n_bytes_read; current_offset += n_bytes_read;
idx ^= 1; idx ^= 1;
} }
} else { } else {
while (1) { while (1) {
read_block(bytes_per_block, block[idx], &n_bytes_read); read_block(G.bytes_per_block, block[idx], &n_bytes_read);
if (n_bytes_read < bytes_per_block) if (n_bytes_read < G.bytes_per_block)
break; break;
assert(n_bytes_read == bytes_per_block); assert(n_bytes_read == G.bytes_per_block);
write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
current_offset += n_bytes_read; current_offset += n_bytes_read;
idx ^= 1; idx ^= 1;
@ -1028,7 +1040,7 @@ dump(off_t current_offset, off_t end_offset)
current_offset += n_bytes_read; current_offset += n_bytes_read;
} }
format_address(current_offset, '\n'); G.format_address(current_offset, '\n');
if ((option_mask32 & OPT_N) && current_offset >= end_offset) if ((option_mask32 & OPT_N) && current_offset >= end_offset)
check_and_close(); check_and_close();
@ -1059,16 +1071,16 @@ dump(off_t current_offset, off_t end_offset)
static void static void
dump_strings(off_t address, off_t end_offset) dump_strings(off_t address, off_t end_offset)
{ {
unsigned bufsize = MAX(100, string_min); unsigned bufsize = MAX(100, G.string_min);
unsigned char *buf = xmalloc(bufsize); unsigned char *buf = xmalloc(bufsize);
while (1) { while (1) {
size_t i; size_t i;
int c; int c;
/* See if the next 'string_min' chars are all printing chars. */ /* See if the next 'G.string_min' chars are all printing chars. */
tryline: tryline:
if ((option_mask32 & OPT_N) && (end_offset - string_min <= address)) if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
break; break;
i = 0; i = 0;
while (!(option_mask32 & OPT_N) || address < end_offset) { while (!(option_mask32 & OPT_N) || address < end_offset) {
@ -1077,8 +1089,8 @@ dump_strings(off_t address, off_t end_offset)
buf = xrealloc(buf, bufsize); buf = xrealloc(buf, bufsize);
} }
while (in_stream) { /* !EOF */ while (G.in_stream) { /* !EOF */
c = fgetc(in_stream); c = fgetc(G.in_stream);
if (c != EOF) if (c != EOF)
goto got_char; goto got_char;
check_and_close(); check_and_close();
@ -1095,12 +1107,12 @@ dump_strings(off_t address, off_t end_offset)
buf[i++] = c; /* String continues; store it all. */ buf[i++] = c; /* String continues; store it all. */
} }
if (i < string_min) /* Too short! */ if (i < G.string_min) /* Too short! */
goto tryline; goto tryline;
/* If we get here, the string is all printable and NUL-terminated */ /* If we get here, the string is all printable and NUL-terminated */
buf[i] = 0; buf[i] = 0;
format_address(address - i - 1, ' '); G.format_address(address - i - 1, ' ');
for (i = 0; (c = buf[i]); i++) { for (i = 0; (c = buf[i]); i++) {
switch (c) { switch (c) {
@ -1118,7 +1130,7 @@ dump_strings(off_t address, off_t end_offset)
} }
/* We reach this point only if we search through /* We reach this point only if we search through
(max_bytes_to_format - string_min) bytes before reaching EOF. */ (max_bytes_to_format - G.string_min) bytes before reaching EOF. */
check_and_close(); check_and_close();
ret: ret:
free(buf); free(buf);
@ -1190,8 +1202,10 @@ int od_main(int argc UNUSED_PARAM, char **argv)
/* The maximum number of bytes that will be formatted. */ /* The maximum number of bytes that will be formatted. */
off_t max_bytes_to_format = 0; off_t max_bytes_to_format = 0;
spec = NULL; INIT_G();
format_address = format_address_std;
/*G.spec = NULL; - already is */
G.format_address = format_address_std;
address_base_char = 'o'; address_base_char = 'o';
address_pad_len_char = '7'; address_pad_len_char = '7';
@ -1217,7 +1231,7 @@ int od_main(int argc UNUSED_PARAM, char **argv)
bb_error_msg_and_die("bad output address radix " bb_error_msg_and_die("bad output address radix "
"'%c' (must be [doxn])", str_A[0]); "'%c' (must be [doxn])", str_A[0]);
pos = p - doxn; pos = p - doxn;
if (pos == 3) format_address = format_address_none; if (pos == 3) G.format_address = format_address_none;
address_base_char = doxn_address_base_char[pos]; address_base_char = doxn_address_base_char[pos];
address_pad_len_char = doxn_address_pad_len_char[pos]; address_pad_len_char = doxn_address_pad_len_char[pos];
} }
@ -1240,11 +1254,11 @@ int od_main(int argc UNUSED_PARAM, 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 = xstrtou_sfx(str_S, 0, bkm_suffixes); G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
} }
// Bloat: // Bloat:
//if ((option_mask32 & OPT_S) && n_specs > 0) //if ((option_mask32 & OPT_S) && G.n_specs > 0)
// bb_error_msg_and_die("no type may be specified when dumping strings"); // bb_error_msg_and_die("no type may be specified when dumping strings");
/* If the --traditional option is used, there may be from /* If the --traditional option is used, there may be from
@ -1300,14 +1314,14 @@ int od_main(int argc UNUSED_PARAM, char **argv)
} }
if (pseudo_start >= 0) { if (pseudo_start >= 0) {
if (format_address == format_address_none) { if (G.format_address == format_address_none) {
address_base_char = 'o'; address_base_char = 'o';
address_pad_len_char = '7'; address_pad_len_char = '7';
format_address = format_address_paren; G.format_address = format_address_paren;
} else { } else {
format_address = format_address_label; G.format_address = format_address_label;
} }
pseudo_offset = pseudo_start - n_bytes_to_skip; G_pseudo_offset = pseudo_start - n_bytes_to_skip;
} }
} }
/* else: od --traditional (without args) */ /* else: od --traditional (without args) */
@ -1320,45 +1334,45 @@ int od_main(int argc UNUSED_PARAM, char **argv)
bb_error_msg_and_die("SKIP + SIZE is too large"); bb_error_msg_and_die("SKIP + SIZE is too large");
} }
if (n_specs == 0) { if (G.n_specs == 0) {
decode_format_string("o2"); decode_format_string("o2");
/*n_specs = 1; - done by decode_format_string */ /*G.n_specs = 1; - done by decode_format_string */
} }
/* If no files were listed on the command line, /* If no files were listed on the command line,
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; G.file_list = bb_argv_dash;
if (argv[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; G.file_list = (char const *const *) argv;
} }
/* Open the first input file */ /* Open the first input file */
open_next_file(); open_next_file();
/* Skip over any unwanted header bytes */ /* Skip over any unwanted header bytes */
skip(n_bytes_to_skip); skip(n_bytes_to_skip);
if (!in_stream) if (!G.in_stream)
return EXIT_FAILURE; return EXIT_FAILURE;
/* Compute output block length */ /* Compute output block length */
l_c_m = get_lcm(); l_c_m = get_lcm();
if (opt & OPT_w) { /* -w: width */ if (opt & OPT_w) { /* -w: width */
if (!bytes_per_block || bytes_per_block % l_c_m != 0) { if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) {
bb_error_msg("warning: invalid width %u; using %d instead", bb_error_msg("warning: invalid width %u; using %d instead",
(unsigned)bytes_per_block, l_c_m); (unsigned)G.bytes_per_block, l_c_m);
bytes_per_block = l_c_m; G.bytes_per_block = l_c_m;
} }
} else { } else {
bytes_per_block = l_c_m; G.bytes_per_block = l_c_m;
if (l_c_m < DEFAULT_BYTES_PER_BLOCK) if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m; G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
} }
#ifdef DEBUG #ifdef DEBUG
for (i = 0; i < n_specs; i++) { for (i = 0; i < G.n_specs; i++) {
printf("%d: fmt=\"%s\" width=%d\n", printf("%d: fmt=\"%s\" width=%d\n",
i, spec[i].fmt_string, width_bytes[spec[i].size]); i, spec[i].fmt_string, width_bytes[spec[i].size]);
} }
@ -1372,5 +1386,5 @@ int od_main(int argc UNUSED_PARAM, char **argv)
if (fclose(stdin)) if (fclose(stdin))
bb_perror_msg_and_die(bb_msg_standard_input); bb_perror_msg_and_die(bb_msg_standard_input);
return exit_code; return G.exit_code;
} }