Improve VerbosePkgList by caching attributes then and cell's length with
the cell's label instead of recalculating.
Right align every cell that containing a file size, not just the last
collumn.
Simplify printf statements and the alignment application.
---
src/pacman/util.c | 237 ++++++++++++++++++++++++++++--------------------------
1 file changed, 123 insertions(+), 114 deletions(-)
diff --git a/src/pacman/util.c b/src/pacman/util.c
index bd09adc..acbf217 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -47,9 +47,17 @@
#include "callback.h"
-struct table_row_t {
- const char *label;
- off_t size;
+struct table_cell_t {
+ char *label;
+ size_t len;
+ int mode;
+};
+
+enum {
+ CELL_NORMAL = 0,
+ CELL_TITLE = 1,
+ CELL_RIGHT_ALIGN = 1 << 2,
+ CELL_FREE = 1 << 3
};
int trans_init(alpm_transflag_t flags, int check_valid)
@@ -424,6 +432,60 @@ static size_t string_length(const char *s)
return len;
}
+static void add_table_cell(alpm_list_t **row, char *label, int mode)
+{
+ struct table_cell_t *cell = malloc(sizeof(struct table_cell_t));
+
+ cell->label = label;
+ cell->mode = mode;
+ cell->len = string_length(label);
+
+ *row = alpm_list_add(*row, cell);
+}
+
+static void table_free_cell(void *ptr)
+{
+ struct table_cell_t *cell = ptr;
+
+ if(cell) {
+ if((cell->mode & CELL_FREE) && cell->label) {
+ free(cell->label);
+ }
+ free(cell);
+ }
+}
+
+static void table_free(alpm_list_t *headers, alpm_list_t *rows)
+{
+ alpm_list_t *i;
+
+ alpm_list_free_inner(headers, table_free_cell);
+
+ for(i = rows; i; i = alpm_list_next(i)) {
+ if(i->data) {
+ alpm_list_free_inner(i->data, table_free_cell);
+ alpm_list_free(i->data);
+ }
+ }
+
+ alpm_list_free(headers);
+ alpm_list_free(rows);
+}
+
+static void add_transaction_sizes_row(alpm_list_t **table, char *label, int size)
+{
+ alpm_list_t *row = NULL;
+ char *str;
+ const char *units;
+ double s = humanize_size(size, 'M', 2, &units);
+ pm_asprintf(&str, "%.2f %s", s, units);
+
+ add_table_cell(&row, label, CELL_TITLE);
+ add_table_cell(&row, str, CELL_RIGHT_ALIGN | CELL_FREE);
+
+ *table = alpm_list_add(*table, row);
+}
+
void string_display(const char *title, const char *string, unsigned short cols)
{
if(title) {
@@ -442,43 +504,30 @@ void string_display(const char *title, const char *string, unsigned short cols)
static void table_print_line(const alpm_list_t *line, short col_padding,
size_t colcount, size_t *widths, int *has_data)
{
- size_t i, lastcol = 0;
+ size_t i;
int need_padding = 0;
const alpm_list_t *curcell;
- for(i = colcount; i > 0; i--) {
- if(has_data[i - 1]) {
- lastcol = i - 1;
- break;
- }
- }
-
for(i = 0, curcell = line; curcell && i < colcount;
i++, curcell = alpm_list_next(curcell)) {
- const char *value;
+ const struct table_cell_t *cell = curcell->data;
+ const char *str = (cell->label ? cell->label : "");
int cell_padding;
if(!has_data[i]) {
continue;
}
- value = curcell->data;
- if(!value) {
- value = "";
- }
- /* silly printf requires padding size to be an int */
- cell_padding = (int)widths[i] - (int)string_length(value);
- if(cell_padding < 0) {
- cell_padding = 0;
- }
+ cell_padding = (cell->mode & CELL_RIGHT_ALIGN ? (int)widths[i] : -(int)widths[i]);
+
if(need_padding) {
printf("%*s", col_padding, "");
}
- /* left-align all but the last column */
- if(i != lastcol) {
- printf("%s%*s", value, cell_padding, "");
+
+ if(cell->mode & CELL_TITLE) {
+ printf("%s%*s%s", config->colstr.title, cell_padding, str, config->colstr.nocolor);
} else {
- printf("%*s%s", cell_padding, "", value);
+ printf("%*s", cell_padding, str);
}
need_padding = 1;
}
@@ -487,7 +536,6 @@ static void table_print_line(const alpm_list_t *line, short col_padding,
}
-
/**
* Find the max string width of each column. Also determines whether values
* exist in the column and sets the value in has_data accordingly.
@@ -522,7 +570,8 @@ static size_t table_calc_widths(const alpm_list_t *header,
}
/* header determines column count and initial values of longest_strs */
for(i = header, curcol = 0; i; i = alpm_list_next(i), curcol++) {
- colwidths[curcol] = string_length(i->data);
+ const struct table_cell_t *row = i->data;
+ colwidths[curcol] = row->len;
/* note: header does not determine whether column has data */
}
@@ -531,8 +580,8 @@ static size_t table_calc_widths(const alpm_list_t *header,
/* grab first column of each row and iterate through columns */
const alpm_list_t *j = i->data;
for(curcol = 0; j; j = alpm_list_next(j), curcol++) {
- const char *str = j->data;
- size_t str_len = string_length(str);
+ const struct table_cell_t *row = j->data;
+ size_t str_len = row ? row->len : 0;
if(str_len > colwidths[curcol]) {
colwidths[curcol] = str_len;
@@ -571,20 +620,24 @@ static size_t table_calc_widths(const alpm_list_t *header,
* @param cols the number of columns available in the terminal
* @return -1 if not enough terminal cols available, else 0
*/
-static int table_display(const char *title, const alpm_list_t *header,
+static int table_display(const alpm_list_t *header,
const alpm_list_t *rows, unsigned short cols)
{
const unsigned short padding = 2;
- const alpm_list_t *i;
+ const alpm_list_t *i, *first;
size_t *widths = NULL, totalcols, totalwidth;
int *has_data = NULL;
- if(rows == NULL || header == NULL) {
+ if(rows == NULL) {
return 0;
}
- totalcols = alpm_list_count(header);
- totalwidth = table_calc_widths(header, rows, padding, totalcols,
+ /* we want the first row. if no headers are provided, use the first
+ * entry of the rows array. */
+ first = header ? header : rows->data;
+
+ totalcols = alpm_list_count(first);
+ totalwidth = table_calc_widths(first, rows, padding, totalcols,
&widths, &has_data);
/* return -1 if terminal is not wide enough */
if(totalwidth > cols) {
@@ -596,13 +649,11 @@ static int table_display(const char *title, const alpm_list_t *header,
return -1;
}
- if(title != NULL) {
- printf("%s\n\n", title);
+ if (header) {
+ table_print_line(header, padding, totalcols, widths, has_data);
+ printf("\n");
}
- table_print_line(header, padding, totalcols, widths, has_data);
- printf("\n");
-
for(i = rows; i; i = alpm_list_next(i)) {
table_print_line(i->data, padding, totalcols, widths, has_data);
}
@@ -759,23 +810,20 @@ void signature_display(const char *title, alpm_siglist_t *siglist,
}
/* creates a header row for use with table_display */
-static alpm_list_t *create_verbose_header(void)
+static alpm_list_t *create_verbose_header(size_t count)
{
- alpm_list_t *res = NULL;
- char *str;
+ alpm_list_t *ret = NULL;
+
+ char *header;
+ pm_asprintf(&header, "%s (%zd)", _("Package"), count);
+
+ add_table_cell(&ret, header, CELL_TITLE | CELL_FREE);
+ add_table_cell(&ret, _("Old Version"), CELL_TITLE);
+ add_table_cell(&ret, _("New Version"), CELL_TITLE);
+ add_table_cell(&ret, _("Net Change"), CELL_TITLE);
+ add_table_cell(&ret, _("Download Size"), CELL_TITLE);
- str = _("Name");
- res = alpm_list_add(res, str);
- str = _("Old Version");
- res = alpm_list_add(res, str);
- str = _("New Version");
- res = alpm_list_add(res, str);
- str = _("Net Change");
- res = alpm_list_add(res, str);
- str = _("Download Size");
- res = alpm_list_add(res, str);
-
- return res;
+ return ret;
}
/* returns package info as list of strings */
@@ -798,23 +846,23 @@ static alpm_list_t *create_verbose_row(pm_target_t *target)
} else {
pm_asprintf(&str, "%s", alpm_pkg_get_name(target->remove));
}
- ret = alpm_list_add(ret, str);
+ add_table_cell(&ret, str, CELL_NORMAL);
/* old and new versions */
pm_asprintf(&str, "%s",
target->remove != NULL ? alpm_pkg_get_version(target->remove) : "");
- ret = alpm_list_add(ret, str);
+ add_table_cell(&ret, str, CELL_NORMAL);
pm_asprintf(&str, "%s",
target->install != NULL ? alpm_pkg_get_version(target->install) : "");
- ret = alpm_list_add(ret, str);
+ add_table_cell(&ret, str, CELL_NORMAL);
/* and size */
size -= target->remove ? alpm_pkg_get_isize(target->remove) : 0;
size += target->install ? alpm_pkg_get_isize(target->install) : 0;
human_size = humanize_size(size, 'M', 2, &label);
pm_asprintf(&str, "%.2f %s", human_size, label);
- ret = alpm_list_add(ret, str);
+ add_table_cell(&ret, str, CELL_RIGHT_ALIGN);
size = target->install ? alpm_pkg_download_size(target->install) : 0;
if(size != 0) {
@@ -823,55 +871,18 @@ static alpm_list_t *create_verbose_row(pm_target_t *target)
} else {
str = NULL;
}
- ret = alpm_list_add(ret, str);
+ add_table_cell(&ret, str, CELL_RIGHT_ALIGN);
return ret;
}
-static void add_transaction_sizes_row(alpm_list_t **table, const char *label, off_t size)
-{
- struct table_row_t *row = malloc(sizeof(struct table_row_t));
-
- row->label = label;
- row->size = size;
-
- *table = alpm_list_add(*table, row);
-}
-
-static void display_transaction_sizes(alpm_list_t *table)
-{
- alpm_list_t *i;
- int max_len = 0;
-
- for(i = table; i; i = alpm_list_next(i)) {
- struct table_row_t *row = i->data;
- int len = string_length(row->label);
-
- if(len > max_len) {
- max_len = len;
- }
- }
-
- max_len += 2;
-
- for(i = table; i; i = alpm_list_next(i)) {
- struct table_row_t *row = i->data;
- const char *units;
- const colstr_t *colstr = &config->colstr;
- double s = humanize_size(row->size, 'M', 2, &units);
-
- printf("%s%-*s%s %.2f %s\n", colstr->title, max_len, row->label,
- colstr->nocolor, s, units);
- }
-}
-
/* prepare a list of pkgs to display */
static void _display_targets(alpm_list_t *targets, int verbose)
{
char *str;
off_t isize = 0, rsize = 0, dlsize = 0;
unsigned short cols;
- alpm_list_t *i, *rows = NULL, *names = NULL, *table = NULL;
+ alpm_list_t *i, *names = NULL, *header = NULL, *rows = NULL;
if(!targets) {
return;
@@ -895,7 +906,10 @@ static void _display_targets(alpm_list_t *targets, int verbose)
for(i = targets; i; i = alpm_list_next(i)) {
pm_target_t *target = i->data;
- rows = alpm_list_add(rows, create_verbose_row(target));
+ if(verbose) {
+ rows = alpm_list_add(rows, create_verbose_row(target));
+ }
+
if(target->install) {
pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(target->install),
alpm_pkg_get_version(target->install));
@@ -910,48 +924,43 @@ static void _display_targets(alpm_list_t *targets, int verbose)
}
/* print to screen */
- pm_asprintf(&str, "%s (%zd):", _("Packages"), alpm_list_count(targets));
+ pm_asprintf(&str, "%s (%zd)", _("Packages"), alpm_list_count(targets));
printf("\n");
cols = getcols(fileno(stdout));
if(verbose) {
- alpm_list_t *header = create_verbose_header();
- if(table_display(str, header, rows, cols) != 0) {
+ header = create_verbose_header(alpm_list_count(targets));
+ if(table_display(header, rows, cols) != 0) {
/* fallback to list display if table wouldn't fit */
list_display(str, names, cols);
}
- alpm_list_free(header);
} else {
list_display(str, names, cols);
}
printf("\n");
- /* rows is a list of lists of strings, free inner lists here */
- for(i = rows; i; i = alpm_list_next(i)) {
- alpm_list_t *lp = i->data;
- FREELIST(lp);
- }
- alpm_list_free(rows);
+ table_free(header, rows);
FREELIST(names);
free(str);
+ rows = NULL;
if(dlsize > 0 || config->op_s_downloadonly) {
- add_transaction_sizes_row(&table, _("Total Download Size:"), dlsize);
+ add_transaction_sizes_row(&rows, _("Total Download Size:"), dlsize);
}
if(!config->op_s_downloadonly) {
if(isize > 0) {
- add_transaction_sizes_row(&table, _("Total Installed Size:"), isize);
+ add_transaction_sizes_row(&rows, _("Total Installed Size:"), isize);
}
if(rsize > 0 && isize == 0) {
- add_transaction_sizes_row(&table, _("Total Removed Size:"), rsize);
+ add_transaction_sizes_row(&rows, _("Total Removed Size:"), rsize);
}
/* only show this net value if different from raw installed size */
if(isize > 0 && rsize > 0) {
- add_transaction_sizes_row(&table, _("Net Upgrade Size:"), isize - rsize);
+ add_transaction_sizes_row(&rows, _("Net Upgrade Size:"), isize - rsize);
}
}
- display_transaction_sizes(table);
- FREELIST(table);
+ table_display(NULL, rows, cols);
+ table_free(NULL, rows);
}
static int target_cmp(const void *p1, const void *p2)
--
1.8.3