Implement r_table_uniq as API and query (#16385) ##util

This commit is contained in:
Alexis Ehret 2020-04-08 20:34:05 +02:00 committed by GitHub
parent aac88e2db3
commit 60ee0daa91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 239 additions and 17 deletions

View File

@ -86,10 +86,9 @@ R_API void *r_list_first(const RList *list);
R_API void *r_list_last(const RList *list);
R_API RListIter *r_list_add_sorted(RList *list, void *data, RListComparator cmp);
R_API void r_list_sort(RList *list, RListComparator cmp);
R_API RList *r_list_uniq(const RList *list, RListComparator cmp);
R_API void r_list_merge_sort(RList *list, RListComparator cmp);
R_API void r_list_insertion_sort(RList *list, RListComparator cmp);
R_API RList *r_list_uniq(const RList *list, RListComparator cmp);
R_API void r_list_init(RList *list);
R_API void r_list_delete(RList *list, RListIter *iter);
R_API bool r_list_delete_data(RList *list, void *ptr);

View File

@ -45,13 +45,15 @@ typedef struct {
bool showJSON;
bool showSum;
bool adjustedCols;
void *cons;
void *cons;
} RTable;
typedef void (*RTableSelector)(RTableRow *acc, RTableRow *new_row, int nth);
R_API void r_table_row_free(void *_row);
R_API void r_table_column_free(void *_col);
R_API RTableColumn *r_table_column_clone(RTableColumn *col);
R_API RTableColumnType *r_table_type (const char *name);
R_API RTableColumnType *r_table_type(const char *name);
R_API RTable *r_table_new(void);
R_API void r_table_free(RTable *t);
R_API int r_table_column_nth(RTable *t, const char *name);
@ -67,8 +69,10 @@ R_API char *r_table_tocsv(RTable *t);
R_API char *r_table_tojson(RTable *t);
R_API void r_table_filter(RTable *t, int nth, int op, const char *un);
R_API void r_table_sort(RTable *t, int nth, bool inc);
R_API void r_table_uniq(RTable *t);
R_API void r_table_group(RTable *t, int nth, RTableSelector fcn);
R_API bool r_table_query(RTable *t, const char *q);
R_API void r_table_hide_header (RTable *t);
R_API void r_table_hide_header(RTable *t);
R_API bool r_table_align(RTable *t, int nth, int align);
R_API void r_table_visual_list(RTable *table, RList* list, ut64 seek, ut64 len, int width, bool va);
R_API RTable *r_table_clone(RTable *t);

View File

@ -598,14 +598,85 @@ R_API void r_table_sortlen(RTable *t, int nth, bool dec) {
RTableColumn *col = r_list_get_n (t->cols, nth);
if (col) {
Gnth = nth;
Gcmp = cmplen;
t->rows->sorted = false; //force sorting
r_list_sort (t->rows, Gcmp);
r_list_sort (t->rows, cmplen);
if (dec) {
r_list_reverse (t->rows);
}
Gnth = 0;
Gcmp = NULL;
}
}
static int r_rows_cmp(RList *lhs, RList *rhs, RList *cols, int nth) {
RListIter *iter_lhs;
RListIter *iter_rhs;
RListIter *iter_col;
RTableColumn *item_col;
void *item_lhs;
void *item_rhs;
int tmp;
int i = 0;
for (iter_lhs = lhs->head, iter_rhs = rhs->head, iter_col = cols->head;
iter_lhs && iter_rhs && iter_col;
iter_lhs = iter_lhs->n, iter_rhs = iter_rhs->n, iter_col = iter_col->n) {
item_lhs = iter_lhs->data;
item_rhs = iter_rhs->data;
item_col = iter_col->data;
if (nth == -1 || i == nth) {
tmp = item_col->type->cmp (item_lhs, item_rhs);
if (tmp) {
return tmp;
}
}
++i;
}
if (iter_lhs) {
return 1;
}
if (iter_rhs) {
return -1;
}
return 0;
}
R_API void r_table_uniq(RTable *t) {
r_table_group (t, -1, NULL);
}
R_API void r_table_group(RTable *t, int nth, RTableSelector fcn) {
RListIter *iter;
RListIter *tmp;
RTableRow *row;
RListIter *iter_inner;
RTableRow *uniq_row;
RList *rows = t->rows;
r_list_foreach_safe (rows, iter, tmp, row) {
for (iter_inner = rows->head;
iter_inner && iter_inner != iter;
iter_inner = iter_inner->n) {
uniq_row = iter_inner->data;
if (!r_rows_cmp (uniq_row->items, row->items, t->cols, nth)) {
if (fcn) {
fcn (uniq_row, row, nth);
}
r_list_delete (rows, iter);
break;
}
}
}
}
@ -785,6 +856,8 @@ R_API bool r_table_query(RTable *t, const char *q) {
eprintf (" col0/gt/0x800 grep rows matching col0 > 0x800\n");
eprintf (" col0/lt/0x800 grep rows matching col0 < 0x800\n");
eprintf (" col0/eq/0x800 grep rows matching col0 == 0x800\n");
eprintf (" col0/uniq get the first row of each that col0 is unique\n");
eprintf (" /uniq same as | uniq (match all columns)\n");
eprintf (" name/str/warn grep rows matching col(name).str(warn)\n");
eprintf (" name/strlen/3 grep rows matching strlen(col) == X\n");
eprintf (" name/minlen/3 grep rows matching strlen(col) > X\n");
@ -811,7 +884,7 @@ R_API bool r_table_query(RTable *t, const char *q) {
if (col == -1) {
if (*columnName == '[') {
col = atoi (columnName + 1);
} else {
} else if (columnName == NULL && strcmp (operation, "uniq")) {
eprintf ("Invalid column name (%s) for (%s)\n", columnName, query);
}
}
@ -820,6 +893,8 @@ R_API bool r_table_query(RTable *t, const char *q) {
}
if (!strcmp (operation, "sort")) {
r_table_sort (t, col, operand && !strcmp (operand, "dec"));
} else if (!strcmp (operation, "uniq")) {
r_table_group (t, col, NULL);
} else if (!strcmp (operation, "sortlen")) {
r_table_sortlen (t, col, operand && !strcmp (operand, "dec"));
} else if (!strcmp (operation, "join")) {

View File

@ -106,15 +106,157 @@ bool test_r_table_sort1(void) {
mu_end;
}
bool test_r_table_columns() {
bool test_r_table_uniq(void) {
RTable *t = __table_test_data1 ();
r_table_uniq (t);
char *strd = r_table_tostring (t);
mu_assert_streq (strd,
"ascii code\n"
"----------\n"
"a 97\n"
"b 98\n"
"c 99\n",
"uniq delete nothing");
free (strd);
r_table_add_row (t, "a", "97", NULL);
r_table_add_row (t, "a", "97", NULL);
r_table_add_row (t, "a", "97", NULL);
r_table_add_row (t, "b", "98", NULL);
r_table_add_row (t, "c", "99", NULL);
r_table_add_row (t, "b", "98", NULL);
r_table_add_row (t, "c", "99", NULL);
r_table_add_row (t, "d", "99", NULL);
r_table_add_row (t, "b", "98", NULL);
r_table_add_row (t, "d", "99", NULL);
r_table_add_row (t, "c", "99", NULL);
r_table_add_row (t, "c", "100", NULL);
r_table_uniq (t);
char *stri = r_table_tostring (t);
mu_assert_streq (stri,
"ascii code\n"
"----------\n"
"a 97\n"
"b 98\n"
"c 99\n"
"d 99\n"
"c 100\n",
"uniq delete some rows");
free (stri);
r_table_free (t);
mu_end;
}
static void simple_merge(RTableRow *acc, RTableRow *new_row, int nth) {
RList *lhs = acc->items;
RList *rhs = new_row->items;
RListIter *iter_lhs;
RListIter *iter_rhs;
char *item_lhs;
char *item_rhs;
int tmp;
int i = 0;
for (iter_lhs = lhs->head, iter_rhs = rhs->head;
iter_lhs && iter_rhs;
iter_lhs = iter_lhs->n, iter_rhs = iter_rhs->n) {
item_lhs = iter_lhs->data;
item_rhs = iter_rhs->data;
if (i != nth) {
if (!strcmp (item_lhs, "a")) {
free (iter_lhs->data);
iter_lhs->data = r_str_new ("a | e");
} else if (!strcmp (item_lhs, "b")) {
free (iter_lhs->data);
iter_lhs->data = r_str_new ("b | f");
} else if (!strcmp (item_lhs, "c")) {
free (iter_lhs->data);
iter_lhs->data = r_str_new ("c | h");
} else if (!strcmp (item_lhs, "d")) {
free (iter_lhs->data);
iter_lhs->data = r_str_new ("d | g");
}
}
++i;
}
}
bool test_r_table_group (void) {
RTable *t = __table_test_data1 ();
r_table_group (t, -1, NULL);
char *str = r_table_tostring (t);
mu_assert_streq (str,
"ascii code\n"
"----------\n"
"a 97\n"
"b 98\n"
"c 99\n",
"group delete nothing");
free (str);
r_table_add_row (t, "a", "97", NULL);
r_table_add_row (t, "a", "97", NULL);
r_table_add_row (t, "a", "97", NULL);
r_table_add_row (t, "b", "98", NULL);
r_table_add_row (t, "c", "99", NULL);
r_table_add_row (t, "b", "98", NULL);
r_table_add_row (t, "c", "99", NULL);
r_table_add_row (t, "d", "1", NULL);
r_table_add_row (t, "b", "98", NULL);
r_table_add_row (t, "d", "99", NULL);
r_table_add_row (t, "c", "99", NULL);
r_table_add_row (t, "c", "100", NULL);
r_table_group (t, 0, NULL);
str = r_table_tostring (t);
mu_assert_streq (str,
"ascii code\n"
"----------\n"
"a 97\n"
"b 98\n"
"c 99\n"
"d 1\n",
"group delete some rows");
free (str);
r_table_add_row (t, "e", "97", NULL);
r_table_add_row (t, "f", "98", NULL);
r_table_add_row (t, "g", "99", NULL);
r_table_add_row (t, "h", "1", NULL);
r_table_group (t, 1, simple_merge);
str = r_table_tostring (t);
mu_assert_streq (str,
"ascii code\n"
"----------\n"
"a | e 97\n"
"b | f 98\n"
"c | h 99\n"
"d | g 1\n",
"group delete some rows");
free (str);
r_table_free (t);
mu_end;
}
bool test_r_table_columns () {
RTable *t = NULL;
#define CREATE_TABLE \
r_table_free (t); \
t = r_table_new (); \
r_table_add_column (t, r_table_type ("number"), "name", 0); \
#define CREATE_TABLE \
r_table_free (t); \
t = r_table_new (); \
r_table_add_column (t, r_table_type ("number"), "name", 0); \
r_table_add_column (t, r_table_type ("number"), "address", 0); \
r_table_add_row (t, "hello", "100", NULL); \
r_table_add_row (t, "namings", "20000", NULL); \
r_table_add_row (t, "hello", "100", NULL); \
r_table_add_row (t, "namings", "20000", NULL);
CREATE_TABLE
char *s = r_table_tocsv (t);
@ -175,7 +317,9 @@ bool all_tests() {
mu_run_test(test_r_table_column_type);
mu_run_test(test_r_table_tostring);
mu_run_test(test_r_table_sort1);
mu_run_test(test_r_table_columns);
mu_run_test(test_r_table_uniq);
mu_run_test(test_r_table_group);
mu_run_test (test_r_table_columns);
return tests_passed != tests_run;
}