mirror of https://git.tukaani.org/xz.git
xz: Automatically align column headings in xz -lvv.
This commit is contained in:
parent
6cb42e8aa1
commit
a750c35a7d
261
src/xz/list.c
261
src/xz/list.c
|
@ -100,6 +100,63 @@ static int colon_strs_fw[ARRAY_SIZE(colon_strs)];
|
||||||
#define COLON_STR(num) colon_strs_fw[num], _(colon_strs[num])
|
#define COLON_STR(num) colon_strs_fw[num], _(colon_strs[num])
|
||||||
|
|
||||||
|
|
||||||
|
/// Column headings
|
||||||
|
struct {
|
||||||
|
/// Table column heading string
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
/// Number of terminal-columns to use for this table-column.
|
||||||
|
/// If a translated string is longer than the initial value,
|
||||||
|
/// this value will be increased in init_headings().
|
||||||
|
int columns;
|
||||||
|
|
||||||
|
/// Field width to use for printf() to pad "str" to use "columns"
|
||||||
|
/// number of columns on a terminal. This is calculated in
|
||||||
|
/// init_headings().
|
||||||
|
int fw;
|
||||||
|
|
||||||
|
} headings[] = {
|
||||||
|
{ N_("Stream"), 6, 0 },
|
||||||
|
{ N_("Block"), 9, 0 },
|
||||||
|
{ N_("Blocks"), 9, 0 },
|
||||||
|
{ N_("CompOffset"), 15, 0 },
|
||||||
|
{ N_("UncompOffset"), 15, 0 },
|
||||||
|
{ N_("CompSize"), 15, 0 },
|
||||||
|
{ N_("UncompSize"), 15, 0 },
|
||||||
|
{ N_("TotalSize"), 15, 0 },
|
||||||
|
{ N_("Ratio"), 5, 0 },
|
||||||
|
{ N_("Check"), 10, 0 },
|
||||||
|
{ N_("CheckVal"), 1, 0 },
|
||||||
|
{ N_("Padding"), 7, 0 },
|
||||||
|
{ N_("Header"), 5, 0 },
|
||||||
|
{ N_("Flags"), 2, 0 },
|
||||||
|
{ N_("MemUsage"), 7 + 4, 0 }, // +4 is for " MiB"
|
||||||
|
{ N_("Filters"), 1, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Enum matching the above strings.
|
||||||
|
enum {
|
||||||
|
HEADING_STREAM,
|
||||||
|
HEADING_BLOCK,
|
||||||
|
HEADING_BLOCKS,
|
||||||
|
HEADING_COMPOFFSET,
|
||||||
|
HEADING_UNCOMPOFFSET,
|
||||||
|
HEADING_COMPSIZE,
|
||||||
|
HEADING_UNCOMPSIZE,
|
||||||
|
HEADING_TOTALSIZE,
|
||||||
|
HEADING_RATIO,
|
||||||
|
HEADING_CHECK,
|
||||||
|
HEADING_CHECKVAL,
|
||||||
|
HEADING_PADDING,
|
||||||
|
HEADING_HEADERSIZE,
|
||||||
|
HEADING_HEADERFLAGS,
|
||||||
|
HEADING_MEMUSAGE,
|
||||||
|
HEADING_FILTERS,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HEADING_STR(num) headings[num].fw, _(headings[num].str)
|
||||||
|
|
||||||
|
|
||||||
/// Check ID to string mapping
|
/// Check ID to string mapping
|
||||||
static const char check_names[LZMA_CHECK_ID_MAX + 1][12] = {
|
static const char check_names[LZMA_CHECK_ID_MAX + 1][12] = {
|
||||||
// TRANSLATORS: Indicates that there is no integrity check.
|
// TRANSLATORS: Indicates that there is no integrity check.
|
||||||
|
@ -155,10 +212,9 @@ static struct {
|
||||||
} totals = { 0, 0, 0, 0, 0, 0, 0, 0, 50000002, true };
|
} totals = { 0, 0, 0, 0, 0, 0, 0, 0, 50000002, true };
|
||||||
|
|
||||||
|
|
||||||
/// Initialize the printf field widths that are needed to get nicely aligned
|
/// Initialize colon_strs_fw[].
|
||||||
/// output with translated strings.
|
|
||||||
static void
|
static void
|
||||||
init_field_widths(void)
|
init_colon_strs(void)
|
||||||
{
|
{
|
||||||
// Lengths of translated strings as bytes.
|
// Lengths of translated strings as bytes.
|
||||||
size_t lens[ARRAY_SIZE(colon_strs)];
|
size_t lens[ARRAY_SIZE(colon_strs)];
|
||||||
|
@ -196,6 +252,44 @@ init_field_widths(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Initialize headings[].
|
||||||
|
static void
|
||||||
|
init_headings(void)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < ARRAY_SIZE(headings); ++i) {
|
||||||
|
size_t len;
|
||||||
|
size_t w = tuklib_mbstr_width(headings[i].str, &len);
|
||||||
|
|
||||||
|
// Error handling like in init_colon_strs().
|
||||||
|
assert(w != (size_t)-1);
|
||||||
|
if (w == (size_t)-1)
|
||||||
|
w = len;
|
||||||
|
|
||||||
|
// If the translated string is wider than the minimum width
|
||||||
|
// set at compile time, increase the width.
|
||||||
|
if ((size_t)(headings[i].columns) < w)
|
||||||
|
headings[i].columns = w;
|
||||||
|
|
||||||
|
// Calculate the field width for printf("%*s") so that
|
||||||
|
// the string uses .columns number of columns on a terminal.
|
||||||
|
headings[i].fw = (int)(len + headings[i].columns - w);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Initialize the printf field widths that are needed to get nicely aligned
|
||||||
|
/// output with translated strings.
|
||||||
|
static void
|
||||||
|
init_field_widths(void)
|
||||||
|
{
|
||||||
|
init_colon_strs();
|
||||||
|
init_headings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Convert XZ Utils version number to a string.
|
/// Convert XZ Utils version number to a string.
|
||||||
static const char *
|
static const char *
|
||||||
xz_ver_to_str(uint32_t ver)
|
xz_ver_to_str(uint32_t ver)
|
||||||
|
@ -372,6 +466,10 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter,
|
||||||
// Check the Block Flags. These must be done before calling
|
// Check the Block Flags. These must be done before calling
|
||||||
// lzma_block_compressed_size(), because it overwrites
|
// lzma_block_compressed_size(), because it overwrites
|
||||||
// block.compressed_size.
|
// block.compressed_size.
|
||||||
|
//
|
||||||
|
// NOTE: If you add new characters here, update the minimum number of
|
||||||
|
// columns in headings[HEADING_HEADERFLAGS] to match the number of
|
||||||
|
// characters used here.
|
||||||
bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
|
bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
|
||||||
? 'c' : '-';
|
? 'c' : '-';
|
||||||
bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
|
bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
|
||||||
|
@ -670,13 +768,19 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
|
||||||
|
|
||||||
// Print information about the Streams.
|
// Print information about the Streams.
|
||||||
//
|
//
|
||||||
// TRANSLATORS: The second line is column headings. All except
|
// All except Check are right aligned; Check is left aligned.
|
||||||
// Check are right aligned; Check is left aligned. Test with
|
// Test with "xz -lv foo.xz".
|
||||||
// "xz -lv foo.xz".
|
printf(" %s\n %*s %*s %*s %*s %*s %*s %*s %-*s %*s\n",
|
||||||
puts(_(" Streams:\n Stream Blocks"
|
_(colon_strs[COLON_STR_STREAMS]),
|
||||||
" CompOffset UncompOffset"
|
HEADING_STR(HEADING_STREAM),
|
||||||
" CompSize UncompSize Ratio"
|
HEADING_STR(HEADING_BLOCKS),
|
||||||
" Check Padding"));
|
HEADING_STR(HEADING_COMPOFFSET),
|
||||||
|
HEADING_STR(HEADING_UNCOMPOFFSET),
|
||||||
|
HEADING_STR(HEADING_COMPSIZE),
|
||||||
|
HEADING_STR(HEADING_UNCOMPSIZE),
|
||||||
|
HEADING_STR(HEADING_RATIO),
|
||||||
|
HEADING_STR(HEADING_CHECK),
|
||||||
|
HEADING_STR(HEADING_PADDING));
|
||||||
|
|
||||||
lzma_index_iter iter;
|
lzma_index_iter iter;
|
||||||
lzma_index_iter_init(&iter, xfi->idx);
|
lzma_index_iter_init(&iter, xfi->idx);
|
||||||
|
@ -689,10 +793,18 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
|
||||||
uint64_to_str(iter.stream.uncompressed_offset, 3),
|
uint64_to_str(iter.stream.uncompressed_offset, 3),
|
||||||
};
|
};
|
||||||
printf(" %*s %*s %*s %*s ",
|
printf(" %*s %*s %*s %*s ",
|
||||||
tuklib_mbstr_fw(cols1[0], 6), cols1[0],
|
tuklib_mbstr_fw(cols1[0],
|
||||||
tuklib_mbstr_fw(cols1[1], 9), cols1[1],
|
headings[HEADING_STREAM].columns),
|
||||||
tuklib_mbstr_fw(cols1[2], 15), cols1[2],
|
cols1[0],
|
||||||
tuklib_mbstr_fw(cols1[3], 15), cols1[3]);
|
tuklib_mbstr_fw(cols1[1],
|
||||||
|
headings[HEADING_BLOCKS].columns),
|
||||||
|
cols1[1],
|
||||||
|
tuklib_mbstr_fw(cols1[2],
|
||||||
|
headings[HEADING_COMPOFFSET].columns),
|
||||||
|
cols1[2],
|
||||||
|
tuklib_mbstr_fw(cols1[3],
|
||||||
|
headings[HEADING_UNCOMPOFFSET].columns),
|
||||||
|
cols1[3]);
|
||||||
|
|
||||||
const char *cols2[5] = {
|
const char *cols2[5] = {
|
||||||
uint64_to_str(iter.stream.compressed_size, 0),
|
uint64_to_str(iter.stream.compressed_size, 0),
|
||||||
|
@ -703,11 +815,21 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
|
||||||
uint64_to_str(iter.stream.padding, 2),
|
uint64_to_str(iter.stream.padding, 2),
|
||||||
};
|
};
|
||||||
printf("%*s %*s %*s %-*s %*s\n",
|
printf("%*s %*s %*s %-*s %*s\n",
|
||||||
tuklib_mbstr_fw(cols2[0], 15), cols2[0],
|
tuklib_mbstr_fw(cols2[0],
|
||||||
tuklib_mbstr_fw(cols2[1], 15), cols2[1],
|
headings[HEADING_COMPSIZE].columns),
|
||||||
tuklib_mbstr_fw(cols2[2], 5), cols2[2],
|
cols2[0],
|
||||||
tuklib_mbstr_fw(cols2[3], 10), cols2[3],
|
tuklib_mbstr_fw(cols2[1],
|
||||||
tuklib_mbstr_fw(cols2[4], 7), cols2[4]);
|
headings[HEADING_UNCOMPSIZE].columns),
|
||||||
|
cols2[1],
|
||||||
|
tuklib_mbstr_fw(cols2[2],
|
||||||
|
headings[HEADING_RATIO].columns),
|
||||||
|
cols2[2],
|
||||||
|
tuklib_mbstr_fw(cols2[3],
|
||||||
|
headings[HEADING_CHECK].columns),
|
||||||
|
cols2[3],
|
||||||
|
tuklib_mbstr_fw(cols2[4],
|
||||||
|
headings[HEADING_PADDING].columns),
|
||||||
|
cols2[4]);
|
||||||
|
|
||||||
// Update the maximum Check size.
|
// Update the maximum Check size.
|
||||||
if (lzma_check_size(iter.stream.flags->check) > check_max)
|
if (lzma_check_size(iter.stream.flags->check) > check_max)
|
||||||
|
@ -723,26 +845,43 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
|
||||||
// Print information about the Blocks but only if there is
|
// Print information about the Blocks but only if there is
|
||||||
// at least one Block.
|
// at least one Block.
|
||||||
if (lzma_index_block_count(xfi->idx) > 0) {
|
if (lzma_index_block_count(xfi->idx) > 0) {
|
||||||
// Calculate the width of the CheckVal field.
|
// Calculate the width of the CheckVal column. This can be
|
||||||
const int checkval_width = my_max(8, 2 * check_max);
|
// used as is as the field width for printf() when printing
|
||||||
|
// the actual check value as it is hexadecimal. However, to
|
||||||
|
// print the column heading, further calculation is needed
|
||||||
|
// to handle a translated string (it's done a few lines later).
|
||||||
|
const int checkval_width = my_max(
|
||||||
|
(uint32_t)(headings[HEADING_CHECKVAL].columns),
|
||||||
|
2 * check_max);
|
||||||
|
|
||||||
// TRANSLATORS: The second line is column headings. All
|
// All except Check are right aligned; Check is left aligned.
|
||||||
// except Check are right aligned; Check is left aligned.
|
printf(" %s\n %*s %*s %*s %*s %*s %*s %*s %-*s",
|
||||||
printf(_(" Blocks:\n Stream Block"
|
_(colon_strs[COLON_STR_BLOCKS]),
|
||||||
" CompOffset UncompOffset"
|
HEADING_STR(HEADING_STREAM),
|
||||||
" TotalSize UncompSize Ratio Check"));
|
HEADING_STR(HEADING_BLOCK),
|
||||||
|
HEADING_STR(HEADING_COMPOFFSET),
|
||||||
|
HEADING_STR(HEADING_UNCOMPOFFSET),
|
||||||
|
HEADING_STR(HEADING_TOTALSIZE),
|
||||||
|
HEADING_STR(HEADING_UNCOMPSIZE),
|
||||||
|
HEADING_STR(HEADING_RATIO),
|
||||||
|
detailed ? headings[HEADING_CHECK].fw : 1,
|
||||||
|
_(headings[HEADING_CHECK].str));
|
||||||
|
|
||||||
if (detailed) {
|
if (detailed) {
|
||||||
// TRANSLATORS: These are additional column headings
|
// CheckVal (Check value), Flags, and Filters are
|
||||||
// for the most verbose listing mode. CheckVal
|
// left aligned. Block Header Size, CompSize, and
|
||||||
// (Check value), Flags, and Filters are left aligned.
|
// MemUsage are right aligned. Test with
|
||||||
// Header (Block Header Size), CompSize, and MemUsage
|
// "xz -lvv foo.xz".
|
||||||
// are right aligned. %*s is replaced with 0-120
|
printf(" %-*s %*s %-*s %*s %*s %s",
|
||||||
// spaces to make the CheckVal column wide enough.
|
headings[HEADING_CHECKVAL].fw
|
||||||
// Test with "xz -lvv foo.xz".
|
+ checkval_width
|
||||||
printf(_(" CheckVal %*s Header Flags "
|
- headings[HEADING_CHECKVAL].columns,
|
||||||
"CompSize MemUsage Filters"),
|
_(headings[HEADING_CHECKVAL].str),
|
||||||
checkval_width - 8, "");
|
HEADING_STR(HEADING_HEADERSIZE),
|
||||||
|
HEADING_STR(HEADING_HEADERFLAGS),
|
||||||
|
HEADING_STR(HEADING_COMPSIZE),
|
||||||
|
HEADING_STR(HEADING_MEMUSAGE),
|
||||||
|
_(headings[HEADING_FILTERS].str));
|
||||||
}
|
}
|
||||||
|
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
@ -764,10 +903,18 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
|
||||||
iter.block.uncompressed_file_offset, 3)
|
iter.block.uncompressed_file_offset, 3)
|
||||||
};
|
};
|
||||||
printf(" %*s %*s %*s %*s ",
|
printf(" %*s %*s %*s %*s ",
|
||||||
tuklib_mbstr_fw(cols1[0], 6), cols1[0],
|
tuklib_mbstr_fw(cols1[0],
|
||||||
tuklib_mbstr_fw(cols1[1], 9), cols1[1],
|
headings[HEADING_STREAM].columns),
|
||||||
tuklib_mbstr_fw(cols1[2], 15), cols1[2],
|
cols1[0],
|
||||||
tuklib_mbstr_fw(cols1[3], 15), cols1[3]);
|
tuklib_mbstr_fw(cols1[1],
|
||||||
|
headings[HEADING_BLOCK].columns),
|
||||||
|
cols1[1],
|
||||||
|
tuklib_mbstr_fw(cols1[2],
|
||||||
|
headings[HEADING_COMPOFFSET].columns),
|
||||||
|
cols1[2],
|
||||||
|
tuklib_mbstr_fw(cols1[3], headings[
|
||||||
|
HEADING_UNCOMPOFFSET].columns),
|
||||||
|
cols1[3]);
|
||||||
|
|
||||||
const char *cols2[4] = {
|
const char *cols2[4] = {
|
||||||
uint64_to_str(iter.block.total_size, 0),
|
uint64_to_str(iter.block.total_size, 0),
|
||||||
|
@ -778,11 +925,18 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
|
||||||
_(check_names[iter.stream.flags->check])
|
_(check_names[iter.stream.flags->check])
|
||||||
};
|
};
|
||||||
printf("%*s %*s %*s %-*s",
|
printf("%*s %*s %*s %-*s",
|
||||||
tuklib_mbstr_fw(cols2[0], 15), cols2[0],
|
tuklib_mbstr_fw(cols2[0],
|
||||||
tuklib_mbstr_fw(cols2[1], 15), cols2[1],
|
headings[HEADING_TOTALSIZE].columns),
|
||||||
tuklib_mbstr_fw(cols2[2], 5), cols2[2],
|
cols2[0],
|
||||||
tuklib_mbstr_fw(cols2[3], detailed ? 11 : 1),
|
tuklib_mbstr_fw(cols2[1],
|
||||||
cols2[3]);
|
headings[HEADING_UNCOMPSIZE].columns),
|
||||||
|
cols2[1],
|
||||||
|
tuklib_mbstr_fw(cols2[2],
|
||||||
|
headings[HEADING_RATIO].columns),
|
||||||
|
cols2[2],
|
||||||
|
tuklib_mbstr_fw(cols2[3], detailed
|
||||||
|
? headings[HEADING_CHECK].columns : 1),
|
||||||
|
cols2[3]);
|
||||||
|
|
||||||
if (detailed) {
|
if (detailed) {
|
||||||
const lzma_vli compressed_size
|
const lzma_vli compressed_size
|
||||||
|
@ -803,13 +957,20 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
|
||||||
};
|
};
|
||||||
// Show MiB for memory usage, because it
|
// Show MiB for memory usage, because it
|
||||||
// is the only size which is not in bytes.
|
// is the only size which is not in bytes.
|
||||||
printf("%-*s %*s %-5s %*s %*s MiB %s",
|
printf(" %-*s %*s %-*s %*s %*s MiB %s",
|
||||||
checkval_width, cols3[0],
|
checkval_width, cols3[0],
|
||||||
tuklib_mbstr_fw(cols3[1], 6), cols3[1],
|
tuklib_mbstr_fw(cols3[1], headings[
|
||||||
|
HEADING_HEADERSIZE].columns),
|
||||||
|
cols3[1],
|
||||||
|
tuklib_mbstr_fw(cols3[2], headings[
|
||||||
|
HEADING_HEADERFLAGS].columns),
|
||||||
cols3[2],
|
cols3[2],
|
||||||
tuklib_mbstr_fw(cols3[3], 15),
|
tuklib_mbstr_fw(cols3[3], headings[
|
||||||
cols3[3],
|
HEADING_COMPSIZE].columns),
|
||||||
tuklib_mbstr_fw(cols3[4], 7), cols3[4],
|
cols3[3],
|
||||||
|
tuklib_mbstr_fw(cols3[4], headings[
|
||||||
|
HEADING_MEMUSAGE].columns - 4),
|
||||||
|
cols3[4],
|
||||||
cols3[5]);
|
cols3[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue