From 57a86f9bff68f24b167df9c571a09c6b89712296 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 20 May 2014 15:04:11 +0200 Subject: [PATCH] libsmartcols: add scols_sort_table() * add pointer to column cmp() function [scols_column_set_cmpfunc()] * allow to store per-cell application private data (to make it possible to sort tables on data independent on cell output data) [scols_cell_set_userdata() ...] * make it possible to access line cell by column [scols_line_get_column_cell()] Sort and cmp() stuff based on patches from Shakur Shams Mullick. Co-Author: Shakur Shams Mullick Signed-off-by: Shakur Shams Mullick Signed-off-by: Karel Zak Signed-off-by: Karel Zak --- libsmartcols/docs/libsmartcols-sections.txt | 6 ++ libsmartcols/src/cell.c | 66 ++++++++++++++++++++- libsmartcols/src/column.c | 24 ++++++++ libsmartcols/src/libsmartcols.h.in | 15 +++++ libsmartcols/src/libsmartcols.sym | 6 ++ libsmartcols/src/line.c | 19 ++++++ libsmartcols/src/smartcolsP.h | 6 ++ libsmartcols/src/table.c | 39 ++++++++++++ 8 files changed, 179 insertions(+), 2 deletions(-) diff --git a/libsmartcols/docs/libsmartcols-sections.txt b/libsmartcols/docs/libsmartcols-sections.txt index 307691e00..b07774783 100644 --- a/libsmartcols/docs/libsmartcols-sections.txt +++ b/libsmartcols/docs/libsmartcols-sections.txt @@ -4,9 +4,12 @@ libscols_cell scols_cell_copy_content scols_cell_get_color scols_cell_get_data +scols_cell_get_userdata scols_cell_refer_data scols_cell_set_color scols_cell_set_data +scols_cell_set_userdata +scols_cmpstr_cells scols_reset_cell @@ -22,6 +25,7 @@ scols_column_is_right scols_column_is_strict_width scols_column_is_tree scols_column_is_trunc +scols_column_set_cmpfunc scols_column_set_color scols_column_set_flags scols_column_set_whint @@ -49,6 +53,7 @@ scols_line_alloc_cells scols_line_free_cells scols_line_get_cell scols_line_get_color +scols_line_get_column_cell scols_line_get_ncells scols_line_get_parent scols_line_get_userdata @@ -118,6 +123,7 @@ scols_table_set_column_separator scols_table_set_line_separator scols_table_set_stream scols_table_set_symbols +scols_sort_table scols_unref_table diff --git a/libsmartcols/src/cell.c b/libsmartcols/src/cell.c index d73a1f808..1d2ab5838 100644 --- a/libsmartcols/src/cell.c +++ b/libsmartcols/src/cell.c @@ -55,7 +55,7 @@ int scols_reset_cell(struct libscols_cell *ce) /** * scols_cell_set_data: * @ce: a pointer to a struct libscols_cell instance - * @str: user data + * @str: data (used for scols_printtable()) * * Stores a copy of the @str in @ce. * @@ -82,7 +82,7 @@ int scols_cell_set_data(struct libscols_cell *ce, const char *str) /** * scols_cell_refer_data: * @ce: a pointer to a struct libscols_cell instance - * @str: user data + * @str: data (used for scols_printtable()) * * Adds a reference to @str to @ce. The pointer is deallocated by * scols_reset_cell() or scols_unref_line(). This function is mostly designed @@ -114,6 +114,66 @@ const char *scols_cell_get_data(const struct libscols_cell *ce) return ce ? ce->data : NULL; } +/** + * scols_cell_set_userdata: + * @ce: a pointer to a struct libscols_cell instance + * @data: private user data + * + * Returns: 0, a negative value in case of an error. + */ +int scols_cell_set_userdata(struct libscols_cell *ce, void *data) +{ + assert(ce); + + if (!ce) + return -EINVAL; + ce->userdata = data; + return 0; +} + +/** + * scols_cell_get_userdata + * + * @ce: a pointer to a struct libscols_cell instance + * + * Returns: user data + */ +void *scols_cell_get_userdata(struct libscols_cell *ce) +{ + return ce ? ce->userdata : NULL; +} + +/** + * scols_cmpstr_cells: + * @a: pointer to cell + * @b: pointer to cell + * + * Compares cells data by strcmp(). The function is designed for + * scols_column_set_cmpfunc() and scols_sort_table(). + * + * Returns: follows strcmp() return values. + */ +int scols_cmpstr_cells(struct libscols_cell *a, + struct libscols_cell *b, + __attribute__((__unused__)) void *data) +{ + const char *adata, *bdata; + + if (a == b) + return 0; + + adata = scols_cell_get_data(a); + bdata = scols_cell_get_data(b); + + if (adata == NULL && bdata == NULL) + return 0; + if (adata == NULL) + return -1; + if (bdata == NULL) + return 1; + return strcmp(adata, bdata); +} + /** * scols_cell_set_color: * @ce: a pointer to a struct libscols_cell instance @@ -179,5 +239,7 @@ int scols_cell_copy_content(struct libscols_cell *dest, rc = scols_cell_set_data(dest, scols_cell_get_data(src)); if (!rc) rc = scols_cell_set_color(dest, scols_cell_get_color(src)); + if (!rc) + dest->userdata = src->userdata; return rc; } diff --git a/libsmartcols/src/column.c b/libsmartcols/src/column.c index a8f117f85..130a729e2 100644 --- a/libsmartcols/src/column.c +++ b/libsmartcols/src/column.c @@ -238,6 +238,30 @@ const char *scols_column_get_color(struct libscols_column *cl) return cl ? cl->color : NULL; } + +/** + * scols_column_set_cmpfunc: + * @cl: column + * @cmp: pointer to compare function + * @data: private data for cmp function + * + * Returns: 0, a negative value in case of an error. + */ +int scols_column_set_cmpfunc(struct libscols_column *cl, + int (*cmp)(struct libscols_cell *, + struct libscols_cell *, + void *), + void *data) +{ + assert(cl); + if (!cl) + return -EINVAL; + + cl->cmpfunc = cmp; + cl->cmpfunc_data = data; + return 0; +} + /** * scols_column_is_trunc: * @cl: a pointer to a struct libscols_column instance diff --git a/libsmartcols/src/libsmartcols.h.in b/libsmartcols/src/libsmartcols.h.in index 9468226f2..e61256022 100644 --- a/libsmartcols/src/libsmartcols.h.in +++ b/libsmartcols/src/libsmartcols.h.in @@ -116,6 +116,11 @@ extern const char *scols_cell_get_data(const struct libscols_cell *ce); extern int scols_cell_set_color(struct libscols_cell *ce, const char *color); extern const char *scols_cell_get_color(const struct libscols_cell *ce); +extern void *scols_cell_get_userdata(struct libscols_cell *ce); +extern int scols_cell_set_userdata(struct libscols_cell *ce, void *data); + +extern int scols_cmpstr_cells(struct libscols_cell *a, + struct libscols_cell *b, void *data); /* column.c */ extern int scols_column_is_tree(struct libscols_column *cl); extern int scols_column_is_trunc(struct libscols_column *cl); @@ -135,6 +140,11 @@ extern struct libscols_cell *scols_column_get_header(struct libscols_column *cl) extern int scols_column_set_color(struct libscols_column *cl, const char *color); extern const char *scols_column_get_color(struct libscols_column *cl); +extern int scols_column_set_cmpfunc(struct libscols_column *cl, + int (*cmp)(struct libscols_cell *a, + struct libscols_cell *b, void *), + void *data); + /* line.c */ extern struct libscols_line *scols_new_line(void); extern void scols_ref_line(struct libscols_line *ln); @@ -153,6 +163,9 @@ extern int scols_line_set_color(struct libscols_line *ln, const char *color); extern const char *scols_line_get_color(struct libscols_line *ln); extern size_t scols_line_get_ncells(struct libscols_line *ln); extern struct libscols_cell *scols_line_get_cell(struct libscols_line *ln, size_t n); +extern struct libscols_cell *scols_line_get_column_cell( + struct libscols_line *ln, + struct libscols_column *cl); extern int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data); extern int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data); extern struct libscols_line *scols_copy_line(struct libscols_line *ln); @@ -203,6 +216,8 @@ extern int scols_table_set_stream(struct libscols_table *tb, FILE *stream); extern FILE *scols_table_get_stream(struct libscols_table *tb); extern int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce); +extern int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl); + /* table_print.c */ extern int scols_print_table(struct libscols_table *tb); extern int scols_print_table_to_string(struct libscols_table *tb, char **data); diff --git a/libsmartcols/src/libsmartcols.sym b/libsmartcols/src/libsmartcols.sym index 4b64f280c..a4de524f4 100644 --- a/libsmartcols/src/libsmartcols.sym +++ b/libsmartcols/src/libsmartcols.sym @@ -6,9 +6,12 @@ global: scols_cell_copy_content; scols_cell_get_color; scols_cell_get_data; + scols_cell_get_userdata; scols_cell_refer_data; scols_cell_set_color; scols_cell_set_data; + scols_cell_set_userdata; + scols_cmpstr_cells; scols_column_get_color; scols_column_get_flags; scols_column_get_header; @@ -18,6 +21,7 @@ global: scols_column_is_strict_width; scols_column_is_tree; scols_column_is_trunc; + scols_column_set_cmpfunc; scols_column_set_color; scols_column_set_flags; scols_column_set_whint; @@ -34,6 +38,7 @@ global: scols_line_free_cells; scols_line_get_cell; scols_line_get_color; + scols_line_get_column_cell; scols_line_get_ncells; scols_line_get_parent; scols_line_get_userdata; @@ -58,6 +63,7 @@ global: scols_ref_table; scols_reset_cell; scols_reset_iter; + scols_sort_table; scols_symbols_set_branch; scols_symbols_set_right; scols_symbols_set_vertical; diff --git a/libsmartcols/src/line.c b/libsmartcols/src/line.c index 32c8964ad..611209081 100644 --- a/libsmartcols/src/line.c +++ b/libsmartcols/src/line.c @@ -354,6 +354,25 @@ struct libscols_cell *scols_line_get_cell(struct libscols_line *ln, return &ln->cells[n]; } +/** + * scols_line_get_column_cell: + * @ln: a pointer to a struct libscols_line instance + * @cl: pointer to cell + * + * Like scols_line_get_cell() by cell is referenced by column. + * + * Returns: the @n-th cell in @ln, NULL in case of an error. + */ +struct libscols_cell *scols_line_get_column_cell( + struct libscols_line *ln, + struct libscols_column *cl) +{ + assert(ln); + assert(cl); + + return scols_line_get_cell(ln, cl->seqnum); +} + /** * scols_line_set_data: * @ln: a pointer to a struct libscols_cell instance diff --git a/libsmartcols/src/smartcolsP.h b/libsmartcols/src/smartcolsP.h index ebdc9295f..613ddd587 100644 --- a/libsmartcols/src/smartcolsP.h +++ b/libsmartcols/src/smartcolsP.h @@ -63,6 +63,7 @@ struct libscols_symbols { struct libscols_cell { char *data; char *color; + void *userdata; }; @@ -83,6 +84,11 @@ struct libscols_column { int is_extreme; char *color; /* default column color */ + int (*cmpfunc)(struct libscols_cell *, + struct libscols_cell *, + void *); /* cells comparison function */ + void *cmpfunc_data; + struct libscols_cell header; struct list_head cl_columns; }; diff --git a/libsmartcols/src/table.c b/libsmartcols/src/table.c index d4c61eea3..a51a84abc 100644 --- a/libsmartcols/src/table.c +++ b/libsmartcols/src/table.c @@ -977,3 +977,42 @@ char *scols_table_get_line_separator(struct libscols_table *tb) return tb->linesep; } + +static int cells_cmp_wrapper(struct list_head *a, struct list_head *b, void *data) +{ + struct libscols_column *cl = (struct libscols_column *) data; + struct libscols_line *ra, *rb; + struct libscols_cell *ca, *cb; + + assert(a); + assert(b); + assert(cl); + + ra = list_entry(a, struct libscols_line, ln_lines); + rb = list_entry(b, struct libscols_line, ln_lines); + ca = scols_line_get_cell(ra, cl->seqnum); + cb = scols_line_get_cell(rb, cl->seqnum); + + return cl->cmpfunc(ca, cb, cl->cmpfunc_data); +} + +/** + * scols_sort_table: + * @tb: table + * @cl: order by this column + * + * Orders the table by the column. See also scols_column_set_cmpfunc(). + * + * Returns: 0, a negative value in case of an error. + */ +int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl) +{ + assert(tb); + assert(cl); + + if (!tb || !cl) + return -EINVAL; + + list_sort(&tb->tb_lines, cells_cmp_wrapper, cl); + return 0; +}