add case insensitive matching in xschem search function

This commit is contained in:
stefan schippers 2023-07-12 13:58:54 +02:00
parent 83b1993c32
commit 3c73bb918b
6 changed files with 96 additions and 37 deletions

View File

@ -496,6 +496,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
<li><kbd> abort_operation</kbd></li><pre>
Resets UI state, unselect all and abort any pending operation </pre>
<li><kbd> add_symbol_pin</kbd></li><pre>
@ -1042,7 +1043,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
If nothing selected open another window of the second
schematic (issues a warning).
if 'new_process' is given start a new xschem process </pre>
<li><kbd> search regex|exact select tok val</kbd></li><pre>
<li><kbd> search regex|exact select tok val [match_case]</kbd></li><pre>
Search instances with attribute string containing 'tok'
attribute and value 'val'
search can be exact ('exact') or as a regular expression ('regex')
@ -1057,7 +1058,11 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
*symbol* attribute string.
cell::name : will search for 'val' in the symbol name
cell::&lt;attr&gt; will search for 'val' in symbol attribute 'attr'
example: xschem search regex 0 cell::template GAIN=100</pre>
example: xschem search regex 0 cell::template GAIN=100
match_case:
1 : Match case
0 : Do not match case
If not given assume 1 (Match case)</pre>
<li><kbd> select instance|wire|text id [clear]</kbd></li><pre>
Select indicated instance or wire or text.
For 'instance' 'id' can be the instance name or number
@ -1254,6 +1259,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
</ul>

View File

