Commit 4adf8a92 authored by Sam Ravnborg's avatar Sam Ravnborg

kconfig: Redo and improve search support

Based on patch from: Roman Zippel <zippel@linux-m68k.org>

The search functionality has been improved:
- Restructured printout with more info
- Include value of relevant symbols
- Improved handling of corner cases
- Generic search support moved to backend - ready to be utilised by xconfig and gconfig
- Search functionality moved to fronend - not hardcoded in menubox.c

Sample search (^$ used to limit search):
Search for "^USB_STORAGE$":

Symbol: USB_STORAGE [=y]
Prompt: USB Mass Storage support
  Defined at drivers/usb/storage/Kconfig:7
  Depends on: USB
  Location:
    -> Device Drivers
      -> USB Support
  Selects: SCSI


Some symbols has loong "Depends on:" lines - for example FW_LOADER.
Use arrows to scroll horisontally to see full value.
Signed-off-by: default avatarSam Ravnborg <sam@ravnborg.org>
parent f7f36464
...@@ -1087,3 +1087,13 @@ void expr_fprint(struct expr *e, FILE *out) ...@@ -1087,3 +1087,13 @@ void expr_fprint(struct expr *e, FILE *out)
{ {
expr_print(e, expr_print_file_helper, out, E_NONE); expr_print(e, expr_print_file_helper, out, E_NONE);
} }
static void expr_print_gstr_helper(void *data, const char *str)
{
str_append((struct gstr*)data, str);
}
void expr_gstr_print(struct expr *e, struct gstr *gs)
{
expr_print(e, expr_print_gstr_helper, gs, E_NONE);
}
...@@ -174,6 +174,8 @@ void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, s ...@@ -174,6 +174,8 @@ void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, s
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
void expr_fprint(struct expr *e, FILE *out); void expr_fprint(struct expr *e, FILE *out);
struct gstr; /* forward */
void expr_gstr_print(struct expr *e, struct gstr *gs);
static inline int expr_is_yes(struct expr *e) static inline int expr_is_yes(struct expr *e)
{ {
......
...@@ -18,6 +18,7 @@ P(sym_change_count,int,); ...@@ -18,6 +18,7 @@ P(sym_change_count,int,);
P(sym_lookup,struct symbol *,(const char *name, int isconst)); P(sym_lookup,struct symbol *,(const char *name, int isconst));
P(sym_find,struct symbol *,(const char *name)); P(sym_find,struct symbol *,(const char *name));
P(sym_re_search,struct symbol **,(const char *pattern));
P(sym_type_name,const char *,(enum symbol_type type)); P(sym_type_name,const char *,(enum symbol_type type));
P(sym_calc_value,void,(struct symbol *sym)); P(sym_calc_value,void,(struct symbol *sym));
P(sym_get_type,enum symbol_type,(struct symbol *sym)); P(sym_get_type,enum symbol_type,(struct symbol *sym));
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include <regex.h>
#define LKC_DIRECT_LINK #define LKC_DIRECT_LINK
#include "lkc.h" #include "lkc.h"
...@@ -79,8 +78,45 @@ save_config_help[] = ...@@ -79,8 +78,45 @@ save_config_help[] =
"configuration options you have selected at that time.\n" "configuration options you have selected at that time.\n"
"\n" "\n"
"If you are uncertain what all this means then you should probably\n" "If you are uncertain what all this means then you should probably\n"
"leave this blank.\n" "leave this blank.\n",
; search_help[] =
"\n"
"Search for CONFIG_ symbols and display their relations.\n"
"Example: search for \"^FOO\"\n"
"Result:\n"
"-----------------------------------------------------------------\n"
"Symbol: FOO [=m]\n"
"Prompt: Foo bus is used to drive the bar HW\n"
"Defined at drivers/pci/Kconfig:47\n"
"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
"Location:\n"
" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
" -> PCI support (PCI [=y])\n"
" -> PCI access mode (<choice> [=y])\n"
"Selects: LIBCRC32\n"
"Selected by: BAR\n"
"-----------------------------------------------------------------\n"
"o The line 'Prompt:' shows the text used in the menu structure for\n"
" this CONFIG_ symbol\n"
"o The 'Defined at' line tell at what file / line number the symbol\n"
" is defined\n"
"o The 'Depends on:' line tell what symbols needs to be defined for\n"
" this symbol to be visible in the menu (selectable)\n"
"o The 'Location:' lines tell where in the menu structure this symbol\n"
" is located\n"
" A location followed by a [=y] indicate that this is a selectable\n"
" menu item - and current value is displayed inside brackets.\n"
"o The 'Selects:' line tell what symbol will be automatically\n"
" selected if this symbol is selected (y or m)\n"
"o The 'Selected by' line tell what symbol has selected this symbol\n"
"\n"
"Only relevant lines are shown.\n"
"\n\n"
"Search examples:\n"
"Examples: USB => find all CONFIG_ symbols containing USB\n"
" ^USB => find all CONFIG_ symbols starting with USB\n"
" USB$ => find all CONFIG_ symbols ending with USB\n"
"\n";
static signed char buf[4096], *bufptr = buf; static signed char buf[4096], *bufptr = buf;
static signed char input_buf[4096]; static signed char input_buf[4096];
...@@ -104,9 +140,6 @@ static void show_helptext(const char *title, const char *text); ...@@ -104,9 +140,6 @@ static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu); static void show_help(struct menu *menu);
static void show_readme(void); static void show_readme(void);
static void show_file(const char *filename, const char *title, int r, int c); static void show_file(const char *filename, const char *title, int r, int c);
static void show_expr(struct menu *menu, FILE *fp);
static void search_conf(char *pattern);
static int regex_match(const char *string, regex_t *re);
static void cprint_init(void); static void cprint_init(void);
static int cprint1(const char *fmt, ...); static int cprint1(const char *fmt, ...);
...@@ -196,6 +229,74 @@ static int cprint(const char *fmt, ...) ...@@ -196,6 +229,74 @@ static int cprint(const char *fmt, ...)
return res; return res;
} }
static void get_prompt_str(struct gstr *r, struct property *prop)
{
int i, j;
struct menu *submenu[8], *menu;
str_printf(r, "Prompt: %s\n", prop->text);
str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
prop->menu->lineno);
if (!expr_is_yes(prop->visible.expr)) {
str_append(r, " Depends on: ");
expr_gstr_print(prop->visible.expr, r);
str_append(r, "\n");
}
menu = prop->menu->parent;
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
submenu[i++] = menu;
if (i > 0) {
str_printf(r, " Location:\n");
for (j = 4; --i >= 0; j += 2) {
menu = submenu[i];
str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
if (menu->sym) {
str_printf(r, " (%s [=%s])", menu->sym->name ?
menu->sym->name : "<choice>",
sym_get_string_value(menu->sym));
}
str_append(r, "\n");
}
}
}
static struct gstr get_relations_str(struct symbol **sym_arr)
{
struct symbol *sym;
struct property *prop;
struct gstr res = str_new();
struct gstr *r = &res;
bool hit;
int i;
for (i = 0; sym_arr && (sym = sym_arr[i]); i++) {
str_printf(&res, "Symbol: %s [=%s]\n", sym->name,
sym_get_string_value(sym));
for_all_prompts(sym, prop)
get_prompt_str(r, prop);
hit = false;
for_all_properties(sym, prop, P_SELECT) {
if (!hit) {
str_append(r, " Selects: ");
hit = true;
} else
str_printf(r, " && ");
expr_gstr_print(prop->expr, r);
}
if (hit)
str_append(r, "\n");
if (sym->rev_dep.expr) {
str_append(r, " Selected by: ");
expr_gstr_print(sym->rev_dep.expr, r);
str_append(r, "\n");
}
str_append(r, "\n\n");
}
if (!i)
str_append(r, "No matches found.\n");
return res;
}
pid_t pid; pid_t pid;
static void winch_handler(int sig) static void winch_handler(int sig)
...@@ -279,112 +380,39 @@ static int exec_conf(void) ...@@ -279,112 +380,39 @@ static int exec_conf(void)
return WEXITSTATUS(stat); return WEXITSTATUS(stat);
} }
static int regex_match(const char *string, regex_t *re) static void search_conf(void)
{
int rc;
rc = regexec(re, string, (size_t) 0, NULL, 0);
if (rc)
return 0;
return 1;
}
static void show_expr(struct menu *menu, FILE *fp)
{
bool hit = false;
fprintf(fp, "Depends:\n ");
if (menu->prompt->visible.expr) {
if (!hit)
hit = true;
expr_fprint(menu->prompt->visible.expr, fp);
}
if (!hit)
fprintf(fp, "None");
if (menu->sym) {
struct property *prop;
hit = false;
fprintf(fp, "\nSelects:\n ");
for_all_properties(menu->sym, prop, P_SELECT) {
if (!hit)
hit = true;
expr_fprint(prop->expr, fp);
}
if (!hit)
fprintf(fp, "None");
hit = false;
fprintf(fp, "\nSelected by:\n ");
if (menu->sym->rev_dep.expr) {
hit = true;
expr_fprint(menu->sym->rev_dep.expr, fp);
}
if (!hit)
fprintf(fp, "None");
}
}
static void search_conf(char *pattern)
{ {
struct symbol *sym = NULL; struct symbol **sym_arr;
struct menu *menu[32] = { 0 }; int stat;
struct property *prop = NULL; struct gstr res;
FILE *fp = NULL;
bool hit = false;
int i, j, k, l;
regex_t re;
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB))
return;
fp = fopen(".search.tmp", "w"); again:
if (fp == NULL) { cprint_init();
perror("fopen"); cprint("--title");
cprint("Search Configuration Parameter");
cprint("--inputbox");
cprint("Enter Keyword");
cprint("10");
cprint("75");
cprint("");
stat = exec_conf();
if (stat < 0)
goto again;
switch (stat) {
case 0:
break;
case 1:
show_helptext("Search Configuration", search_help);
goto again;
default:
return; return;
} }
for_all_symbols(i, sym) {
if (!sym->name) sym_arr = sym_re_search(input_buf);
continue; res = get_relations_str(sym_arr);
if (!regex_match(sym->name, &re)) free(sym_arr);
continue; show_textbox("Search Results", str_get(&res), 0, 0);
for_all_prompts(sym, prop) { str_free(&res);
struct menu *submenu = prop->menu;
if (!submenu)
continue;
j = 0;
hit = false;
while (submenu) {
menu[j++] = submenu;
submenu = submenu->parent;
}
if (j > 0) {
if (!hit)
hit = true;
fprintf(fp, "%s (%s)\n", prop->text, sym->name);
fprintf(fp, "Location:\n");
}
for (k = j-2, l=1; k > 0; k--, l++) {
const char *prompt = menu_get_prompt(menu[k]);
if (menu[k]->sym)
fprintf(fp, "%*c-> %s (%s)\n",
l, ' ',
prompt,
menu[k]->sym->name);
else
fprintf(fp, "%*c-> %s\n",
l, ' ',
prompt);
}
if (hit) {
show_expr(menu[0], fp);
fprintf(fp, "\n\n\n");
}
}
}
if (!hit)
fprintf(fp, "No matches found.");
regfree(&re);
fclose(fp);
show_file(".search.tmp", "Search Results", 0, 0);
unlink(".search.tmp");
} }
static void build_conf(struct menu *menu) static void build_conf(struct menu *menu)
...@@ -576,23 +604,6 @@ static void conf(struct menu *menu) ...@@ -576,23 +604,6 @@ static void conf(struct menu *menu)
cprint(" Save Configuration to an Alternate File"); cprint(" Save Configuration to an Alternate File");
} }
stat = exec_conf(); stat = exec_conf();
if (stat == 26) {
char *pattern;
if (!strlen(input_buf))
continue;
pattern = malloc(sizeof(char)*sizeof(input_buf));
if (pattern == NULL) {
perror("malloc");
continue;
}
for (i = 0; input_buf[i]; i++)
pattern[i] = toupper(input_buf[i]);
pattern[i] = '\0';
search_conf(pattern);
free(pattern);
continue;
}
if (stat < 0) if (stat < 0)
continue; continue;
...@@ -669,6 +680,9 @@ static void conf(struct menu *menu) ...@@ -669,6 +680,9 @@ static void conf(struct menu *menu)
else if (type == 'm') else if (type == 'm')
conf(submenu); conf(submenu);
break; break;
case 7:
search_conf();
break;
} }
} }
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <regex.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#define LKC_DIRECT_LINK #define LKC_DIRECT_LINK
...@@ -656,6 +657,43 @@ struct symbol *sym_find(const char *name) ...@@ -656,6 +657,43 @@ struct symbol *sym_find(const char *name)
return symbol; return symbol;
} }
struct symbol **sym_re_search(const char *pattern)
{
struct symbol *sym, **sym_arr = NULL;
int i, cnt, size;
regex_t re;
cnt = size = 0;
/* Skip if empty */
if (strlen(pattern) == 0)
return NULL;
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
return NULL;
for_all_symbols(i, sym) {
if (sym->flags & SYMBOL_CONST || !sym->name)
continue;
if (regexec(&re, sym->name, 0, NULL, 0))
continue;
if (cnt + 1 >= size) {
void *tmp = sym_arr;
size += 16;
sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
if (!sym_arr) {
free(tmp);
return NULL;
}
}
sym_arr[cnt++] = sym;
}
if (sym_arr)
sym_arr[cnt] = NULL;
regfree(&re);
return sym_arr;
}
struct symbol *sym_check_deps(struct symbol *sym); struct symbol *sym_check_deps(struct symbol *sym);
static struct symbol *sym_check_expr_deps(struct expr *e) static struct symbol *sym_check_expr_deps(struct expr *e)
......
...@@ -276,15 +276,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width, ...@@ -276,15 +276,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
while (key != ESC) { while (key != ESC) {
key = wgetch(menu); key = wgetch(menu);
if ( key == '/' ) {
int ret = dialog_inputbox("Search Configuration Parameter",
"Enter Keyword", height, width,
(char *) NULL);
if (ret == 0) {
fprintf(stderr, "%s", dialog_input_result);
return 26;
}
}
if (key < 256 && isalpha(key)) key = tolower(key); if (key < 256 && isalpha(key)) key = tolower(key);
...@@ -408,6 +399,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width, ...@@ -408,6 +399,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
case 'y': case 'y':
case 'n': case 'n':
case 'm': case 'm':
case '/':
/* save scroll info */ /* save scroll info */
if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) { if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) {
fprintf(f,"%d\n",scroll); fprintf(f,"%d\n",scroll);
...@@ -421,6 +413,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width, ...@@ -421,6 +413,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
case 'n': return 4; case 'n': return 4;
case 'm': return 5; case 'm': return 5;
case ' ': return 6; case ' ': return 6;
case '/': return 7;
} }
return 0; return 0;
case 'h': case 'h':
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment