Fix #20760 - Implement native gron via ~{=} ##shell

This commit is contained in:
pancake 2022-09-19 10:48:44 +02:00 committed by pancake
parent 97c77155f9
commit ec884e6dfa
5 changed files with 192 additions and 9 deletions

View File

@ -2,6 +2,7 @@
#include <r_cons.h>
#include <r_util/r_print.h>
#include <r_util/r_json.h>
#include <sdb.h>
#define I(x) r_cons_singleton ()->x
@ -46,6 +47,7 @@ static const char *help_detail_tilde[] = {
" {}", "", "json indentation",
" {}..", "", "less json indentation",
" {}...", "", "hud json indentation",
" {=}", "", "gron-like output (key=value)",
" {path}", "", "json path grep",
"endmodifier:", "", "",
" $", "", "words must be placed at the end of line",
@ -157,6 +159,9 @@ static void parse_grep_expression(const char *str) {
} else if (r_str_startswith (ptr, "{:..")) {
grep->less = 1;
}
} else if (ptr[1] == '=' && ptr[2] == '}') {
grep->gron = true;
ptr += 2;
} else if (ptr[1] == '}') {
// standard json indentation
grep->json = 1;
@ -404,17 +409,16 @@ static char *find_next_intgrep(char *cmd, const char *quotes) {
* with reshaped grep expression.
*/
static char *preprocess_filter_expr(char *cmd, const char *quotes) {
char *p1, *p2, *ns = NULL;
char *p2, *ns = NULL;
const char *strsep = "&";
int len;
int i;
p1 = find_next_intgrep (cmd, quotes);
char *p1 = find_next_intgrep (cmd, quotes);
if (!p1) {
return NULL;
}
len = strlen (p1);
int len = strlen (p1);
if (len > 4 && r_str_endswith (p1, "~?") && p1[len - 3] != '\\') {
p1[len - 2] = '\0';
ns = r_str_append (ns, "?");
@ -504,10 +508,68 @@ static int cmp(const void *a, const void *b) {
return strcmp (a, b);
}
static bool gron(RStrBuf *sb, RJson *node, const char *root) {
if (!sb || !node || !root) {
return false;
}
switch (node->type) {
case R_JSON_ARRAY:
{
RJson *cn = node->children.first;
int n = 0;
r_strbuf_appendf (sb, "%s = [];\n", root);
while (cn) {
char *newroot = r_str_newf ("%s[%d]", root, n);
gron (sb, cn, newroot);
free (newroot);
cn = cn->next;
n++;
}
}
break;
case R_JSON_OBJECT:
{
RJson *cn = node->children.first;
r_strbuf_appendf (sb, "%s = {};\n", root);
while (cn) {
char *newroot = r_str_newf ("%s.%s", root, cn->key);
gron (sb, cn, newroot);
cn = cn->next;
}
}
break;
case R_JSON_STRING:
{
size_t l = strlen (node->str_value);
char *estr = r_str_encoded_json (node->str_value, l, PJ_ENCODING_STR_DEFAULT);
r_strbuf_appendf (sb, "%s = \"%s\";\n", root, estr);
free (estr);
}
break;
case R_JSON_BOOLEAN:
r_strbuf_appendf (sb, "%s = %s;\n", root, r_str_bool (node->num.u_value));
break;
case R_JSON_INTEGER:
r_strbuf_appendf (sb, "%s = %"PFMT64d";\n", root, node->num.u_value);
break;
case R_JSON_NULL:
r_strbuf_appendf (sb, "%s = null;\n", root);
break;
case R_JSON_DOUBLE:
r_strbuf_appendf (sb, "%s = %lf;\n", root, node->num.dbl_value);
break;
break;
default:
eprintf ("unk %s\n", r_json_type (node));
break;
}
return true;
}
R_API void r_cons_grepbuf(void) {
RCons *cons = r_cons_singleton ();
const char *buf = cons->context->buffer;
const int len = cons->context->buffer_len;
size_t len = cons->context->buffer_len;
RConsGrep *grep = &cons->context->grep;
const char *in = buf;
int ret, total_lines = 0, l = 0, tl = 0;
@ -542,9 +604,9 @@ R_API void r_cons_grepbuf(void) {
}
if ((!len || !buf || !*buf) && (grep->json || grep->less)) {
grep->json = 0;
grep->json = false;
grep->hud = false;
grep->less = 0;
grep->hud = 0;
return;
}
if (grep->ascart) {
@ -573,6 +635,23 @@ R_API void r_cons_grepbuf(void) {
free (sin);
return;
}
if (grep->gron) {
char *a = strdup (cons->context->buffer);
RJson *node = r_json_parse (a);
RStrBuf *sb = r_strbuf_new ("");
gron (sb, node, "json");
char *s = r_strbuf_drain (sb);
R_FREE (cons->context->buffer);
cons->context->buffer_len = 0;
cons->context->buffer_sz = 0;
r_cons_print (s);
buf = cons->context->buffer;
len = cons->context->buffer_len;
goto continuation;
r_json_free (node);
free (a);
return;
}
if (grep->json) {
if (grep->json_path) {
char *u = sdb_json_get_str (cons->context->buffer, grep->json_path);
@ -643,7 +722,9 @@ R_API void r_cons_grepbuf(void) {
}
return;
}
RStrBuf *ob = r_strbuf_new ("");
RStrBuf *ob = NULL;
continuation:
ob = r_strbuf_new ("");
// if we modify cons->lines we should update I.context->buffer too
cons->lines = 0;
// used to count lines and change negative grep.line values

View File

@ -91,7 +91,8 @@ typedef struct r_cons_grep_t {
int less;
bool hud;
bool human;
int json;
bool gron;
bool json;
char *json_path;
int range_line;
int line;

View File

@ -57,6 +57,7 @@ R_API R_MUSTUSE RJson *r_json_parse(R_BORROW char *text);
R_API void r_json_free(RJson *js);
R_API const RJson *r_json_get(const RJson *json, const char *key); // get object's property by key
R_API const RJson *r_json_item(const RJson *json, size_t idx); // get array element by index
R_API const char *r_json_type(const RJson *json);
#ifdef __cplusplus
}

View File

@ -398,3 +398,22 @@ R_API const RJson *r_json_item(const RJson *json, size_t idx) {
return NULL;
}
R_API const char *r_json_type(const RJson *json) {
switch (json->type) {
case R_JSON_ARRAY:
return "array";
case R_JSON_OBJECT:
return "object";
case R_JSON_INTEGER:
return "integer";
case R_JSON_BOOLEAN:
return "boolean";
case R_JSON_DOUBLE:
return "double";
case R_JSON_STRING:
return "string";
case R_JSON_NULL:
return "null";
}
return "";
}

View File

@ -543,3 +543,84 @@ EXPECT=<<EOF
fd
EOF
RUN
NAME=ij.gron
FILE=bins/elf/crackme
CMDS=<<EOF
ij~{=}
EOF
EXPECT=<<EOF
json = {};
json.core = {};
json.core.type = "EXEC (Executable file)";
json.core.file = "bins/elf/crackme";
json.core.fd = 3;
json.core.size = 7441;
json.core.humansz = "7.3K";
json.core.iorw = false;
json.core.mode = "r-x";
json.core.minopsz = 1;
json.core.maxopsz = 16;
json.core.invopsz = 1;
json.core.block = 256;
json.core.format = "elf64";
json.bin = {};
json.bin.arch = "x86";
json.bin.baddr = 4194304;
json.bin.binsz = 7441;
json.bin.bintype = "elf";
json.bin.bits = 64;
json.bin.canary = false;
json.bin.class = "ELF64";
json.bin.compiled = "";
json.bin.compiler = "GCC: (Debian 4.4.5-8) 4.4.5";
json.bin.crypto = false;
json.bin.dbg_file = "";
json.bin.endian = "little";
json.bin.havecode = true;
json.bin.guid = "";
json.bin.intrp = "/lib64/ld-linux-x86-64.so.2";
json.bin.laddr = 0;
json.bin.lang = "c";
json.bin.linenum = true;
json.bin.lsyms = true;
json.bin.machine = "AMD x86-64 architecture";
json.bin.nx = true;
json.bin.os = "linux";
json.bin.cc = "";
json.bin.pic = false;
json.bin.relocs = true;
json.bin.relro = "no";
json.bin.rpath = "NONE";
json.bin.sanitize = false;
json.bin.static = false;
json.bin.stripped = false;
json.bin.subsys = "linux";
json.bin.va = true;
json.bin.checksums = {};
EOF
RUN
NAME=ij.gron.grep
FILE=bins/elf/crackme
CMDS=<<EOF
ij~{=}opsz
EOF
EXPECT=<<EOF
json.core.minopsz = 1;
json.core.maxopsz = 16;
json.core.invopsz = 1;
EOF
RUN
NAME=ij.gron.grep.two
FILE=bins/elf/crackme
CMDS=<<EOF
ij~{=}~opsz
EOF
EXPECT=<<EOF
json.core.minopsz = 1;
json.core.maxopsz = 16;
json.core.invopsz = 1;
EOF
RUN