@ -45,6 +45,28 @@ int my_strcasecmp(const char *s1, const char *s2)
return tolower(*s1) - tolower(*s2);
}
char *my_strcasestr(const char *haystack, const char *needle)
{
const char *h, *n;
int found = 0;
if(needle[0] == '\0') return (char *)haystack;
for(h = haystack; *h; h++) {
found = 1;
for(n = needle; *n; n++) {
const char *hh = h + (n - needle);
dbg(1, "%c %c\n", *hh, *n);
if(toupper(*hh) != toupper(*n)) {
found = 0;
break;
}
}
if(found) return (char *)h;
}
return NULL;
}
int my_strncasecmp(const char *s1, const char *s2, size_t n)
{
if (n == 0) return 0;

View File

@ -632,7 +632,7 @@ static int win_regexec(const char *options, const char *pattern, char *name)
* 0 : regex search
* 1 : exact search
*/
int search(const char *tok, const char *val, int sub, int sel)
int search(const char *tok, const char *val, int sub, int sel, int match_case)
{
int save_draw;
int i,c, col = 7,tmp,bus=0;
@ -642,9 +642,14 @@ int search(const char *tok, const char *val, int sub, int sel)
const char *empty_string = "";
char *tmpname=NULL;
int found = 0;
#ifdef __unix__
int(*comparefn)(const char *,const char *) = strcmp;
char *(*substrfn)(const char *,const char *) = strstr;
#ifdef __unix__
int cflags = REG_NOSUB | REG_EXTENDED;
regex_t re;
#endif
#else
char *regexp_options = NULL;
#endif
if(!val) {
fprintf(errfp, "search(): warning: null val key\n");
@ -652,13 +657,25 @@ int search(const char *tok, const char *val, int sub, int sel)
}
save_draw = xctx->draw_window;
xctx->draw_window=1;
#ifdef __unix__
if(regcomp(&re, val , REG_NOSUB | REG_EXTENDED)) return TCL_ERROR;
#endif
/* replace strcmp and strstr with my_strcasecmp and my_strcasestr
* if SPICE or VHDL (case insensitive) netlist mode is set */
if(!match_case) {
comparefn = my_strcasecmp;
substrfn = my_strcasestr;
}
#ifdef __unix__
if(!match_case) {
cflags |= REG_ICASE; /* ignore case for Spice and VHDL (these are case insensitive netlists) */
}
if(regcomp(&re, val , cflags)) return TCL_ERROR;
#else
if(!match_case) {
regexp_options = "-nocase";
}
#endif
dbg(1, "search():val=%s\n", val);
if(!sel) {
col=xctx->hilight_color;
if(tclgetboolvar("incr_hilight")) incr_hilight_color();
}
has_token = 0;
prepare_netlist_structs(0);
@ -693,11 +710,10 @@ int search(const char *tok, const char *val, int sub, int sel)
if(str && has_token) {
#ifdef __unix__
if( (!sub && !regexec(&re, str,0 , NULL, 0) ) || /* 20071120 regex instead of strcmp */
(sub && !strcmp(str, val) && !bus) || (sub && strstr(str,val) && bus))
(sub && !bus && !comparefn(str, val)) || (sub && bus && substrfn(str,val)))
#else
if( (!sub && win_regexec(NULL, val, str)) ||
(sub && !strcmp(str, val) && !bus) || (sub && strstr(str,val) && bus))
if( (!sub && win_regexec(regexp_options, val, str)) ||
(sub && !bus && !comparefn(str, val)) || (sub && bus && substrfn(str,val)))
#endif
{
if(!sel) {
@ -728,10 +744,10 @@ int search(const char *tok, const char *val, int sub, int sel)
if(xctx->tok_size ) {
#ifdef __unix__
if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || /* 20071120 regex instead of strcmp */
( !strcmp(str, val) && sub ) )
( !comparefn(str, val) && sub ) )
#else
if( (win_regexec(NULL, val, str) && !sub ) || /* 20071120 regex instead of strcmp */
( !strcmp(str, val) && sub ) )
if( (win_regexec(regexp_options, val, str) && !sub ) || /* 20071120 regex instead of strcmp */
( !comparefn(str, val) && sub ) )
#endif
{
@ -759,10 +775,10 @@ int search(const char *tok, const char *val, int sub, int sel)
if(xctx->tok_size) {
#ifdef __unix__
if( (!regexec(&re, str,0 , NULL, 0) && !sub ) ||
( !strcmp(str, val) && sub ))
( !comparefn(str, val) && sub ))
#else
if( (win_regexec(NULL, val, str) && !sub ) ||
( !strcmp(str, val) && sub ))
if( (win_regexec(regexp_options, val, str) && !sub ) ||
( !comparefn(str, val) && sub ))
#endif
{
if(sel==1) {
@ -786,10 +802,10 @@ int search(const char *tok, const char *val, int sub, int sel)
if(xctx->tok_size) {
#ifdef __unix__
if( (!regexec(&re, str,0 , NULL, 0) && !sub ) ||
( !strcmp(str, val) && sub ))
( !comparefn(str, val) && sub ))
#else
if( (win_regexec(NULL, val, str) && !sub ) ||
( !strcmp(str, val) && sub ))
if( (win_regexec(regexp_options, val, str) && !sub ) ||
( !comparefn(str, val) && sub ))
#endif
{
if(sel==1) {
@ -809,6 +825,7 @@ int search(const char *tok, const char *val, int sub, int sel)
}
}
if(found) {
if(tclgetboolvar("incr_hilight")) incr_hilight_color();
if(sel == -1) {
draw();
}

View File

@ -3154,7 +3154,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_ResetResult(interp);
}
/* search regex|exact select tok val
/* search regex|exact select tok val [match_case]
* Search instances with attribute string containing 'tok'
* attribute and value 'val'
* search can be exact ('exact') or as a regular expression ('regex')
@ -3170,21 +3170,27 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
* cell::name : will search for 'val' in the symbol name
* cell::<attr> will search for 'val' in symbol attribute 'attr'
* example: xschem search regex 0 cell::template GAIN=100
* match_case:
* 1 : Match case
* 0 : Do not match case
* If not given assume 1 (Match case)
*/
else if(!strcmp(argv[1], "search") || !strcmp(argv[1], "searchmenu"))
{
/* 0 1 2 3 4 5 */
/* select */
/* xschem search regex|exact 0|1|-1 tok val */
/* 0 1 2 3 4 5 6 */
/* select */
/* xschem search regex|exact 0|1|-1 tok val [match_case] */
int select, r;
int match_case = 1;
if(argc > 6 && argv[6][0] == '0') match_case = 0;
if(argc < 6) {
Tcl_SetResult(interp, "xschem search requires 4 or 5 additional fields.", TCL_STATIC);
return TCL_ERROR;
}
if(argc > 5) {
select = atoi(argv[3]);
if(!strcmp(argv[2], "regex") ) r = search(argv[4],argv[5],0,select);
else r = search(argv[4],argv[5],1,select);
if(!strcmp(argv[2], "regex") ) r = search(argv[4],argv[5],0,select, match_case);
else r = search(argv[4],argv[5],1,select, match_case);
if(r == 0) {
if(has_x && !strcmp(argv[1], "searchmenu"))
tcleval("tk_messageBox -type ok -parent [xschem get topwindow] -message {Not found.}");
@ -3855,8 +3861,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
* testmode */
else if(!strcmp(argv[1], "test"))
{
dbg(0, "sizeof Xschem_ctx=%d\n", sizeof(Xschem_ctx));
/* swap_windows(); */
/*
* if(argc > 3) {
* char *r = my_strcasestr(argv[2], argv[3]);
* dbg(0, "%s\n", r ? r : "NULL");
* }
*/
Tcl_ResetResult(interp);
}

View File

@ -1198,7 +1198,7 @@ extern Hilight_hashentry *bus_hilight_hash_lookup(const char *token, int value,
/* wrapper function to hash highlighted instances, avoid clash with net names */
extern Hilight_hashentry *inst_hilight_hash_lookup(int i, int value, int what);
extern Hilight_hashentry *hilight_lookup(const char *token, int value, int what);
extern int search(const char *tok, const char *val, int sub, int sel);
extern int search(const char *tok, const char *val, int sub, int sel, int match_case);
extern int process_options(int argc, char **argv);
extern void calc_drawing_bbox(xRect *boundbox, int selected);
extern int ps_draw(int what);
@ -1457,6 +1457,7 @@ extern char *my_strtok_r(char *str, const char *delim, const char *quote, char *
extern char **parse_cmd_string(const char *cmd, int *argc);
extern int my_strncpy(char *d, const char *s, size_t n);
extern int my_strcasecmp(const char *s1, const char *s2);
extern char *my_strcasestr(const char *haystack, const char *needle);
extern double mylog10(double x);
extern double mylog(double x);
extern int my_strncasecmp(const char *s1, const char *s2, size_t n);

View File

@ -1327,7 +1327,7 @@ proc descend_hierarchy {path {redraw 1}} {
set inst $path
regsub {\..*} $inst {} inst ;# take 1st path component: xlev1[3].xlev2.m3 -> xlev1[3]
regsub {[^.]+\.} $path {} path ;# take remaining path: xlev1[3].xlev2.m3 -> xlev2.m3
xschem search exact 1 name $inst
xschem search exact 1 name $inst 1
# handle vector instances: xlev1[3:0] -> xlev1[3],xlev1[2],xlev1[1],xlev1[0]
# descend into the right one
set inst_list [split [lindex [xschem expandlabel [lindex [xschem selected_set] 0 ] ] 0] {,}]
@ -3600,7 +3600,7 @@ proc about {} {
proc property_search {} {
global search_value search_found
global search_exact
global search_exact search_case
global search_select
global custom_token OS
@ -3631,22 +3631,24 @@ proc property_search {} {
set custom_token [.dialog.custom.e get]
if {$debug_var<=-1} { puts stderr "|$custom_token|" }
if { $search_exact==1 } {
set search_found [xschem searchmenu exact $search_select $custom_token $search_value]
set search_found [xschem searchmenu exact $search_select $custom_token $search_value $search_case]
} else {
set search_found [xschem searchmenu regex $search_select $custom_token $search_value]
set search_found [xschem searchmenu regex $search_select $custom_token $search_value $search_case]
}
destroy .dialog
}
button .dialog.but.cancel -text Cancel -command { set search_found 1; destroy .dialog }
# Window doesn't support regular expression, has to be exact match for now
checkbutton .dialog.but.sub -text Exact_search -variable search_exact
checkbutton .dialog.but.sub -text {Exact search} -variable search_exact
checkbutton .dialog.but.case -text {Match case} -variable search_case
radiobutton .dialog.but.nosel -text {Highlight} -variable search_select -value 0
radiobutton .dialog.but.sel -text {Select} -variable search_select -value 1
# 20171211 added unselect
radiobutton .dialog.but.unsel -text {Unselect} -variable search_select -value -1
pack .dialog.but.ok -anchor w -side left
pack .dialog.but.sub -side left
pack .dialog.but.case -side left
pack .dialog.but.nosel -side left
pack .dialog.but.sel -side left
pack .dialog.but.unsel -side left
@ -5493,7 +5495,7 @@ set tctx::global_list {
netlist_type no_change_attrs nolist_libs noprint_libs old_selected_tok only_probes path pathlist
persistent_command preserve_unchanged_attrs prev_symbol ps_colors ps_paper_size rainbow_colors
rawfile_loaded rcode recentfile
replace_key retval retval_orig rotated_text search_exact search_found search_schematic
replace_key retval retval_orig rotated_text search_case search_exact search_found search_schematic
search_select search_value selected_tok show_hidden_texts show_infowindow
show_infowindow_after_netlist show_pin_net_names
simconf_default_geometry simconf_vpos simulate_bg spiceprefix split_files svg_colors
@ -6754,6 +6756,7 @@ set_ne XSCHEM_START_WINDOW {}
set custom_token {lab}
set search_value {}
set search_exact 0
set search_case 1
# 20171005
set custom_label_prefix {}