From 41d6e9edde82afd4172629f533f5f7c128238bdd Mon Sep 17 00:00:00 2001 From: pancake Date: Tue, 4 Oct 2016 14:34:06 +0200 Subject: [PATCH] Add bash autocompletion support --- binr/rabin2/rabin2.c | 12 ++- binr/radare2/radare2.c | 21 ++++- doc/bash_autocompletion.sh | 187 +++++++++++++++++++++++++++++++++++++ libr/bin/bin.c | 87 ++++++++++------- libr/config/config.c | 5 + libr/core/cmd_debug.c | 8 +- libr/core/cmd_eval.c | 5 +- libr/core/config.c | 5 +- libr/debug/plugin.c | 12 ++- libr/include/r_debug.h | 2 +- 10 files changed, 297 insertions(+), 47 deletions(-) create mode 100644 doc/bash_autocompletion.sh diff --git a/binr/rabin2/rabin2.c b/binr/rabin2/rabin2.c index 340ce5e59a..38d9b5c326 100644 --- a/binr/rabin2/rabin2.c +++ b/binr/rabin2/rabin2.c @@ -652,7 +652,11 @@ int main(int argc, char **argv) { case 'v': return blob_version ("rabin2"); case 'L': bin->cb_printf = (PrintfCallback)printf; - r_bin_list (bin, rad == R_CORE_BIN_JSON); + if (rad) { + r_bin_list (bin, 'q'); + } else { + r_bin_list (bin, rad == R_CORE_BIN_JSON); + } return 1; case 'G': laddr = r_num_math (NULL, optarg); @@ -926,7 +930,11 @@ int main(int argc, char **argv) { // List fatmach0 sub-binaries, etc if (action & R_BIN_REQ_LISTARCHS || ((arch || bits || arch_name) && !r_bin_select (bin, arch, bits, arch_name))) { - r_bin_list_archs (bin, (rad == R_CORE_BIN_JSON)? 'j': 1); + if (rad == R_CORE_BIN_SIMPLEST || rad == R_CORE_BIN_SIMPLE) { + r_bin_list_archs (bin, 'q'); + } else { + r_bin_list_archs (bin, (rad == R_CORE_BIN_JSON)? 'j': 1); + } actions_done++; free (arch_name); } diff --git a/binr/radare2/radare2.c b/binr/radare2/radare2.c index 613d93eeaa..168dff621c 100644 --- a/binr/radare2/radare2.c +++ b/binr/radare2/radare2.c @@ -468,10 +468,19 @@ int main(int argc, char **argv, char **envp) { case 'D': debug = 2; debugbackend = optarg; + if (!strcmp (optarg, "?")) { + r_debug_plugin_list (r.dbg, 'q'); + r_cons_flush(); + return 0; + } break; case 'e': - r_config_eval (r.config, optarg); - r_list_append (evals, optarg); + if (!strcmp (optarg, "q")) { + r_core_cmd0 (&r, "eq"); + } else { + r_config_eval (r.config, optarg); + r_list_append (evals, optarg); + } break; case 'f': fullfile = 1; break; case 'F': forcebin = optarg; break; @@ -509,7 +518,13 @@ int main(int argc, char **argv, char **envp) { case 'n': run_anal--; break; case 'N': run_rc = 0; break; case 'p': - r_config_set (r.config, "file.project", optarg); + if (!strcmp (optarg, "?")) { + r_core_project_list (&r, 0); + r_cons_flush (); + return 0; + } else { + r_config_set (r.config, "file.project", optarg); + } break; case 'P': patchfile = optarg; diff --git a/doc/bash_autocompletion.sh b/doc/bash_autocompletion.sh new file mode 100644 index 0000000000..ec5b1b0f18 --- /dev/null +++ b/doc/bash_autocompletion.sh @@ -0,0 +1,187 @@ +#!/bin/bash + +_r2 () { + local cur + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + prv=${COMP_WORDS[COMP_CWORD-1]} + case "$prv" in + -a) + COMPREPLY=( $(compgen -W "$(rasm2 -qL)" -- $cur)) + return 0 + ;; + -b) + COMPREPLY=( $(compgen -W "8 16 32 64" -- $cur )) + return 0 + ;; + -o) + COMPREPLY=( $(compgen -W "$(r2 -qc 'e asm.os=?' --)" -- $cur )) + return 0 + ;; + -e) + COMPREPLY=( $(compgen -W "$(r2 -qceq --)" -- $cur )) + return 0 + ;; + -F) + COMPREPLY=( $(compgen -W "$(rabin2 -qL)" -- $cur )) + return 0 + ;; + -H) + COMPREPLY=( $(compgen -W "$(r2 -H |cut -d = -f 1)" -- $cur)) + return 0 + ;; + -p) + COMPREPLY=( $(compgen -W "$(r2 -p?)" -- $cur )) + return 0 + ;; + -D) + COMPREPLY=( $(compgen -W "$(r2 -D?)" -- $cur )) + return 0 + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W '-0 -a -A -b -B -c -C -d -D -e -f -F -h -hh -H -i -I -k -l -L -m -M -n -nn -N -o -q -p -P -R -s -S -t -u -v -V -w -z -zz' -- $cur)) + ;; + *) + COMPREPLY=( $(compgen -f -- $cur)) + ;; + esac + + return 0 +} + +complete -F _r2 -o filenames r2 +complete -F _r2 -o filenames radare2 + +_rasm2 () { + local cur + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + prv=${COMP_WORDS[COMP_CWORD-1]} + case "$prv" in + -a) + COMPREPLY=( $(compgen -W "$(rasm2 -qL)" -- $cur)) + return 0 + ;; + -b) + COMPREPLY=( $(compgen -W "8 16 32 64" -- $cur )) + return 0 + ;; + -c) + # TODO. grab -a and get asm.cpu=? output + return 0 + ;; + -k) + COMPREPLY=( $(compgen -W "$(r2 -qc 'e asm.os=?' --)" -- $cur )) + return 0 + ;; + -s) + COMPREPLY=( $(compgen -W "$(r2 -qc 'e asm.syntax=?' --)" -- $cur )) + return 0 + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W '-a -A -b -c -C -d -D -e -E -f -F -h -i -k-l -L -o -O -s -B -v -w -q' -- $cur)) + ;; + *) + COMPREPLY=( $(compgen -f -- $cur)) + ;; + esac + + return 0 +} + +complete -F _rasm2 -o filenames rasm2 + +_rabin2 () { + local cur + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + prv=${COMP_WORDS[COMP_CWORD-1]} + case "$prv" in + -a) + COMPREPLY=( $(compgen -W "$(rasm2 -qL)" -- $cur)) + return 0 + ;; + -b) + COMPREPLY=( $(compgen -W "8 16 32 64" -- $cur )) + return 0 + ;; + -c) + # TODO. grab -a and get asm.cpu=? output + return 0 + ;; + -k) + COMPREPLY=( $(compgen -W "$(r2 -qc 'e asm.os=?' --)" -- $cur )) + return 0 + ;; + -s) + COMPREPLY=( $(compgen -W "$(r2 -qc 'e asm.syntax=?' --)" -- $cur )) + return 0 + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W '-a -A -b -c -C -d -D -e -E -f -F -h -i -k-l -L -o -O -s -B -v -w -q' -- $cur)) + ;; + *) + COMPREPLY=( $(compgen -f -- $cur)) + ;; + esac + + return 0 +} + +complete -F _rabin2 -o filenames rabin2 + +_rafind2 () { + local cur + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + case "$cur" in + -*) + COMPREPLY=( $( compgen -W '-a -b -e -f -h -m -M -n -r -s -S -t -v -x -X -z -Z' -- $cur)) + ;; + *) + COMPREPLY=( $(compgen -f -- $cur)) + ;; + esac + + return 0 +} + +complete -F _rafind2 -o filenames rafind2 + +_radiff2() { + local cur + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + prv=${COMP_WORDS[COMP_CWORD-1]} + case "$prv" in + -a) + COMPREPLY=( $(compgen -W "$(rasm2 -qL)" -- $cur)) + return 0 + ;; + -b) + COMPREPLY=( $(compgen -W "8 16 32 64" -- $cur )) + return 0 + ;; + esac + case "$cur" in + -*) + COMPREPLY=( $( compgen -W '-a -A -AA -AAA -b -c -C -d -D -g -j -n -O -p -r -s -ss -S -t -x -v -V' -- $cur)) + ;; + *) + COMPREPLY=( $(compgen -f -- $cur)) + ;; + esac + + return 0 +} + +complete -F _radiff2 -o filenames radiff2 diff --git a/libr/bin/bin.c b/libr/bin/bin.c index a1fc1098c2..4bbf13e0b9 100644 --- a/libr/bin/bin.c +++ b/libr/bin/bin.c @@ -1367,7 +1367,14 @@ R_API int r_bin_list(RBin *bin, int json) { RListIter *it; RBinXtrPlugin *bp; RBinXtrPlugin *bx; - if (json) { + if (json == 'q') { + r_list_foreach (bin->plugins, it, bp) { + bin->cb_printf ("%s\n", bp->name); + } + r_list_foreach (bin->binxtrs, it, bx) { + bin->cb_printf ("%s\n", bx->name); + } + } else if (json) { bin->cb_printf ("{\"bin\":["); r_list_foreach (bin->plugins, it, bp) { bin->cb_printf ("{\"filetype\":\"%s\",\"name\":\"%s\",\"license\":\"%s\"}", @@ -1848,13 +1855,19 @@ static void list_xtr_archs(RBin *bin, int mode) { arch = xtr_data->metadata->arch; machine = xtr_data->metadata->machine; bits = xtr_data->metadata->bits; - if (mode == 'j') { + switch (mode) { + case 'q': + bin->cb_printf ("%s\n", arch); + break; + case 'j': bin->cb_printf ("%s{\"arch\":\"%s\",\"bits\":%d," "\"offset\":%" PFMT64d ",\"size\":\"%" PFMT64d ",\"machine\":\"%s\"}", i++? ",": "", arch, bits, xtr_data->offset, xtr_data->size, machine); - } else { + break; + default: bin->cb_printf ("%03i 0x%08" PFMT64x " %"PFMT64d" %s_%i %s\n", i++, xtr_data->offset, xtr_data->size, arch, bits, machine); + break; } } } @@ -1908,16 +1921,18 @@ R_API void r_bin_list_archs(RBin *bin, int mode) { } if (info && narch > 1) { - if (mode) { - if (mode == 'j') { - bin->cb_printf ("%s{\"arch\":\"%s\",\"bits\":%d," - "\"offset\":%" PFMT64d ",\"machine\":\"%s\"}", - i? ",": "", arch, bits, - boffset, machine); - } else { - bin->cb_printf ("%03i 0x%08" PFMT64x " %d %s_%i %s\n", i, - boffset, obj_size, arch, bits, machine); - } + switch (mode) { + case 'q': + bin->cb_printf ("%s\n", arch); + break; + case 'j': + bin->cb_printf ("%s{\"arch\":\"%s\",\"bits\":%d," + "\"offset\":%" PFMT64d ",\"machine\":\"%s\"}", + i? ",": "", arch, bits, + boffset, machine); + default: + bin->cb_printf ("%03i 0x%08" PFMT64x " %d %s_%i %s\n", i, + boffset, obj_size, arch, bits, machine); } snprintf (archline, sizeof (archline) - 1, "0x%08" PFMT64x ":%d:%s:%d:%s", @@ -1926,31 +1941,37 @@ R_API void r_bin_list_archs(RBin *bin, int mode) { //sdb_array_push (binfile_sdb, ARCHS_KEY, archline, 0); } else { if (info) { - if (mode) { - if (mode == 'j') { - bin->cb_printf ("%s{\"arch\":\"%s\",\"bits\":%d," - "\"offset\":%" PFMT64d "}", - i? ",": "", arch, bits, - boffset); - } else { - bin->cb_printf ("%03i 0x%08" PFMT64x " %d %s_%d\n", i, - boffset, obj_size, arch, bits); - } + switch (mode) { + case 'q': + bin->cb_printf ("%s\n", arch); + break; + case 'j': + bin->cb_printf ("%s{\"arch\":\"%s\",\"bits\":%d," + "\"offset\":%" PFMT64d "}", + i? ",": "", arch, bits, + boffset); + break; + default: + bin->cb_printf ("%03i 0x%08" PFMT64x " %d %s_%d\n", i, + boffset, obj_size, arch, bits); } snprintf (archline, sizeof (archline), "0x%08" PFMT64x ":%d:%s:%d", boffset, obj_size, arch, bits); } else if (nbinfile && mode) { - if (mode) { - if (mode == 'j') { - bin->cb_printf ("%s{\"arch\":\"unk_%d\",\"bits\":%d," - "\"offset\":%" PFMT64d ",\"size\":%d}", - i? ",": "", i, bits, - boffset, obj_size); - } else { - bin->cb_printf ("%03i 0x%08" PFMT64x " %d unk_0\n", i, - boffset, obj_size); - } + switch (mode) { + case 'q': + bin->cb_printf ("%s\n", arch); + break; + case 'j': + bin->cb_printf ("%s{\"arch\":\"unk_%d\",\"bits\":%d," + "\"offset\":%" PFMT64d ",\"size\":%d}", + i? ",": "", i, bits, + boffset, obj_size); + break; + default: + bin->cb_printf ("%03i 0x%08" PFMT64x " %d unk_0\n", i, + boffset, obj_size); } snprintf (archline, sizeof (archline), "0x%08" PFMT64x ":%d:%s:%d", diff --git a/libr/config/config.c b/libr/config/config.c index a9edaa8e6e..bb7bdd5144 100644 --- a/libr/config/config.c +++ b/libr/config/config.c @@ -69,6 +69,11 @@ R_API void r_config_list(RConfig *cfg, const char *str, int rad) { node->desc? node->desc: ""); } break; + case 'q': + r_list_foreach (cfg->nodes, iter, node) { + cfg->cb_printf ("%s\n", node->name); + } + break; case 'j': cfg->cb_printf ("{"); r_list_foreach (cfg->nodes, iter, node) { diff --git a/libr/core/cmd_debug.c b/libr/core/cmd_debug.c index e358642547..eba08f5bde 100644 --- a/libr/core/cmd_debug.c +++ b/libr/core/cmd_debug.c @@ -3207,12 +3207,16 @@ static int cmd_debug(void *data, const char *input) { cmd_debug_pid (core, input); break; case 'h': // "dh" - if (input[1]==' ') { + if (input[1]=='q') { + r_debug_plugin_list (core->dbg, 'q'); + } else if (input[1]==' ') { char *str = r_str_chop (strdup (input + 2)); r_config_set (core->config, "dbg.backend", str); // implicit by config.set r_debug_use (core->dbg, str); free (str); - } else r_debug_plugin_list (core->dbg); + } else { + r_debug_plugin_list (core->dbg, 0); + } break; case 'i': { diff --git a/libr/core/cmd_eval.c b/libr/core/cmd_eval.c index cff528a5a8..eb64144e51 100644 --- a/libr/core/cmd_eval.c +++ b/libr/core/cmd_eval.c @@ -179,9 +179,12 @@ static int cmd_eval(void *data, const char *input) { case 'x': // exit // XXX we need headers for the cmd_xxx files. return cmd_quit (data, ""); - case 'j': + case 'j': // json r_config_list (core->config, NULL, 'j'); break; + case 'q': // quiet list of eval keys + r_config_list (core->config, NULL, 'q'); + break; case '\0': // "e" r_config_list (core->config, NULL, 0); break; diff --git a/libr/core/config.c b/libr/core/config.c index 85e1072343..acfc787632 100644 --- a/libr/core/config.c +++ b/libr/core/config.c @@ -822,7 +822,10 @@ static int cb_dbgstatus(void *user, void *data) { static int cb_dbgbackend(void *user, void *data) { RCore *core = (RCore*) user; RConfigNode *node = (RConfigNode*) data; - // XXX: remove this spagetti + if (!strcmp (node->value, "?")) { + r_debug_plugin_list (core->dbg, 'q'); + return false; + } if (!strcmp (node->value, "bf")) { r_config_set (core->config, "asm.arch", "bf"); } diff --git a/libr/debug/plugin.c b/libr/debug/plugin.c index d238da6eb9..d3cc5192f2 100644 --- a/libr/debug/plugin.c +++ b/libr/debug/plugin.c @@ -51,7 +51,7 @@ R_API bool r_debug_use(RDebug *dbg, const char *str) { return (dbg->h != NULL); } -R_API int r_debug_plugin_list(RDebug *dbg) { +R_API int r_debug_plugin_list(RDebug *dbg, int mode) { char spaces[16]; int count = 0; struct list_head *pos; @@ -61,9 +61,13 @@ R_API int r_debug_plugin_list(RDebug *dbg) { RDebugPlugin *h = list_entry(pos, RDebugPlugin, list); int sp = 8-strlen (h->name); spaces[sp] = 0; - dbg->cb_printf ("%d %s %s %s%s\n", - count, (h == dbg->h)? "dbg": "---", - h->name, spaces, h->license); + if (mode == 'q') { + dbg->cb_printf ("%s\n", h->name); + } else { + dbg->cb_printf ("%d %s %s %s%s\n", + count, (h == dbg->h)? "dbg": "---", + h->name, spaces, h->license); + } spaces[sp] = ' '; count++; } diff --git a/libr/include/r_debug.h b/libr/include/r_debug.h index 05b070d77c..e5e2dfa718 100644 --- a/libr/include/r_debug.h +++ b/libr/include/r_debug.h @@ -397,7 +397,7 @@ R_API int r_debug_kill_setup(RDebug *dbg, int sig, int action); /* handle.c */ R_API void r_debug_plugin_init(RDebug *dbg); R_API int r_debug_plugin_set(RDebug *dbg, const char *str); -R_API int r_debug_plugin_list(RDebug *dbg); +R_API int r_debug_plugin_list(RDebug *dbg, int mode); R_API bool r_debug_plugin_add(RDebug *dbg, RDebugPlugin *foo); /* memory */