1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Wed Jan 14 14:20:33 2009
19 ****************************************************************************/
20 #include "tkgate.h"
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <unistd.h>
25 #include <string.h>
26
27 /*****************************************************************************
28 *
29 * Create a "GSearchContext" object used for keeping information about search
30 * operations.
31 *
32 *****************************************************************************/
new_GSearchContext()33 GSearchContext *new_GSearchContext()
34 {
35 GSearchContext *S = (GSearchContext *) ob_malloc(sizeof(GSearchContext),"GSearchContext");
36
37 S->mode = 0;
38 S->target = 0;
39 S->m_elem = 0;
40 S->g_elem = 0;
41 S->n_elem = 0;
42
43 return S;
44 }
45
46 /*****************************************************************************
47 *
48 * Set the position as a result of a search.
49 *
50 *****************************************************************************/
GSearchContext_setPosition(GModuleDef * M,GCElement * g,GNet * n)51 void GSearchContext_setPosition(GModuleDef *M,GCElement *g,GNet *n)
52 {
53 int x,y;
54
55 x = y = 0;
56
57 if (TkGate.circuit->es->env != M) {
58 ob_touch(TkGate.circuit);
59 editstate_navigateToModule(&TkGate.circuit->es,M);
60 editstate_setCurrent(TkGate.circuit->es);
61 ClearErrorMark();
62 }
63
64 if (g) {
65 int minx,miny,maxx,maxy;
66
67 gate_getbbx(g,TD_X11,&minx,&miny,&maxx,&maxy);
68 x = (minx+maxx)/2;
69 y = (miny+maxy)/2;
70
71 TkGate_clearSelection();
72 sel_clear(TkGate.circuit->es,1);
73 sel_appendGate(TkGate.circuit->es,g,1);
74 sel_finish(TkGate.circuit->es);
75
76 message(0,msgLookup("msg.foundgate"),g->ename); /* "Found gate named '%s'" */
77 } else if (n) {
78 GWireNode *wn1,*wn2;
79
80 wn1 = n->n_driver->nodes;
81 wn2 = wn1->out ? wn1->out : wn1->in;
82
83 x = (wn1->x + wn2->x)/2;
84 y = (wn1->y + wn2->y)/2;
85
86 TkGate_clearSelection();
87 sel_clear(TkGate.circuit->es,1);
88
89 message(0,msgLookup("msg.foundwire"),n->n_signame); /* "Found wire named '%s'" */
90 }
91
92
93 TkGate_setOrigin(TkGate.width/2 - x,TkGate.height/2 - y);
94 ob_touch(TkGate.circuit->es);
95 editstate_saveOrig(TkGate.circuit->es);
96
97 SetErrorPosition(x,y);
98 FlagRedraw();
99 }
100
101 /*****************************************************************************
102 *
103 * Clear the context from a seach operation
104 *
105 *****************************************************************************/
GSearchContext_clear(GSearchContext * S)106 void GSearchContext_clear(GSearchContext *S)
107 {
108 ob_touch(S);
109 S->mode = 0;
110 if (S->target) ob_free(S->target);
111 S->target = 0;
112 S->m_elem = 0;
113 S->g_elem = 0;
114 S->n_elem = 0;
115 }
116
GSearchContext_strcmp(GSearchContext * S,const char * s1,const char * s2)117 static int GSearchContext_strcmp(GSearchContext *S,const char *s1,const char *s2)
118 {
119 if ((S->mode & SF_IGNORECASE))
120 return strcasecmp(s1,s2);
121 else
122 return strcmp(s1,s2);
123 }
124
GSearchContext_strncmp(GSearchContext * S,const char * s1,const char * s2,int n)125 static int GSearchContext_strncmp(GSearchContext *S,const char *s1,const char *s2,int n)
126 {
127 if ((S->mode & SF_IGNORECASE))
128 return strncasecmp(s1,s2,n);
129 else
130 return strncmp(s1,s2,n);
131 }
132
GSearchContext_strstr(GSearchContext * S,const char * s1,const char * s2)133 static char *GSearchContext_strstr(GSearchContext *S,const char *s1,const char *s2)
134 {
135 if ((S->mode & SF_IGNORECASE))
136 return strcasestr(s1,s2);
137 else
138 return strstr(s1,s2);
139 }
140
141
142 /*****************************************************************************
143 *
144 * Find a string with the specified mode values.
145 *
146 * Parameters:
147 * S The search context to use
148 * target The string to look for
149 * mode Search mode specifier
150 * qualifier Search qualifier (contains, begins, ends)
151 *
152 *****************************************************************************/
GSearchContext_find(GSearchContext * S,const char * target,int mode,int qualifier)153 void GSearchContext_find(GSearchContext *S,const char *target,int mode,int qualifier)
154 {
155 GModuleDef *M = 0;
156
157 /*
158 * If no target string, clear the search context and return.
159 */
160 if (!*target) {
161 GSearchContext_clear(S);
162 return;
163 }
164
165 /*
166 * If any search parameters have changed, clear the current context
167 * to begin a new search.
168 */
169 if (S->mode != mode || !S->target || GSearchContext_strcmp(S,S->target,target) != 0)
170 GSearchContext_clear(S);
171
172 ob_touch(S);
173 if (S->target) ob_free(S->target);
174 S->target = ob_strdup(target);
175 S->mode = mode;
176
177 if (!S->m_elem) {
178 S->m_elem = Hash_first(TkGate.circuit->moduleTable);
179 if (S->m_elem) {
180 M = (GModuleDef *) HashElem_obj(S->m_elem);
181 if ((mode & SF_GATES)) S->g_elem = Hash_first(M->m_gates);
182 if ((mode & SF_NETS)) S->n_elem = Hash_first(M->m_gates);
183 }
184 } else
185 M = (GModuleDef *) HashElem_obj(S->m_elem);
186
187 while (S->m_elem) {
188 if (S->g_elem) {
189 GCElement *g = (GCElement*) HashElem_obj(S->g_elem);
190 S->g_elem = Hash_next(M->m_gates,S->g_elem);
191
192 if (g->typeinfo->code == GC_JOINT) continue;
193
194 if (GSearchContext_strstr(S,g->ename,S->target)) {
195 GSearchContext_setPosition(M,g,0);
196 return;
197 }
198 } else if (S->n_elem) {
199 GNet *n = (GNet*) HashElem_obj(S->n_elem);
200 S->n_elem = Hash_next(M->m_nets,S->n_elem);
201
202 if (GSearchContext_strstr(S,n->n_signame,S->target)) {
203 GSearchContext_setPosition(M,0,n);
204 return;
205 }
206 } else {
207 S->m_elem = Hash_next(TkGate.circuit->moduleTable,S->m_elem);
208 if (S->m_elem) {
209 M = (GModuleDef *) HashElem_obj(S->m_elem);
210 if ((mode & SF_GATES)) S->g_elem = Hash_first(M->m_gates);
211 if ((mode & SF_NETS)) S->n_elem = Hash_first(M->m_nets);
212 }
213 }
214 }
215 message(1,msgLookup("msg.searchagn"),S->target); /* Target string '%s' not found. Hit 'find' to restart search again. */
216 }
217
218 /*****************************************************************************
219 *
220 * Search some text for a match
221 *
222 * Parameters:
223 * S The search context to use
224 * target Target string to look for.
225 * text String to search for target
226 * modName Name of module to report on hit
227 * typeName Type of object to report on hit
228 * objName Name of object to report on hit
229 * qualifier Search qualifier
230 * result Result variable to use
231 * *count Count of hits
232 * lineNo Line number if this is a comment (-1 otherwise)
233 *
234 *****************************************************************************/
Search_hitTest(GSearchContext * S,const char * target,const char * text,const char * modName,const char * typeName,const char * objName,int qualifier,const char * result,int * count,int lineNo)235 static int Search_hitTest(GSearchContext *S,const char *target,const char *text,const char *modName,const char *typeName,
236 const char *objName,int qualifier, const char *result, int *count,int lineNo)
237 {
238 char buf[STRMAX],scount[STRMAX];
239 int isHit = 0;
240 int target_len;
241 int text_len;
242 const char *p = 0;
243
244 switch (qualifier) {
245 case SQ_CONTAINS :
246 if ((p = GSearchContext_strstr(S,text,target)))
247 isHit = 1;
248 break;
249 case SQ_BEGINS :
250 target_len = strlen(target);
251 if (GSearchContext_strncmp(S,target,text,target_len) == 0) {
252 isHit = 1;
253 p = text;
254 }
255 break;
256 case SQ_ENDS :
257 target_len = strlen(target);
258 text_len = strlen(text);
259 if (target_len <= text_len && GSearchContext_strncmp(S,target,text+text_len-target_len,target_len) == 0) {
260 isHit = 1;
261 p = text+text_len-target_len;
262 }
263 break;
264 case SQ_MATCHES :
265 if (GSearchContext_strcmp(S,target,text) == 0) {
266 isHit = 1;
267 p = text;
268 }
269 break;
270 }
271
272 /*
273 * Report the search hit
274 */
275 if (isHit) {
276 if (lineNo > 0)
277 sprintf(buf,"%s %s %s@%d.%ld",modName,typeName,objName,lineNo,(p-text));
278 else
279 sprintf(buf,"%s %s %s",modName,typeName,objName);
280 sprintf(scount,"%d",(*count)++);
281 Tcl_SetVar2(TkGate.tcl,(char*)result,scount,buf,TCL_GLOBAL_ONLY);
282 }
283
284 return isHit;
285 }
286
287 /*****************************************************************************
288 *
289 * Get list of hits for a specified search target
290 *
291 * Parameters:
292 * S The search context to use
293 * target The string to look for
294 * mode Search mode specifier
295 * qualifier Search qualifier (contains, begins, ends)
296 *
297 *****************************************************************************/
GSearchContext_list(GSearchContext * S,const char * target,int mode,int qualifier,const char * result)298 void GSearchContext_list(GSearchContext *S,const char *target,int mode,int qualifier,const char *result)
299 {
300 HashElem *ME,*E;
301 int count = 0;
302 char scount[STRMAX];
303
304 S->mode = mode;
305
306 /*
307 * If no target string, return
308 */
309 if (!*target) {
310 return;
311 }
312
313 for (ME = Hash_first(TkGate.circuit->moduleTable);ME; ME = Hash_next(TkGate.circuit->moduleTable,ME)) {
314 GModuleDef *M = (GModuleDef *) HashElem_obj(ME);
315
316 if ((mode & SF_GATES) || (mode & SF_TEXT)) {
317 for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
318 GCElement *g = (GCElement*) HashElem_obj(E);
319
320 if (g->typeinfo->code == GC_JOINT) continue;
321
322 if ((mode & SF_GATES)) {
323 if (Search_hitTest(S,target, g->ename, M->m_name, "gate", g->ename, qualifier, result, &count,-1))
324 continue;
325 }
326
327 if ((mode & SF_TEXT) && g->typeinfo->code == GC_COMMENT) {
328 TextLine *CL;
329 int lineNo = 1;
330
331 for (CL = g->u.comment.first;CL;CL = CL->next) {
332 if (Search_hitTest(S,target, CL->text, M->m_name, "comment", g->ename, qualifier, result, &count,lineNo++))
333 break;
334 }
335 }
336 }
337 }
338
339 if ((mode & SF_NETS)) {
340 for (E = Hash_first(M->m_nets);E;E = Hash_next(M->m_nets,E)) {
341 GNet *n = (GNet*) HashElem_obj(E);
342
343 Search_hitTest(S, target, n->n_signame, M->m_name, "net", n->n_signame, qualifier, result, &count,-1);
344 }
345 }
346 }
347
348 sprintf(scount,"%d",count);
349 Tcl_SetVar2(TkGate.tcl,(char*)result,"count",scount,TCL_GLOBAL_ONLY);
350 }
351
352 /*****************************************************************************
353 *
354 * Search for an object by name and open it in an edit window.
355 *
356 * Parameters:
357 * spec Specification of object
358 *
359 *****************************************************************************/
GSearchContext_goto(const char * spec)360 void GSearchContext_goto(const char *spec)
361 {
362 char modName[STRMAX];
363 char typeName[STRMAX];
364 char objName[STRMAX];
365
366 if (sscanf(spec,"%s %s %[^ \t@]",modName,typeName,objName) == 3) {
367 GModuleDef *M = env_findModule(modName);
368 GNet *n = 0;
369 GCElement *g = 0;
370
371 if (M) {
372 if (strcmp(typeName,"net") == 0)
373 n = GModuleDef_findNet(M,objName);
374 else
375 g = GModuleDef_findGate(M,objName);
376 }
377
378 if (g || n) {
379 GSearchContext_setPosition(M,g,n);
380 } else {
381 message(1,msgLookup("err.badfind"),objName);
382 }
383 }
384 }
385