From b0d9da33f58cf3dfd193f56b07101a7a26f7ad3c Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Mon, 1 Jun 2026 10:57:46 +0200 Subject: [PATCH] xschem search: add txt_ptr special token for searching text objects by their content --- doc/xschem_man/developer_info.html | 4 +- src/hilight.c | 387 +++++++++++++++-------------- src/scheduler.c | 4 +- 3 files changed, 206 insertions(+), 189 deletions(-) diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index dfbd5315..6c1c3c4c 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -1464,12 +1464,14 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" 1 : select matching instances -1 : unselect matching instances 'tok' set as: + <attr> : will search for 'val' in instance attribute 'attr' propstring : will search for 'val' in the entire *instance* attribute string. + txt_ptr : this is used to search only the txt_ptr string of text pbjects cell::propstring : will search for 'val' in the entire *symbol* attribute string. cell::name : will search for 'val' in the symbol name - cell::<attr> will search for 'val' in symbol attribute 'attr' + cell::<attr> : will search for 'val' in symbol attribute 'attr' example: xschem search regex 0 cell::template GAIN=100 if 'no_match_case' is specified do not consider case sensitivity in search if 'nodraw' is specified do not draw search result diff --git a/src/hilight.c b/src/hilight.c index 5eb5d7ff..966675c6 100644 --- a/src/hilight.c +++ b/src/hilight.c @@ -790,7 +790,13 @@ int search(const char *tok, const char *val, int sub, int sel, int match_case, i #else char *regexp_options = NULL; #endif + int only_text_search = 0; + if(!tok) { + fprintf(errfp, "search(): warning: null tok key\n"); + return TCL_ERROR; + } + if(!strcmp(tok, "txt_ptr")) only_text_search = 1; if(!val) { fprintf(errfp, "search(): warning: null val key\n"); return TCL_ERROR; @@ -819,217 +825,223 @@ int search(const char *tok, const char *val, int sub, int sel, int match_case, i } has_token = 0; prepare_netlist_structs(0); - bus=bus_search(val); /* searching for a single bit in a bus, like val -> "DATA[13]" */ - for(i=0;iinstances; ++i) { - if(!strcmp(tok,"cell::name")) { - has_token = (xctx->inst[i].name != NULL) && xctx->inst[i].name[0]; - str = xctx->inst[i].name; - } else if(!strcmp(tok,"cell::propstring")) { - has_token = (str = (xctx->inst[i].ptr+ xctx->sym)->prop_ptr) ? 1 : 0; - } else if(!strncmp(tok,"cell::", 6)) { /* cell::xxx looks for xxx in global symbol attributes */ - my_strdup(_ALLOC_ID_, &tmpname,get_tok_value(xctx->sym[xctx->inst[i].ptr].prop_ptr,tok+6,0)); - has_token = xctx->tok_size; - if(tmpname) { - str = tmpname; + + if(!only_text_search) { + bus=bus_search(val); /* searching for a single bit in a bus, like val -> "DATA[13]" */ + for(i=0;iinstances; ++i) { + if(!strcmp(tok,"cell::name")) { + has_token = (xctx->inst[i].name != NULL) && xctx->inst[i].name[0]; + str = xctx->inst[i].name; + } else if(!strcmp(tok,"cell::propstring")) { + has_token = (str = (xctx->inst[i].ptr+ xctx->sym)->prop_ptr) ? 1 : 0; + } else if(!strncmp(tok,"cell::", 6)) { /* cell::xxx looks for xxx in global symbol attributes */ + my_strdup(_ALLOC_ID_, &tmpname,get_tok_value(xctx->sym[xctx->inst[i].ptr].prop_ptr,tok+6,0)); + has_token = xctx->tok_size; + if(tmpname) { + str = tmpname; + } else { + str = empty_string; + } + } else if(!strcmp(tok,"propstring")) { + has_token = (xctx->inst[i].prop_ptr != NULL) && xctx->inst[i].prop_ptr[0]; + str = xctx->inst[i].prop_ptr; } else { - str = empty_string; + str = get_tok_value(xctx->inst[i].prop_ptr, tok,0); + has_token = xctx->tok_size; } - } else if(!strcmp(tok,"propstring")) { - has_token = (xctx->inst[i].prop_ptr != NULL) && xctx->inst[i].prop_ptr[0]; - str = xctx->inst[i].prop_ptr; - } else { - str = get_tok_value(xctx->inst[i].prop_ptr, tok,0); - has_token = xctx->tok_size; - } - dbg(1, "search(): inst=%d, tok=%s, val=%s \n", i,tok, str); - - if(bus && sub) { - dbg(1, "search(): doing substr search on bus sig:%s inst=%d tok=%s val=%s\n", str,i,tok,val); - str=expandlabel(str,&tmp); - } - if(str && has_token) { - #ifdef __unix__ - if( (!sub && !regexec(&re, str,0 , NULL, 0) ) || /* 20071120 regex instead of strcmp */ - (sub && !bus && !comparefn(str, val)) || (sub && bus && substrfn(str,val))) - #else - if( (!sub && win_regexec(regexp_options, val, str)) || - (sub && !bus && !comparefn(str, val)) || (sub && bus && substrfn(str,val))) - #endif - { - if(!sel) { - type = (xctx->inst[i].ptr+ xctx->sym)->type; - if( !strcmp(tok, "lab") && type && xctx->inst[i].node && IS_LABEL_SH_OR_PIN(type) ) { - bus_hilight_hash_lookup(xctx->inst[i].node[0], col, XINSERT_NOREPLACE); /* sets xctx->hilight_nets=1; */ - } else { - dbg(1, "search(): setting hilight flag on inst %d\n",i); - /* xctx->hilight_nets=1; */ /* done in hilight_hash_lookup() */ - xctx->inst[i].color = col; - inst_hilight_hash_lookup(i, col, XINSERT_NOREPLACE); + dbg(1, "search(): inst=%d, tok=%s, val=%s \n", i,tok, str); + + if(bus && sub) { + dbg(1, "search(): doing substr search on bus sig:%s inst=%d tok=%s val=%s\n", str,i,tok,val); + str=expandlabel(str,&tmp); + } + if(str && has_token) { + #ifdef __unix__ + if( (!sub && !regexec(&re, str,0 , NULL, 0) ) || /* 20071120 regex instead of strcmp */ + (sub && !bus && !comparefn(str, val)) || (sub && bus && substrfn(str,val))) + #else + if( (!sub && win_regexec(regexp_options, val, str)) || + (sub && !bus && !comparefn(str, val)) || (sub && bus && substrfn(str,val))) + #endif + { + if(!sel) { + type = (xctx->inst[i].ptr+ xctx->sym)->type; + if( !strcmp(tok, "lab") && type && xctx->inst[i].node && IS_LABEL_SH_OR_PIN(type) ) { + bus_hilight_hash_lookup(xctx->inst[i].node[0], col, XINSERT_NOREPLACE); /* sets xctx->hilight_nets=1; */ + } else { + dbg(1, "search(): setting hilight flag on inst %d\n",i); + /* xctx->hilight_nets=1; */ /* done in hilight_hash_lookup() */ + xctx->inst[i].color = col; + inst_hilight_hash_lookup(i, col, XINSERT_NOREPLACE); + } } - } - if(sel==1) { - xctx->inst[i].sel = SELECTED; - set_first_sel(ELEMENT, i, 0); - xctx->need_reb_sel_arr=1; - } - if(sel==-1) { /* 20171211 unselect */ - xctx->inst[i].sel = 0; - xctx->need_reb_sel_arr=1; - } - found = 1; - } - } - } - for(i=0;iwires; ++i) { - str = get_tok_value(xctx->wire[i].prop_ptr, tok,0); - if(xctx->tok_size ) { - #ifdef __unix__ - if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || /* 20071120 regex instead of strcmp */ - ( !comparefn(str, val) && sub ) ) - #else - if( (win_regexec(regexp_options, val, str) && !sub ) || /* 20071120 regex instead of strcmp */ - ( !comparefn(str, val) && sub ) ) - - #endif - { - if(!sel) { - bus_hilight_hash_lookup(xctx->wire[i].node, col, XINSERT_NOREPLACE); /* sets xctx->hilight_nets = 1 */ - } - if(sel==1) { - xctx->wire[i].sel = SELECTED; - set_first_sel(WIRE, i, 0); - xctx->need_reb_sel_arr=1; - } - if(sel==-1) { - xctx->wire[i].sel = 0; - xctx->need_reb_sel_arr=1; - } - found = 1; - } - else { - dbg(2, "search(): not found wire=%d, tok=%s, val=%s search=%s\n", i,tok, str,val); - } - } - } - if(!sel && xctx->hilight_nets) propagate_hilights(1, 0, XINSERT_NOREPLACE); - if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;ilines[c]; ++i) { - str = get_tok_value(xctx->line[c][i].prop_ptr, tok,0); - if(xctx->tok_size) { - #ifdef __unix__ - if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || - ( !comparefn(str, val) && sub )) - #else - if( (win_regexec(regexp_options, val, str) && !sub ) || - ( !comparefn(str, val) && sub )) - #endif - { - if(sel==1) { - xctx->line[c][i].sel = SELECTED; - set_first_sel(LINE, i, c); - xctx->need_reb_sel_arr=1; - } - if(sel==-1) { - xctx->line[c][i].sel = 0; - xctx->need_reb_sel_arr=1; - } - found = 1; - } - else { - dbg(2, "search(): not found line=%d col=%d, tok=%s, val=%s search=%s\n", - i, c, tok, str, val); - } - } - } - if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;irects[c]; ++i) { - str = get_tok_value(xctx->rect[c][i].prop_ptr, tok,0); - if(xctx->tok_size) { - #ifdef __unix__ - if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || - ( !comparefn(str, val) && sub )) - #else - if( (win_regexec(regexp_options, val, str) && !sub ) || - ( !comparefn(str, val) && sub )) - #endif - { if(sel==1) { - xctx->rect[c][i].sel = SELECTED; - set_first_sel(xRECT, i, c); + xctx->inst[i].sel = SELECTED; + set_first_sel(ELEMENT, i, 0); + xctx->need_reb_sel_arr=1; + } + if(sel==-1) { /* 20171211 unselect */ + xctx->inst[i].sel = 0; + xctx->need_reb_sel_arr=1; + } + found = 1; + } + } + } + for(i=0;iwires; ++i) { + str = get_tok_value(xctx->wire[i].prop_ptr, tok,0); + if(xctx->tok_size ) { + #ifdef __unix__ + if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || /* 20071120 regex instead of strcmp */ + ( !comparefn(str, val) && sub ) ) + #else + if( (win_regexec(regexp_options, val, str) && !sub ) || /* 20071120 regex instead of strcmp */ + ( !comparefn(str, val) && sub ) ) + + #endif + { + if(!sel) { + bus_hilight_hash_lookup(xctx->wire[i].node, col, XINSERT_NOREPLACE); /* sets xctx->hilight_nets = 1 */ + } + if(sel==1) { + xctx->wire[i].sel = SELECTED; + set_first_sel(WIRE, i, 0); xctx->need_reb_sel_arr=1; } if(sel==-1) { - xctx->rect[c][i].sel = 0; + xctx->wire[i].sel = 0; xctx->need_reb_sel_arr=1; } found = 1; - } - else { - dbg(2, "search(): not found rect=%d col=%d, tok=%s, val=%s search=%s\n", - i, c, tok, str, val); + } + else { + dbg(2, "search(): not found wire=%d, tok=%s, val=%s search=%s\n", i,tok, str,val); + } } } - } - - if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;iarcs[c]; ++i) { - str = get_tok_value(xctx->arc[c][i].prop_ptr, tok,0); - if(xctx->tok_size) { - #ifdef __unix__ - if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || - ( !comparefn(str, val) && sub )) - #else - if( (win_regexec(regexp_options, val, str) && !sub ) || - ( !comparefn(str, val) && sub )) - #endif - { + if(!sel && xctx->hilight_nets) propagate_hilights(1, 0, XINSERT_NOREPLACE); + if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;ilines[c]; ++i) { + str = get_tok_value(xctx->line[c][i].prop_ptr, tok,0); + if(xctx->tok_size) { + #ifdef __unix__ + if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || + ( !comparefn(str, val) && sub )) + #else + if( (win_regexec(regexp_options, val, str) && !sub ) || + ( !comparefn(str, val) && sub )) + #endif + { if(sel==1) { - xctx->arc[c][i].sel = SELECTED; - set_first_sel(ARC, i, c); + xctx->line[c][i].sel = SELECTED; + set_first_sel(LINE, i, c); xctx->need_reb_sel_arr=1; } if(sel==-1) { - xctx->arc[c][i].sel = 0; + xctx->line[c][i].sel = 0; xctx->need_reb_sel_arr=1; } found = 1; - } - else { - dbg(2, "search(): not found arc=%d col=%d, tok=%s, val=%s search=%s\n", - i, c, tok, str, val); + } + else { + dbg(2, "search(): not found line=%d col=%d, tok=%s, val=%s search=%s\n", + i, c, tok, str, val); + } } } - } - - if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;ipolygons[c]; ++i) { - str = get_tok_value(xctx->poly[c][i].prop_ptr, tok,0); - if(xctx->tok_size) { - #ifdef __unix__ - if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || - ( !comparefn(str, val) && sub )) - #else - if( (win_regexec(regexp_options, val, str) && !sub ) || - ( !comparefn(str, val) && sub )) - #endif - { - if(sel==1) { - xctx->poly[c][i].sel = SELECTED; - set_first_sel(POLYGON, i, c); - xctx->need_reb_sel_arr=1; - } - if(sel==-1) { - xctx->poly[c][i].sel = 0; - xctx->need_reb_sel_arr=1; - } - found = 1; - } - else { - dbg(2, "search(): not found arc=%d col=%d, tok=%s, val=%s search=%s\n", - i, c, tok, str, val); + if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;irects[c]; ++i) { + str = get_tok_value(xctx->rect[c][i].prop_ptr, tok,0); + if(xctx->tok_size) { + #ifdef __unix__ + if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || + ( !comparefn(str, val) && sub )) + #else + if( (win_regexec(regexp_options, val, str) && !sub ) || + ( !comparefn(str, val) && sub )) + #endif + { + if(sel==1) { + xctx->rect[c][i].sel = SELECTED; + set_first_sel(xRECT, i, c); + xctx->need_reb_sel_arr=1; + } + if(sel==-1) { + xctx->rect[c][i].sel = 0; + xctx->need_reb_sel_arr=1; + } + found = 1; + } + else { + dbg(2, "search(): not found rect=%d col=%d, tok=%s, val=%s search=%s\n", + i, c, tok, str, val); + } } } - } - + + if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;iarcs[c]; ++i) { + str = get_tok_value(xctx->arc[c][i].prop_ptr, tok,0); + if(xctx->tok_size) { + #ifdef __unix__ + if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || + ( !comparefn(str, val) && sub )) + #else + if( (win_regexec(regexp_options, val, str) && !sub ) || + ( !comparefn(str, val) && sub )) + #endif + { + if(sel==1) { + xctx->arc[c][i].sel = SELECTED; + set_first_sel(ARC, i, c); + xctx->need_reb_sel_arr=1; + } + if(sel==-1) { + xctx->arc[c][i].sel = 0; + xctx->need_reb_sel_arr=1; + } + found = 1; + } + else { + dbg(2, "search(): not found arc=%d col=%d, tok=%s, val=%s search=%s\n", + i, c, tok, str, val); + } + } + } + + if(sel) for(c = 0; c < cadlayers; ++c) for(i=0;ipolygons[c]; ++i) { + str = get_tok_value(xctx->poly[c][i].prop_ptr, tok,0); + if(xctx->tok_size) { + #ifdef __unix__ + if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || + ( !comparefn(str, val) && sub )) + #else + if( (win_regexec(regexp_options, val, str) && !sub ) || + ( !comparefn(str, val) && sub )) + #endif + { + if(sel==1) { + xctx->poly[c][i].sel = SELECTED; + set_first_sel(POLYGON, i, c); + xctx->need_reb_sel_arr=1; + } + if(sel==-1) { + xctx->poly[c][i].sel = 0; + xctx->need_reb_sel_arr=1; + } + found = 1; + } + else { + dbg(2, "search(): not found arc=%d col=%d, tok=%s, val=%s search=%s\n", + i, c, tok, str, val); + } + } + } + } /* if(!only_text_search) */ if(sel) for(i=0;itexts; ++i) { - str = get_tok_value(xctx->text[i].prop_ptr, tok,0); + if(!strcmp(tok, "txt_ptr")) { + str = xctx->text[i].txt_ptr; + if(!str) continue; + xctx->tok_size = 1; + } else str = get_tok_value(xctx->text[i].prop_ptr, tok,0); if(xctx->tok_size) { #ifdef __unix__ if( (!regexec(&re, str,0 , NULL, 0) && !sub ) || @@ -1058,10 +1070,11 @@ int search(const char *tok, const char *val, int sub, int sel, int match_case, i } if(found) { - if(tclgetboolvar("incr_hilight")) incr_hilight_color(); + if(sel == 0 && tclgetboolvar("incr_hilight")) incr_hilight_color(); if(sel == -1) { if(dr) draw(); } + else if(sel) { rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ if(dr) draw_selection(xctx->gc[SELLAYER], 0); diff --git a/src/scheduler.c b/src/scheduler.c index fdb80fbf..ae5def55 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -5173,12 +5173,14 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg * 1 : select matching instances * -1 : unselect matching instances * 'tok' set as: + : will search for 'val' in instance attribute 'attr' * propstring : will search for 'val' in the entire * *instance* attribute string. + * txt_ptr : this is used to search only the txt_ptr string of text pbjects * cell::propstring : will search for 'val' in the entire * *symbol* attribute string. * cell::name : will search for 'val' in the symbol name - * cell:: will search for 'val' in symbol attribute 'attr' + * cell:: : will search for 'val' in symbol attribute 'attr' * example: xschem search regex 0 cell::template GAIN=100 * if 'no_match_case' is specified do not consider case sensitivity in search * if 'nodraw' is specified do not draw search result