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