tbl->column_count = col_count;
- // FIXME: Why? Better check if tbl->callbacks is NULL.
- if(tbl->callbacks->row_output_func == NULL && tbl->callbacks->table_start_callback == NULL && tbl->callbacks->table_end_callback == NULL) {
- tbl->callbacks = &table_fmt_human_readable;
+ if(!tbl->formatter) {
+ tbl->formatter = &table_fmt_human_readable;
}
tbl->print_header = 1; // by default, print header
if(tbl->column_order == NULL) table_make_default_column_order(tbl);
- if(tbl->callbacks->table_start_callback != NULL) tbl->callbacks->table_start_callback(tbl);
+ if(tbl->formatter->table_start != NULL) tbl->formatter->table_start(tbl);
if(tbl->cols_to_output == 0) {
// FIXME: Why?
die("Table should output at least one column.");
mp_restore(tbl->pool, &tbl->pool_state);
- if(tbl->callbacks->table_end_callback) tbl->callbacks->table_end_callback(tbl);
+ if(tbl->formatter->table_end) tbl->formatter->table_end(tbl);
}
/*** Configuration ***/
-void table_set_output_callbacks(struct table *tbl, struct table_output_callbacks *callbacks)
+void table_set_formatter(struct table *tbl, struct table_formatter *fmt)
{
- tbl->callbacks = callbacks;
+ tbl->formatter = fmt;
}
int table_get_col_idx(struct table *tbl, const char *col_name)
{
if(tbl->column_count == 0) return NULL;
+ // FIXME: This does not work! The start of the string may be reallocated later.
char *tmp = mp_printf(tbl->pool, "%s", tbl->columns[0].name);
for(int i = 1; i < tbl->column_count; i++) {
void table_end_row(struct table *tbl)
{
- if(tbl->callbacks->row_output_func) {
- tbl->callbacks->row_output_func(tbl);
- } else {
- die("Tableprinter: invalid parameter, struct table does not have filled row_output_func");
- }
+ ASSERT(tbl->formatter->row_output);
+ tbl->formatter->row_output(tbl);
memset(tbl->col_str_ptrs, 0, sizeof(char *) * tbl->column_count);
mp_restore(tbl->pool, &tbl->pool_state);
tbl->last_printed_col = -1;
/*** Option parsing ***/
-static int get_colon(char *str)
-{
- int l = strlen(str);
- for(int i = 0; i < l; i++) {
- if(str[i] == ':') return i;
- }
- return -1;
-}
-
-static const char *table_set_option2(struct table *tbl, const char *key, const char *value)
+const char *table_set_option_value(struct table *tbl, const char *key, const char *value)
{
+ // Options with no value
if(value == NULL || (value != NULL && strlen(value) == 0)) {
if(strcmp(key, "noheader") == 0) {
tbl->print_header = 0;
return NULL;
- } else {
- int rv = 1;
- if(tbl->callbacks && tbl->callbacks->process_option) rv = tbl->callbacks->process_option(tbl, key, value);
- if(rv) {
- return mp_printf(tbl->pool, "Tableprinter: invalid option: '%s'.", key);
- }
}
- } else {
+ }
+
+ // Options with a value
+ if(value) {
if(strcmp(key, "header") == 0) {
// FIXME: Check syntax of value.
//tbl->print_header = strtol(value, NULL, 10); //atoi(value);
}
return NULL;
} else if(strcmp(key, "fmt") == 0) {
- if(strcmp(value, "human") == 0) table_set_output_callbacks(tbl, &table_fmt_human_readable);
- else if(strcmp(value, "machine") == 0) table_set_output_callbacks(tbl, &table_fmt_machine_readable);
+ if(strcmp(value, "human") == 0) table_set_formatter(tbl, &table_fmt_human_readable);
+ else if(strcmp(value, "machine") == 0) table_set_formatter(tbl, &table_fmt_machine_readable);
else {
return "Tableprinter: invalid argument to output-type option.";
}
char * d = mp_printf(tbl->pool, "%s", value);
tbl->col_delimiter = d;
return NULL;
- } else {
- int rv = 1;
- if(tbl->callbacks && tbl->callbacks->process_option) rv = tbl->callbacks->process_option(tbl, key, value);
- if(rv) {
- return mp_printf(tbl->pool, "Tableprinter: invalid option: '%s:%s'.", key, value);
- }
}
}
- return NULL;
+
+ // Formatter options
+ if(tbl->formatter && tbl->formatter->process_option) {
+ const char *err = NULL;
+ if (tbl->formatter->process_option(tbl, key, value, &err)) {
+ return err;
+ }
+ }
+
+ // Unrecognized option
+ return mp_printf(tbl->pool, "Tableprinter: invalid option: '%s%s%s'.", key, (value ? ":" : ""), (value ? : ""));
}
const char *table_set_option(struct table *tbl, const char *opt)
{
- char *opt_dup = stk_strdup(opt);
- int colidx = get_colon(opt_dup);
- if(colidx > 0) opt_dup[colidx] = 0;
- char *key = opt_dup;
- char *value = NULL;
- if(colidx > 0) value = opt_dup + colidx + 1;
- return table_set_option2(tbl, key, value);
+ char *key = stk_strdup(opt);
+ char *value = strchr(key, ':');
+ if(value) {
+ *value++ = 0;
+ }
+ return table_set_option_value(tbl, key, value);
}
const char *table_set_gary_options(struct table *tbl, char **gary_table_opts)
{
for (uint i = 0; i < GARY_SIZE(gary_table_opts); i++) {
const char *rv = table_set_option(tbl, gary_table_opts[i]);
- if (rv != NULL) {
+ if(rv != NULL) {
return rv;
}
}
return NULL;
}
-/*** Default formatter for human-readble output ***/
+/*** Default formatter for human-readable output ***/
-static int table_oneline_human_readable(struct table *tbl)
+static void table_row_human_readable(struct table *tbl)
{
uint col = tbl->column_order[0];
int col_width = tbl->columns[col].width;
}
bputc(tbl->out, '\n');
- return 0;
}
static void table_write_header(struct table *tbl)
bputc(tbl->out, '\n');
}
-static int table_start_human_readable(struct table *tbl)
+static void table_start_human_readable(struct table *tbl)
{
if(tbl->col_delimiter == NULL) {
tbl->col_delimiter = " ";
tbl->print_header = 0;
table_write_header(tbl);
}
- return 0;
-}
-
-static int table_end_human_readable(struct table *tbl UNUSED)
-{
- return 0;
}
-struct table_output_callbacks table_fmt_human_readable = {
- .row_output_func = table_oneline_human_readable,
- .table_start_callback = table_start_human_readable,
- .table_end_callback = table_end_human_readable,
+struct table_formatter table_fmt_human_readable = {
+ .row_output = table_row_human_readable,
+ .table_start = table_start_human_readable,
};
/*** Default formatter for machine-readable output ***/
-static int table_oneline_machine_readable(struct table *tbl)
+static void table_row_machine_readable(struct table *tbl)
{
uint col = tbl->column_order[0];
bputs(tbl->out, tbl->col_str_ptrs[col]);
}
bputc(tbl->out, '\n');
- return 0;
}
-static int table_start_machine_readable(struct table *tbl)
+static void table_start_machine_readable(struct table *tbl)
{
if(tbl->col_delimiter == NULL) {
tbl->col_delimiter = ";";
}
bputc(tbl->out, '\n');
}
- return 0;
-}
-
-static int table_end_machine_readable(struct table *tbl UNUSED)
-{
- return 0;
}
-struct table_output_callbacks table_fmt_machine_readable = {
- .row_output_func = table_oneline_machine_readable,
- .table_start_callback = table_start_machine_readable,
- .table_end_callback = table_end_machine_readable,
+struct table_formatter table_fmt_machine_readable = {
+ .row_output = table_row_machine_readable,
+ .table_start = table_start_machine_readable,
};
/*** Tests ***/
#define TBL_COL_DELIMITER(_delimiter_) .col_delimiter = _delimiter_
#define TBL_APPEND_DELIMITER(_delimiter_) .append_delimiter = _delimiter_
-#define TBL_OUTPUT_HUMAN_READABLE .callbacks = &table_fmt_human_readable
-#define TBL_OUTPUT_MACHINE_READABLE .callbacks = &table_fmt_machine_readable
+#define TBL_OUTPUT_HUMAN_READABLE .formatter = &table_fmt_human_readable
+#define TBL_OUTPUT_MACHINE_READABLE .formatter = &table_fmt_machine_readable
/***
* [[ Usage ]]
enum column_type type; // Type of the cells in the column
};
-struct table_output_callbacks {
- int (*row_output_func)(struct table *tbl); // [*] Function that outputs one row
- int (*table_start_callback)(struct table *tbl); // [*] table_start callback
- int (*table_end_callback)(struct table *tbl); // [*] table_end callback
- // FIXME: Int -> void?
- int (*process_option)(struct table *tbl, const char *key, const char *value);
- // FIXME: Shouldn't it be possible to return also a custom error string? For example in an optionally writeable `const char **' argument.
-};
-
/** The definition of a table. Contains column definitions plus internal data. */
struct table {
struct table_column *columns; // [*] Definition of columns
int col_out; // Index of the column that is currently printed using fb_col_out
// Back-end used for table formatting and its private data
- struct table_output_callbacks *callbacks;
+ struct table_formatter *formatter;
void *data;
};
void table_col_fbend(struct table *tbl);
/**
- * Sets the callbacks in @tbl. The callbacks are stored the arg @callbacks.
+ * Sets table formatter for @tbl.
**/
-void table_set_output_callbacks(struct table *tbl, struct table_output_callbacks *callbacks);
+void table_set_formatter(struct table *tbl, struct table_formatter *fmt);
+
+/** Definition of a formatter back-end. **/
+struct table_formatter {
+ void (*row_output)(struct table *tbl); // [*] Function that outputs one row
+ void (*table_start)(struct table *tbl); // [*] table_start callback (optional)
+ void (*table_end)(struct table *tbl); // [*] table_end callback (optional)
+ bool (*process_option)(struct table *tbl, const char *key, const char *value, const char **err);
+ // [*] Process table option and possibly return an error message (optional)
+};
+// Standard formatters
+extern struct table_formatter table_fmt_human_readable;
+extern struct table_formatter table_fmt_machine_readable;
/**
* Process the table one option and sets the values in @tbl according to the command-line parameters.
* Returns NULL on success or an error string otherwise.
**/
const char *table_set_option(struct table *tbl, const char *opt);
+const char *table_set_option_value(struct table *tbl, const char *key, const char *value);
const char *table_set_gary_options(struct table *tbl, char **gary_table_opts);
-// Standard formatters
-extern struct table_output_callbacks table_fmt_human_readable;
-extern struct table_output_callbacks table_fmt_machine_readable;
-
#define TABLE_SET_COL_PROTO(_name_, _type_) void table_set_##_name_(struct table *tbl, int col, _type_ val);\
void table_set_##_name_##_name(struct table *tbl, const char *col_name, _type_ val);\
void table_set_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val) FORMAT_CHECK(printf, 3, 0);