Skip to content

Commit 193b40a

Browse files
kconfig: sort found symbols by relevance
When searching for symbols, return the symbols sorted by relevance. Sorting is done as thus: - first, symbols that match exactly - then, alphabetical sort Since the search can be a regexp, it is possible that more than one symbol matches exactly. In this case, we can't decide which to sort first, so we fallback to alphabeticall sort. Explain this (new!) sorting heuristic in the documentation. Reported-by: Jean Delvare <[email protected]> Signed-off-by: "Yann E. MORIN" <[email protected]> Cc: Jean Delvare <[email protected]> Cc: Michal Marek <[email protected]> Cc: Roland Eggner <[email protected]> Cc: Wang YanQing <[email protected]> -- Changes v1->v2: - drop the previous, complex heuristic in favour of a simpler heuristic that is both easier to understand, *and* to maintain (Jean) - explain sorting heuristic in the doc (Jean)
1 parent a5f6d79 commit 193b40a

File tree

2 files changed

+82
-9
lines changed

2 files changed

+82
-9
lines changed

Documentation/kbuild/kconfig.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,19 @@ Searching in menuconfig:
174174

175175
/^hotplug
176176

177+
When searching, symbols are sorted thus:
178+
- exact match first: an exact match is when the search matches
179+
the complete symbol name;
180+
- alphabetical order: when two symbols do not match exactly,
181+
they are sorted in alphabetical order (in the user's current
182+
locale).
183+
For example: ^ATH.K matches:
184+
ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
185+
[...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
186+
of which only ATH5K and ATH9K match exactly and so are sorted
187+
first (and in alphabetical order), then come all other symbols,
188+
sorted in alphabetical order.
189+
177190
______________________________________________________________________
178191
User interface options for 'menuconfig'
179192

scripts/kconfig/symbol.c

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -954,38 +954,98 @@ const char *sym_escape_string_value(const char *in)
954954
return res;
955955
}
956956

957+
struct sym_match {
958+
struct symbol *sym;
959+
off_t so, eo;
960+
};
961+
962+
/* Compare matched symbols as thus:
963+
* - first, symbols that match exactly
964+
* - then, alphabetical sort
965+
*/
966+
static int sym_rel_comp( const void *sym1, const void *sym2 )
967+
{
968+
struct sym_match *s1 = *(struct sym_match **)sym1;
969+
struct sym_match *s2 = *(struct sym_match **)sym2;
970+
int l1, l2;
971+
972+
/* Exact match:
973+
* - if matched length on symbol s1 is the length of that symbol,
974+
* then this symbol should come first;
975+
* - if matched length on symbol s2 is the length of that symbol,
976+
* then this symbol should come first.
977+
* Note: since the search can be a regexp, both symbols may match
978+
* exactly; if this is the case, we can't decide which comes first,
979+
* and we fallback to sorting alphabetically.
980+
*/
981+
l1 = s1->eo - s1->so;
982+
l2 = s2->eo - s2->so;
983+
if (l1 == strlen(s1->sym->name) && l2 != strlen(s2->sym->name))
984+
return -1;
985+
if (l1 != strlen(s1->sym->name) && l2 == strlen(s2->sym->name))
986+
return 1;
987+
988+
/* As a fallback, sort symbols alphabetically */
989+
return strcmp(s1->sym->name, s2->sym->name);
990+
}
991+
957992
struct symbol **sym_re_search(const char *pattern)
958993
{
959994
struct symbol *sym, **sym_arr = NULL;
995+
struct sym_match **sym_match_arr = NULL;
960996
int i, cnt, size;
961997
regex_t re;
998+
regmatch_t match[1];
962999

9631000
cnt = size = 0;
9641001
/* Skip if empty */
9651002
if (strlen(pattern) == 0)
9661003
return NULL;
967-
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
1004+
if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
9681005
return NULL;
9691006

9701007
for_all_symbols(i, sym) {
1008+
struct sym_match *tmp_sym_match;
9711009
if (sym->flags & SYMBOL_CONST || !sym->name)
9721010
continue;
973-
if (regexec(&re, sym->name, 0, NULL, 0))
1011+
if (regexec(&re, sym->name, 1, match, 0))
9741012
continue;
9751013
if (cnt + 1 >= size) {
976-
void *tmp = sym_arr;
1014+
void *tmp;
9771015
size += 16;
978-
sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
979-
if (!sym_arr) {
980-
free(tmp);
981-
return NULL;
1016+
tmp = realloc(sym_match_arr, size * sizeof(struct sym_match *));
1017+
if (!tmp) {
1018+
goto sym_re_search_free;
9821019
}
1020+
sym_match_arr = tmp;
9831021
}
9841022
sym_calc_value(sym);
985-
sym_arr[cnt++] = sym;
1023+
tmp_sym_match = (struct sym_match*)malloc(sizeof(struct sym_match));
1024+
if (!tmp_sym_match)
1025+
goto sym_re_search_free;
1026+
tmp_sym_match->sym = sym;
1027+
/* As regexec return 0, we know we have a match, so
1028+
* we can use match[0].rm_[se]o without further checks
1029+
*/
1030+
tmp_sym_match->so = match[0].rm_so;
1031+
tmp_sym_match->eo = match[0].rm_eo;
1032+
sym_match_arr[cnt++] = tmp_sym_match;
9861033
}
987-
if (sym_arr)
1034+
if (sym_match_arr) {
1035+
qsort(sym_match_arr, cnt, sizeof(struct sym_match*), sym_rel_comp);
1036+
sym_arr = malloc((cnt+1) * sizeof(struct symbol));
1037+
if (!sym_arr)
1038+
goto sym_re_search_free;
1039+
for (i = 0; i < cnt; i++)
1040+
sym_arr[i] = sym_match_arr[i]->sym;
9881041
sym_arr[cnt] = NULL;
1042+
}
1043+
sym_re_search_free:
1044+
if (sym_match_arr) {
1045+
for (i = 0; i < cnt; i++)
1046+
free(sym_match_arr[i]);
1047+
free(sym_match_arr);
1048+
}
9891049
regfree(&re);
9901050

9911051
return sym_arr;

0 commit comments

Comments
 (0)