missing NULL terminator in set_config_x
[geda-gaf.git] / gnetlist-legacy / src / s_traverse.c
blob8b133620efc7d3dde9637ddf9a17d38eea798f95
1 /* gEDA - GPL Electronic Design Automation
2 * gnetlist - gEDA Netlist
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <config.h>
23 #include <stdio.h>
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 #include <math.h>
29 #include <libgeda/libgeda.h>
31 #include "../include/globals.h"
32 #include "../include/prototype.h"
33 #include "../include/gettext.h"
35 /*! Tracks which OBJECTs have been visited so far, and how many times.
37 * The keys of the table are the OBJECT pointers, and the visit count
38 * is stored directly in the value pointers.
40 static GHashTable *visit_table = NULL;
42 /*! Trivial function used when clearing #visit_table. */
43 static gboolean
44 returns_true (gpointer key, gpointer value, gpointer user_data)
46 return TRUE;
49 /*! Retrieve the current visit count for a particular OBJECT. */
50 static inline gint
51 is_visited(OBJECT *obj)
53 gpointer val;
54 gpointer orig_key;
55 gboolean exist = g_hash_table_lookup_extended (visit_table,
56 obj,
57 &orig_key,
58 &val);
59 return exist ? GPOINTER_TO_INT(val) : 0;
62 /*! Increment the current visit count for a particular OBJECT. */
63 static inline gint
64 visit(OBJECT *obj)
66 gpointer val = GINT_TO_POINTER(is_visited (obj) + 1);
67 g_hash_table_replace (visit_table, obj, val);
68 return GPOINTER_TO_INT (val);
71 /*! Reset all visit counts. Simply clears the hashtable completely. */
72 static inline void
73 s_traverse_clear_all_visited (const GList *obj_list)
75 g_hash_table_foreach_remove (visit_table,
76 (GHRFunc) returns_true,
77 NULL);
80 void s_traverse_init(void)
82 netlist_head = s_netlist_add(NULL);
83 netlist_head->nlid = -1; /* head node */
85 graphical_netlist_head = s_netlist_add(NULL);
86 graphical_netlist_head->nlid = -1; /* head node */
88 if (verbose_mode) {
89 printf
90 ("\n\n------------------------------------------------------\n");
91 printf("Verbose mode legend\n\n");
92 printf("n : Found net\n");
93 printf("C : Found component (staring to traverse component)\n");
94 printf
95 ("p : Found pin (starting to traverse pin / or examining pin)\n");
96 printf("P : Found end pin connection (end of this net)\n");
97 printf("R : Starting to rename a net\n");
98 printf("v : Found source attribute, traversing down\n");
99 printf("^ : Finished underlying source, going back up\n");
100 printf("u : Found a refdes which needs to be demangle\n");
101 printf
102 ("U : Found a connected_to refdes which needs to be demangle\n");
103 printf
104 ("------------------------------------------------------\n\n");
108 /* Initialise the hashtable which contains the visit
109 count. N.b. no free functions are required. */
110 visit_table = g_hash_table_new (g_direct_hash,
111 g_direct_equal);
114 void s_traverse_start(TOPLEVEL * pr_current)
116 GList *iter;
117 PAGE *p_current;
119 for ( iter = geda_list_get_glist( pr_current->pages );
120 iter != NULL;
121 iter = g_list_next( iter ) ) {
123 p_current = (PAGE *)iter->data;
125 /* only traverse pages which are toplevel, ie not underneath */
126 if (p_current->page_control == 0) {
127 pr_current->page_current = p_current;
128 s_traverse_sheet (pr_current, s_page_objects (p_current), NULL);
132 /* now that all the sheets have been read, go through and do the */
133 /* post processing work */
134 s_netlist_post_process(pr_current, netlist_head);
136 /* Now match the graphical netlist with the net names already assigned */
137 s_netlist_name_named_nets(pr_current, netlist_head,
138 graphical_netlist_head);
140 if (verbose_mode) {
141 printf("\nInternal netlist representation:\n\n");
142 s_netlist_print(netlist_head);
147 void
148 s_traverse_sheet (TOPLEVEL * pr_current, const GList *obj_list, char *hierarchy_tag)
150 NETLIST *netlist;
151 char *temp;
152 SCM scm_uref;
153 char *temp_uref;
154 const GList *iter;
156 if (verbose_mode) {
157 printf("- Starting internal netlist creation\n");
160 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
161 OBJECT *o_current = iter->data;
163 netlist = s_netlist_return_tail(netlist_head);
165 if (o_current->type == OBJ_PLACEHOLDER) {
166 printf(_("WARNING: Found a placeholder/missing component, are you missing a symbol file? [%s]\n"), o_current->complex_basename);
169 if (o_current->type == OBJ_COMPLEX) {
170 gboolean is_graphical = FALSE;
172 #if DEBUG
173 printf("starting NEW component\n\n");
174 #endif
176 verbose_print(" C");
178 /* look for special tag */
179 temp = o_attrib_search_object_attribs_by_name (o_current, "graphical", 0);
180 if (g_strcmp0 (temp, "1") == 0) {
181 /* traverse graphical elements, but adding them to the
182 graphical netlist */
184 netlist = s_netlist_return_tail(graphical_netlist_head);
185 is_graphical = TRUE;
189 g_free (temp);
190 netlist = s_netlist_add(netlist);
191 netlist->nlid = o_current->sid;
193 scm_uref = g_scm_c_get_uref (o_current);
195 if (scm_is_string( scm_uref )) {
196 temp_uref = scm_to_utf8_string (scm_uref);
197 netlist->component_uref =
198 s_hierarchy_create_uref(pr_current, temp_uref, hierarchy_tag);
199 g_free(temp_uref);
200 } else {
201 if (hierarchy_tag) {
202 netlist->component_uref = g_strdup (hierarchy_tag);
203 } else {
204 netlist->component_uref = NULL;
208 if (hierarchy_tag) {
209 netlist->hierarchy_tag = g_strdup (hierarchy_tag);
212 netlist->object_ptr = o_current;
214 if (!netlist->component_uref) {
216 /* search of net attribute */
217 /* maybe symbol is not a component */
218 /* but a power / gnd symbol */
219 temp = o_attrib_search_object_attribs_by_name (o_current, "net", 0);
221 /* nope net attribute not found */
222 if ( (!temp) && (!is_graphical) ) {
224 fprintf(stderr,
225 _("Could not find refdes on component and could not find any special attributes!\n"));
227 netlist->component_uref = g_strdup("U?");
228 } else {
230 #if DEBUG
231 printf("yeah... found a power symbol\n");
232 #endif
233 /* it's a power or some other special symbol */
234 netlist->component_uref = NULL;
235 g_free(temp);
240 netlist->cpins =
241 s_traverse_component(pr_current, o_current,
242 hierarchy_tag);
244 /* here is where you deal with the */
245 /* net attribute */
246 s_netattrib_handle(pr_current, o_current, netlist,
247 hierarchy_tag);
249 /* now you need to traverse any underlying schematics */
250 if (pr_current->hierarchy_traversal == TRUE) {
251 s_hierarchy_traverse(pr_current, o_current, netlist);
256 verbose_done();
259 CPINLIST *s_traverse_component(TOPLEVEL * pr_current, OBJECT * component,
260 char *hierarchy_tag)
262 CPINLIST *cpinlist_head = NULL;
263 CPINLIST *cpins = NULL;
264 NET *nets_head = NULL;
265 NET *nets = NULL;
266 GList *iter;
268 cpinlist_head = cpins = s_cpinlist_add(NULL);
269 cpins->plid = -1;
271 for (iter = component->complex->prim_objs;
272 iter != NULL;
273 iter = g_list_next (iter)) {
274 OBJECT *o_current = iter->data;
276 /* Ignore objects which aren't net pins */
277 if (o_current->type != OBJ_PIN ||
278 o_current->pin_type != PIN_TYPE_NET)
279 continue;
281 /* add cpin node */
282 cpins = s_cpinlist_add(cpins);
283 cpins->plid = o_current->sid;
284 cpins->type = o_current->pin_type;
286 cpins->pin_number =
287 o_attrib_search_object_attribs_by_name (o_current, "pinnumber", 0);
289 cpins->pin_label =
290 o_attrib_search_object_attribs_by_name (o_current, "pinlabel", 0);
292 /* head nets node */
293 /* is this really need */
294 nets_head = nets = s_net_add(NULL);
295 nets->nid = -1;
297 /* This avoids us adding an unnamed net for an unconnected pin */
298 if (o_current->conn_list != NULL) {
299 s_traverse_net (pr_current, nets, TRUE,
300 o_current, hierarchy_tag, cpins->type);
301 s_traverse_clear_all_visited (s_page_objects (pr_current->page_current));
304 cpins->nets = nets_head;
305 /* s_net_print(nets); */
309 return (cpinlist_head);
313 static int connection_type (OBJECT *object)
315 switch (object->type) {
316 case OBJ_PIN: return object->pin_type;
317 case OBJ_NET: return PIN_TYPE_NET;
318 case OBJ_BUS: return PIN_TYPE_BUS;
319 default:
320 g_critical (_("Non-connectable object being queried for connection type\n"));
321 return PIN_TYPE_NET;
326 NET *s_traverse_net (TOPLEVEL *pr_current, NET *nets, int starting,
327 OBJECT *object, char *hierarchy_tag, int type)
329 NET *new_net;
330 CONN *c_current;
331 GList *cl_current;
332 char *temp = NULL;
333 const gchar *netattrib_pinnum = NULL;
335 visit (object);
337 if (connection_type (object) != type)
338 return nets;
340 new_net = nets = s_net_add(nets);
341 new_net->nid = object->sid;
343 /* pins are not allowed to have the netname attribute attached to them */
344 if (object->type != OBJ_PIN) {
345 /* Ignore netname attributes on buses */
346 if (object->type == OBJ_NET)
347 temp = o_attrib_search_object_attribs_by_name (object, "netname", 0);
349 if (temp) {
350 new_net->net_name =
351 s_hierarchy_create_netname(pr_current, temp,
352 hierarchy_tag);
353 g_free(temp);
354 } else if (object->type == OBJ_NET) {
355 /* search for the old label= attribute on nets */
356 temp = o_attrib_search_object_attribs_by_name (object, "label", 0);
357 if (temp) {
358 printf(_("WARNING: Found label=%s. label= is deprecated, please use netname=\n"), temp);
359 new_net->net_name =
360 s_hierarchy_create_netname(pr_current, temp,
361 hierarchy_tag);
362 g_free(temp);
366 #if DEBUG
367 printf("inside traverse: %s\n", object->name);
368 #endif
370 if (object->type == OBJ_PIN) {
372 verbose_print (starting ? "p" : "P");
374 new_net->connected_to =
375 s_net_return_connected_string (pr_current, object, hierarchy_tag);
377 temp = o_attrib_search_object_attribs_by_name (object, "pinlabel", 0);
379 if (temp) {
380 new_net->pin_label = temp;
383 /* net= new */
384 netattrib_pinnum = s_netattrib_connected_string_get_pinnum (nets->connected_to);
385 if (netattrib_pinnum != NULL && type == PIN_TYPE_NET) {
387 #if DEBUG
388 printf("going to find netname %s \n", nets->connected_to);
389 #endif
390 nets->net_name =
391 s_netattrib_return_netname (pr_current, object,
392 nets->connected_to,
393 hierarchy_tag);
394 nets->net_name_has_priority = TRUE;
395 g_free(nets->connected_to);
396 nets->connected_to = NULL;
398 #if DEBUG
399 printf("traverse connected_to: %s\n", new_net->connected_to);
400 #endif
402 /* Terminate if we hit a pin which isn't the one we started with */
403 if (!starting)
404 return nets;
407 /*printf("Found net %s\n", object->name); */
408 verbose_print("n");
410 /* this is not perfect yet and won't detect a loop... */
411 if (is_visited(object) > 100) {
412 fprintf(stderr, _("Found a possible net/pin infinite connection\n"));
413 exit(-1);
416 cl_current = object->conn_list;
417 while (cl_current != NULL) {
419 c_current = (CONN *) cl_current->data;
421 if (c_current->other_object != NULL) {
423 if (!is_visited(c_current->other_object) &&
424 c_current->other_object != object) {
425 nets = s_traverse_net (pr_current, nets, FALSE,
426 c_current->other_object, hierarchy_tag, type);
430 cl_current = g_list_next(cl_current);
433 return (nets);