mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-11 23:16:05 +00:00
Implement r_table_uniq as API and query (#16385) ##util
This commit is contained in:
parent
aac88e2db3
commit
60ee0daa91
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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")) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user