diff options
-rw-r--r-- | coreutils/od_bloaty.c | 230 |
1 files changed, 122 insertions, 108 deletions
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index ab7ea997d..f47f84b54 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c @@ -66,7 +66,7 @@ enum { /* -S was -s and also had optional parameter */ \ /* but in coreutils 6.3 it was renamed and now has */ \ /* _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 */ @@ -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]; }; -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. */ -static size_t n_specs; -static struct tspec *spec; + /* An array of specs describing how to format each input block. */ + unsigned n_specs; + struct tspec *spec; -/* Function that accepts an address and an optional following char, - and prints the address and char to stdout. */ -static void (*format_address)(off_t, char); -/* The difference between the old-style pseudo starting address and - the number of bytes to skip. */ + /* Function that accepts an address and an optional following char, + and prints the address and char to stdout. */ + void (*format_address)(off_t, char); + + /* The difference between the old-style pseudo starting address and + the number of bytes to skip. */ #if ENABLE_LONG_OPTS -static off_t pseudo_offset; -#else -enum { pseudo_offset = 0 }; + off_t pseudo_offset; +# define G_pseudo_offset G.pseudo_offset #endif -/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all - input is formatted. */ - -/* The number of input bytes formatted per output line. It must be - a multiple of the least common multiple of the sizes associated with - the specified output types. It should be as large as possible, but - no larger than 16 -- unless specified with the -w option. */ -static unsigned bytes_per_block = 32; /* have to use unsigned, not size_t */ - -/* A NULL-terminated list of the file-arguments from the command line. */ -static const char *const *file_list; + /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all + input is formatted. */ + + /* The number of input bytes formatted per output line. It must be + a multiple of the least common multiple of the sizes associated with + the specified output types. It should be as large as possible, but + no larger than 16 -- unless specified with the -w option. */ + unsigned bytes_per_block; /* have to use unsigned, not size_t */ + + /* A NULL-terminated list of the file-arguments from the command line. */ + 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) static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = { @@ -476,17 +490,17 @@ static void open_next_file(void) { while (1) { - if (!*file_list) + if (!*G.file_list) return; - in_stream = fopen_or_warn_stdin(*file_list++); - if (in_stream) { + G.in_stream = fopen_or_warn_stdin(*G.file_list++); + if (G.in_stream) { break; } - exit_code = 1; + G.exit_code = 1; } 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 @@ -499,16 +513,16 @@ open_next_file(void) static void check_and_close(void) { - if (in_stream) { - if (ferror(in_stream)) { - bb_error_msg("%s: read error", (in_stream == stdin) + if (G.in_stream) { + if (ferror(G.in_stream)) { + bb_error_msg("%s: read error", (G.in_stream == stdin) ? bb_msg_standard_input - : file_list[-1] + : G.file_list[-1] ); - exit_code = 1; + G.exit_code = 1; } - fclose_if_not_stdin(in_stream); - in_stream = NULL; + fclose_if_not_stdin(G.in_stream); + G.in_stream = NULL; } if (ferror(stdout)) { @@ -744,9 +758,9 @@ decode_format_string(const char *s) assert(s != next); s = next; - spec = xrealloc_vector(spec, 4, n_specs); - memcpy(&spec[n_specs], &tspec, sizeof(spec[0])); - n_specs++; + G.spec = xrealloc_vector(G.spec, 4, G.n_specs); + memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0])); + G.n_specs++; } } @@ -763,7 +777,7 @@ skip(off_t n_skip) if (n_skip == 0) return; - while (in_stream) { /* !EOF */ + while (G.in_stream) { /* !EOF */ struct stat file_stats; /* 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 as large as the size of the current file, we can 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 ) { if (file_stats.st_size < n_skip) { n_skip -= file_stats.st_size; /* take "check & close / open_next" route */ } else { - if (fseeko(in_stream, n_skip, SEEK_CUR) != 0) - exit_code = 1; + if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0) + G.exit_code = 1; return; } } else { @@ -802,7 +816,7 @@ skip(off_t n_skip) while (n_skip > 0) { if (n_skip < n_bytes_to_read) 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; if (n_bytes_read != n_bytes_to_read) break; /* EOF on this file or error */ @@ -855,7 +869,7 @@ static void format_address_label(off_t address, char c) { format_address_std(address, ' '); - format_address_paren(address + pseudo_offset, c); + format_address_paren(address + G_pseudo_offset, c); } #endif @@ -886,36 +900,34 @@ static void write_block(off_t current_offset, size_t n_bytes, const char *prev_block, const char *curr_block) { - static char first = 1; - static char prev_pair_equal = 0; - size_t i; + unsigned i; if (!(option_mask32 & OPT_v) - && !first - && n_bytes == bytes_per_block - && memcmp(prev_block, curr_block, bytes_per_block) == 0 + && G.not_first + && n_bytes == G.bytes_per_block + && 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 block is the same as the last one, so print nothing. */ } else { puts("*"); - prev_pair_equal = 1; + G.prev_pair_equal = 1; } } else { - first = 0; - prev_pair_equal = 0; - for (i = 0; i < n_specs; i++) { + G.not_first = 1; + G.prev_pair_equal = 0; + for (i = 0; i < G.n_specs; i++) { if (i == 0) - format_address(current_offset, '\0'); + G.format_address(current_offset, '\0'); else printf("%*s", address_pad_len_char - '0', ""); - (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string); - if (spec[i].hexl_mode_trailer) { + (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string); + if (G.spec[i].hexl_mode_trailer) { /* space-pad out to full line width, then dump the trailer */ - unsigned datum_width = width_bytes[spec[i].size]; - unsigned blank_fields = (bytes_per_block - n_bytes) / datum_width; - unsigned field_width = spec[i].field_width + 1; + unsigned datum_width = width_bytes[G.spec[i].size]; + unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width; + unsigned field_width = G.spec[i].field_width + 1; printf("%*s", blank_fields * field_width, ""); dump_hexl_mode_trailer(n_bytes, curr_block); } @@ -927,19 +939,19 @@ write_block(off_t current_offset, size_t n_bytes, static void 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; if (n == 0) return; - while (in_stream != NULL) { /* EOF. */ + while (G.in_stream != NULL) { /* EOF. */ size_t n_needed; size_t n_read; 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; if (n_read == n_needed) break; @@ -958,8 +970,8 @@ get_lcm(void) size_t i; int l_c_m = 1; - for (i = 0; i < n_specs; i++) - l_c_m = lcm(l_c_m, width_bytes[(int) spec[i].size]); + for (i = 0; i < G.n_specs; i++) + l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]); return l_c_m; } @@ -980,8 +992,8 @@ dump(off_t current_offset, off_t end_offset) int idx; size_t n_bytes_read; - block[0] = xmalloc(2 * bytes_per_block); - block[1] = block[0] + bytes_per_block; + block[0] = xmalloc(2 * G.bytes_per_block); + block[1] = block[0] + G.bytes_per_block; idx = 0; if (option_mask32 & OPT_N) { @@ -991,21 +1003,21 @@ dump(off_t current_offset, off_t end_offset) n_bytes_read = 0; 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); - if (n_bytes_read < bytes_per_block) + if (n_bytes_read < G.bytes_per_block) 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]); current_offset += n_bytes_read; idx ^= 1; } } else { while (1) { - read_block(bytes_per_block, block[idx], &n_bytes_read); - if (n_bytes_read < bytes_per_block) + read_block(G.bytes_per_block, block[idx], &n_bytes_read); + if (n_bytes_read < G.bytes_per_block) 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]); current_offset += n_bytes_read; idx ^= 1; @@ -1028,7 +1040,7 @@ dump(off_t current_offset, off_t end_offset) 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) check_and_close(); @@ -1059,16 +1071,16 @@ dump(off_t current_offset, off_t end_offset) static void 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); while (1) { size_t i; 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: - if ((option_mask32 & OPT_N) && (end_offset - string_min <= address)) + if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address)) break; i = 0; 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); } - while (in_stream) { /* !EOF */ - c = fgetc(in_stream); + while (G.in_stream) { /* !EOF */ + c = fgetc(G.in_stream); if (c != EOF) goto got_char; check_and_close(); @@ -1095,12 +1107,12 @@ dump_strings(off_t address, off_t end_offset) buf[i++] = c; /* String continues; store it all. */ } - if (i < string_min) /* Too short! */ + if (i < G.string_min) /* Too short! */ goto tryline; /* If we get here, the string is all printable and NUL-terminated */ buf[i] = 0; - format_address(address - i - 1, ' '); + G.format_address(address - i - 1, ' '); for (i = 0; (c = buf[i]); i++) { switch (c) { @@ -1118,7 +1130,7 @@ dump_strings(off_t address, off_t end_offset) } /* 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(); ret: free(buf); @@ -1190,8 +1202,10 @@ int od_main(int argc UNUSED_PARAM, char **argv) /* The maximum number of bytes that will be formatted. */ off_t max_bytes_to_format = 0; - spec = NULL; - format_address = format_address_std; + INIT_G(); + + /*G.spec = NULL; - already is */ + G.format_address = format_address_std; address_base_char = 'o'; 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 " "'%c' (must be [doxn])", str_A[0]); 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_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_s) decode_format_string("d2"); if (opt & OPT_S) { - string_min = xstrtou_sfx(str_S, 0, bkm_suffixes); + G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes); } // 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"); /* 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 (format_address == format_address_none) { + if (G.format_address == format_address_none) { address_base_char = 'o'; address_pad_len_char = '7'; - format_address = format_address_paren; + G.format_address = format_address_paren; } 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) */ @@ -1320,45 +1334,45 @@ int od_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die("SKIP + SIZE is too large"); } - if (n_specs == 0) { + if (G.n_specs == 0) { 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, set the global pointer FILE_LIST so that it references the null-terminated list of one name: "-". */ - file_list = bb_argv_dash; + G.file_list = bb_argv_dash; if (argv[0]) { /* Set the global pointer FILE_LIST so that it 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_next_file(); /* Skip over any unwanted header bytes */ skip(n_bytes_to_skip); - if (!in_stream) + if (!G.in_stream) return EXIT_FAILURE; /* Compute output block length */ l_c_m = get_lcm(); 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", - (unsigned)bytes_per_block, l_c_m); - bytes_per_block = l_c_m; + (unsigned)G.bytes_per_block, l_c_m); + G.bytes_per_block = l_c_m; } } else { - bytes_per_block = l_c_m; + G.bytes_per_block = l_c_m; 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 - for (i = 0; i < n_specs; i++) { + for (i = 0; i < G.n_specs; i++) { printf("%d: fmt=\"%s\" width=%d\n", 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)) bb_perror_msg_and_die(bb_msg_standard_input); - return exit_code; + return G.exit_code; } |