commit 466a4dcdf8adc4a08c93080e59a7c401779462df
parent 0367626d37f9352378cab11f8b76cc42c78060b5
Author: Louis Burda <quent.burda@gmail.com>
Date: Wed, 7 Jun 2023 04:58:36 +0200
Add squashable column attribution and fix rows_truncated stat
Diffstat:
4 files changed, 72 insertions(+), 45 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -2,3 +2,5 @@ compile_commands.json
build
build.jst
.cache
+.gdb_history
+vgcore*
diff --git a/include/tabular.h b/include/tabular.h
@@ -17,14 +17,14 @@ enum {
enum {
TABULAR_TRUNC,
- TABULAR_SQUASH,
- TABULAR_SQUASH_WORDAWARE
+ TABULAR_WRAP,
+ TABULAR_WRAP_WORDAWARE
};
enum {
TABULAR_ENTRY_HIDDEN,
- TABULAR_ENTRY_STR_AVAIL,
- TABULAR_ENTRY_HIDDEN_AVAIL,
+ TABULAR_ENTRY_STR_SET,
+ TABULAR_ENTRY_HIDDEN_SET,
};
struct tabular_user {
@@ -72,8 +72,11 @@ struct tabular_col {
/* content packing strategy */
int strategy;
- /* omiting column due to space disallowed */
+ /* omiting column due to col contraints disallowed */
bool essential;
+
+ /* reducing length due to col contraints allowed */
+ bool squashable;
};
struct tabular_cfg {
diff --git a/src/tabular.c b/src/tabular.c
@@ -12,6 +12,8 @@
#include <stdint.h>
#include <stddef.h>
+#define BIT(i) (1U << (i))
+
struct col_state {
size_t width;
size_t written;
@@ -39,7 +41,7 @@ static void calc_word_aware(struct tabular_entry *entry, size_t maxwidth,
size_t *offset, size_t *width, size_t *lines);
static size_t recalc_col_word_aware(const struct tabular_cfg *cfg,
struct tabular_row *rows, size_t limit,
- size_t col, size_t maxwidth, size_t remaining);
+ size_t col, size_t maxwidth);
static size_t calc_row_width(struct fmt_state *fmt);
static size_t calc_output_lines(const struct tabular_cfg *cfg,
struct fmt_state *fmt, struct tabular_row *rows, size_t limit);
@@ -138,7 +140,7 @@ calc_word_aware(struct tabular_entry *entry, size_t maxwidth,
size_t
recalc_col_word_aware(const struct tabular_cfg *cfg,
struct tabular_row *rows, size_t limit, size_t col,
- size_t maxwidth, size_t remaining)
+ size_t maxwidth)
{
size_t off, wwidth, max_wwidth, rowcnt;
struct tabular_row *row;
@@ -194,10 +196,10 @@ calc_output_lines(const struct tabular_cfg *cfg, struct fmt_state *fmt,
case TABULAR_TRUNC:
entry_lines = 1;
break;
- case TABULAR_SQUASH:
+ case TABULAR_WRAP:
entry_lines = CEILDIV(row->entries[i].ulen, width);
break;
- case TABULAR_SQUASH_WORDAWARE:
+ case TABULAR_WRAP_WORDAWARE:
calc_word_aware(&row->entries[i],
width, NULL, NULL, &entry_lines);
break;
@@ -216,22 +218,33 @@ bool
recalc_cols(const struct tabular_cfg *cfg, struct tabular_stats *stats,
struct fmt_state *fmt, struct tabular_row *rows, size_t limit)
{
- size_t width, fullwidth;
- size_t i, remaining;
+ size_t width, fullwidth, remaining;
+ ssize_t i;
fullwidth = cfg->outw - cfg->lpad - cfg->rpad;
/* reset widths to minimum requirement */
for (i = 0; i < cfg->column_count; i++) {
if (fmt->columns[i].hidden) continue;
- fmt->columns[i].width = cfg->columns[i].minwidth;
+ if (cfg->columns[i].squashable) {
+ fmt->columns[i].width = cfg->columns[i].minwidth;
+ } else {
+ width = MIN(fmt->columns[i].maxlen,
+ cfg->columns[i].maxwidth - cfg->columns[i].lpad
+ - cfg->columns[i].rpad);
+ if (cfg->columns[i].strategy == TABULAR_WRAP_WORDAWARE)
+ width = recalc_col_word_aware(cfg, rows,
+ limit, (size_t) i, width);
+ fmt->columns[i].width = width + cfg->columns[i].lpad
+ + cfg->columns[i].rpad;
+ }
}
/* could not fit all necessary columns at minimum width */
width = calc_row_width(fmt);
while (width > fullwidth) {
/* remove non-essential columns */
- for (i = cfg->column_count - 1; i >= 0; i--) {
+ for (i = ((ssize_t) cfg->column_count) - 1; i >= 0; i--) {
if (!cfg->columns[i].essential
&& !fmt->columns[i].hidden) {
fmt->columns[i].hidden = true;
@@ -250,12 +263,14 @@ recalc_cols(const struct tabular_cfg *cfg, struct tabular_stats *stats,
remaining = fullwidth - width;
for (i = 0; remaining > 0 && i < cfg->column_count; i++) {
if (fmt->columns[i].hidden) continue;
- width = MIN(fmt->columns[i].maxlen, cfg->columns[i].maxwidth);
- width = MIN(width, fmt->columns[i].width + remaining);
- width = width - fmt->columns[i].lpad - fmt->columns[i].rpad;
- if (cfg->columns[i].strategy == TABULAR_SQUASH_WORDAWARE)
+ if (!cfg->columns[i].squashable) continue;
+ width = MIN(fmt->columns[i].maxlen, cfg->columns[i].maxwidth
+ - fmt->columns[i].lpad - fmt->columns[i].rpad);
+ width = MIN(width, fmt->columns[i].width + remaining
+ - fmt->columns[i].lpad - fmt->columns[i].rpad);
+ if (cfg->columns[i].strategy == TABULAR_WRAP_WORDAWARE)
width = recalc_col_word_aware(cfg, rows,
- limit, i, width, remaining);
+ limit, (size_t) i, width);
width = MAX(width + fmt->columns[i].lpad + fmt->columns[i].rpad,
fmt->columns[i].width);
remaining -= width - fmt->columns[i].width;
@@ -285,7 +300,7 @@ calc_params_row(const struct tabular_cfg *cfg, struct tabular_stats *stats,
tabular_load_row_entry_hidden(cfg, row, i);
if (fmt->columns[i].hidden) {
fmt->columns[i].hidden =
- (row->entries[i].flags & TABULAR_ENTRY_HIDDEN);
+ (row->entries[i].flags & BIT(TABULAR_ENTRY_HIDDEN));
}
if (fmt->columns[i].hidden) continue;
}
@@ -358,20 +373,27 @@ calc_params(const struct tabular_cfg *cfg, struct tabular_stats *stats,
fmt->columns[i].written = 0;
}
+ fmt->row_limit = 0;
+
+ if (!*rows && cfg->row_gen) *rows = cfg->row_gen(&cfg->user);
+ if (!*rows) return 0;
+
if (!recalc_cols(cfg, stats, fmt, *rows, 0)) {
stats->cols_truncated = true;
stats->rows_truncated = true;
return 0;
}
- fmt->row_limit = 0;
for (row = rows; ; row = &(*row)->next) {
if (!*row && cfg->row_gen) *row = cfg->row_gen(&cfg->user);
if (!*row) break;
rc = calc_params_row(cfg, stats, *rows,
*row, fmt, fmt->row_limit + 1);
if (rc < 0) return rc;
- if (rc > 0) break;
+ if (rc > 0) {
+ stats->rows_truncated = true;
+ break;
+ }
fmt->row_limit++;
}
@@ -494,7 +516,7 @@ output_row(FILE *file, const struct tabular_cfg *cfg,
width = fmt->columns[i].width
- fmt->columns[i].lpad - fmt->columns[i].rpad;
padwidth = width;
- if (cfg->columns[i].strategy == TABULAR_SQUASH_WORDAWARE) {
+ if (cfg->columns[i].strategy == TABULAR_WRAP_WORDAWARE) {
calc_word_aware_line(entry, width, &off, &wwidth);
entry += off;
width = wwidth;
@@ -547,8 +569,6 @@ output_rows(FILE *file, const struct tabular_cfg *cfg,
count += 1;
}
- stats->rows_truncated = !row;
-
return 0;
}
@@ -560,13 +580,14 @@ tabular_format(FILE *file, const struct tabular_cfg *cfg,
size_t i;
int rc;
+ stats->lines_used = 0;
stats->rows_displayed = 0;
stats->rows_truncated = false;
stats->cols_truncated = false;
- stats->lines_used = 0;
- if (!cfg->column_count || !rows)
- return 0;
+ if (!rows) return 1;
+
+ if (!cfg->column_count) return 0;
for (i = 0; i < cfg->column_count; i++) {
if (cfg->columns[i].minwidth > cfg->columns[i].maxwidth)
@@ -575,8 +596,8 @@ tabular_format(FILE *file, const struct tabular_cfg *cfg,
>= cfg->columns[i].minwidth)
return 1;
if (cfg->columns[i].strategy != TABULAR_TRUNC
- && cfg->columns[i].strategy != TABULAR_SQUASH
- && cfg->columns[i].strategy != TABULAR_SQUASH_WORDAWARE)
+ && cfg->columns[i].strategy != TABULAR_WRAP
+ && cfg->columns[i].strategy != TABULAR_WRAP_WORDAWARE)
return 1;
}
@@ -643,7 +664,7 @@ tabular_load_row_entry_hidden(const struct tabular_cfg *cfg,
{
bool hidden;
- if (row->entries[col].flags & TABULAR_ENTRY_HIDDEN_AVAIL) return;
+ if (row->entries[col].flags & BIT(TABULAR_ENTRY_HIDDEN_SET)) return;
if (cfg->columns[col].is_hidden) {
hidden = cfg->columns[col].is_hidden(
@@ -653,22 +674,22 @@ tabular_load_row_entry_hidden(const struct tabular_cfg *cfg,
}
if (hidden) {
- row->entries[col].flags |= TABULAR_ENTRY_HIDDEN;
+ row->entries[col].flags |= BIT(TABULAR_ENTRY_HIDDEN);
} else {
- row->entries[col].flags &= TABULAR_ENTRY_HIDDEN;
+ row->entries[col].flags &= ~BIT(TABULAR_ENTRY_HIDDEN);
}
- row->entries[col].flags |= TABULAR_ENTRY_HIDDEN_AVAIL;
+ row->entries[col].flags |= BIT(TABULAR_ENTRY_HIDDEN_SET);
}
void
tabular_load_row_entry_str(const struct tabular_cfg *cfg,
struct tabular_row *row, size_t col)
{
- if (row->entries[col].flags & TABULAR_ENTRY_STR_AVAIL) return;
+ if (row->entries[col].flags & BIT(TABULAR_ENTRY_STR_SET)) return;
row->entries[col].str = cfg->columns[col].to_str(
&row->user, &cfg->columns[col].user);
row->entries[col].ulen = (uint32_t) u8strlen(row->entries[col].str);
- row->entries[col].flags |= TABULAR_ENTRY_STR_AVAIL;
+ row->entries[col].flags |= BIT(TABULAR_ENTRY_STR_SET);
}
diff --git a/src/test.c b/src/test.c
@@ -12,10 +12,10 @@
bool print_style(FILE *file, const struct tabular_cfg *cfg,
const struct tabular_row *row, const struct tabular_col *col);
-char *col_pos_str(const struct tabular_user *user);
+char *col_pos_str(const struct tabular_user *row, const struct tabular_user *col);
bool col_pos_hidden(const struct tabular_user *user);
-char *col_name_str(const struct tabular_user *user);
+char *col_name_str(const struct tabular_user *row, const struct tabular_user *col);
bool col_name_hidden(const struct tabular_user *user);
static const char **argv = NULL;
@@ -50,7 +50,7 @@ static struct tabular_col columns[] = {
.align = TABULAR_ALIGN_LEFT,
- .strategy = TABULAR_SQUASH_WORDAWARE,
+ .strategy = TABULAR_WRAP_WORDAWARE,
.essential = true,
},
};
@@ -101,19 +101,19 @@ print_style(FILE *file, const struct tabular_cfg *cfg,
}
char *
-col_pos_str(const struct tabular_user *user)
+col_pos_str(const struct tabular_user *row, const struct tabular_user *col)
{
char buf[16];
- snprintf(buf, sizeof(buf), "%li", user->id);
+ snprintf(buf, sizeof(buf), "%li", row->id);
return strdup(buf);
}
char *
-col_name_str(const struct tabular_user *user)
+col_name_str(const struct tabular_user *row, const struct tabular_user *col)
{
- return strdup(argv[user->id]);
+ return strdup(argv[row->id]);
}
int
@@ -138,12 +138,13 @@ main(int argc, const char **_argv)
rows = NULL;
end = &rows;
for (i = 0; i < argc; i++) {
- end = tabular_alloc_row(&cfg, &rc, end,
+ *end = tabular_alloc_row(&cfg, &rc,
(struct tabular_user) { .id = (size_t) i });
- if (!end) errx(1, "tabular_append_row %i", rc);
+ if (!*end) errx(1, "tabular_append_row %i", rc);
+ end = &(*end)->next;
}
- rc = tabular_format(stdout, &cfg, &stats, rows);
+ rc = tabular_format(stdout, &cfg, &stats, &rows);
if (rc) errx(1, "tabular_format %i", rc);
printf("\n%lu lines, %lu rows\n",