libgeda: Remove some exit() calls and assertions.
[geda-gaf/peter-b.git] / libgeda / src / s_conn.c
bloba6b207de70fccbcb0d58bcc7a767a79481780757
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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
20 #include <config.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
28 #include "libgeda_priv.h"
30 #ifdef HAVE_LIBDMALLOC
31 #include <dmalloc.h>
32 #endif
34 /*! \file s_conn.c
35 * \brief The connection system
37 * The connection system stores and tracks the connections between
38 * connected <b>OBJECTS</b>. The connected OBJECTS are either
39 * <b>pins</b>, <b>nets</b> and <b>busses</b>.
41 * Each connection object with the type <b>st_conn</b> represents a
42 * single unidirectional relation to another object.
44 * The following figure with two nets and a pin shows the relations
45 * between connections and OBJECTS:
47 * \image html s_conn_overview.png
48 * \image latex s_conn_overview.pdf "Connection overview" width=14cm
52 /*! \brief create a new connection object
53 * \par Function Description
54 * create a single st_conn object and initialize it with the
55 * given parameters.
57 * \return The new connection object
59 CONN *s_conn_return_new(OBJECT * other_object, int type, int x, int y,
60 int whichone, int other_whichone)
62 CONN *new_conn;
64 new_conn = (CONN *) g_malloc(sizeof(CONN));
66 #if DEBUG
67 printf("** creating: %s %d %d\n", other_object->name, x, y);
68 #endif
70 new_conn->other_object = other_object;
71 new_conn->type = type;
72 new_conn->x = x;
73 new_conn->y = y;
74 new_conn->whichone = whichone;
75 new_conn->other_whichone = other_whichone;
77 return (new_conn);
80 /*! \brief check if a connection is uniq in a list
81 * \par Function Description
82 * This function checks if there's no identical connection
83 * in the list of connections.
84 * \param conn_list list of connection objects
85 * \param input_conn single connection object.
86 * \return TRUE if the CONN structure is unique, FALSE otherwise.
88 int s_conn_uniq(GList * conn_list, CONN * input_conn)
90 GList *c_current;
91 CONN *conn;
93 c_current = conn_list;
94 while (c_current != NULL) {
95 conn = (CONN *) c_current->data;
97 if (conn->other_object == input_conn->other_object &&
98 conn->x == input_conn->x && conn->y == input_conn->y &&
99 conn->type == input_conn->type) {
100 return (FALSE);
103 c_current = g_list_next(c_current);
106 return (TRUE);
109 /*! \brief remove a object from the connection list of another object
110 * \par Function Description
111 * This function removes the OBJECT <b>to_remove</b> from the connection
112 * list of the OBJECT <b>other_object</b>.
113 * \param toplevel (currently not used)
114 * \param other_object OBJECT from that the to_remove OBJECT needs to be removed
115 * \param to_remove OBJECT to remove
116 * \return TRUE if a connection has been deleted, FALSE otherwise
118 int s_conn_remove_other (TOPLEVEL *toplevel, OBJECT *other_object,
119 OBJECT *to_remove)
121 GList *c_current = NULL;
122 CONN *conn = NULL;
124 o_emit_pre_change_notify (toplevel, other_object);
126 c_current = other_object->conn_list;
127 while (c_current != NULL) {
128 conn = (CONN *) c_current->data;
130 if (conn->other_object == to_remove) {
131 other_object->conn_list =
132 g_list_remove(other_object->conn_list, conn);
134 #if DEBUG
135 printf("Found other_object in remove_other\n");
136 printf("Freeing other: %s %d %d\n", conn->other_object->name,
137 conn->x, conn->y);
138 #endif
140 /* Do not write modify c_current like this, since this will cause */
141 /* very nasty data corruption and upset glib's memory slice */
142 /* allocator. */
143 /* c_current->data = NULL; Do not comment in */
145 g_free(conn);
147 #if 0 /* this does not work right */
148 if (other_object->type == OBJ_BUS &&
149 other_object->conn_list == NULL) {
150 other_object->bus_ripper_direction = 0;
152 #endif
154 return (TRUE);
157 c_current = g_list_next(c_current);
160 o_emit_change_notify (toplevel, other_object);
162 return (FALSE);
165 /*! \brief removes a GList of OBJECTs from the connection system
167 * \par Function Description
168 * This function removes all connections from and to the OBJECTS
169 * of the given GList.
171 * \param toplevel (currently not used)
172 * \param obj_list GList of OBJECTs to unconnected from all other objects
174 static void s_conn_remove_glist (TOPLEVEL *toplevel, GList *obj_list)
176 OBJECT *o_current;
177 GList *iter;
179 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
180 o_current = iter->data;
181 s_conn_remove_object (toplevel, o_current);
185 /*! \brief remove an OBJECT from the connection system
186 * \par Function Description
187 * This function removes all connections from and to the OBJECT
188 * <b>to_remove</b>.
189 * \param toplevel (currently not used)
190 * \param to_remove OBJECT to unconnected from all other objects
192 void s_conn_remove_object (TOPLEVEL *toplevel, OBJECT *to_remove)
194 GList *c_iter;
195 CONN *conn;
197 switch (to_remove->type) {
198 case OBJ_PIN:
199 case OBJ_NET:
200 case OBJ_BUS:
201 for (c_iter = to_remove->conn_list;
202 c_iter != NULL;
203 c_iter = g_list_next (c_iter)) {
204 conn = c_iter->data;
206 /* keep calling this till it returns false (all refs removed) */
207 /* there is NO body to this while loop */
208 while (s_conn_remove_other (toplevel, conn->other_object, to_remove));
210 c_iter->data = NULL;
211 g_free (conn);
214 g_list_free (to_remove->conn_list);
215 to_remove->conn_list = NULL;
216 break;
218 case OBJ_COMPLEX:
219 case OBJ_PLACEHOLDER:
220 s_conn_remove_glist (toplevel, to_remove->complex->prim_objs);
221 break;
225 /*! \brief Checks if a point is a midpoint of an OBJECT
226 * \par Function Description
227 * Checks if the point (<b>x</b>,<b>y</b>) is on the OBJECT
228 * and between it's endpoints.
229 * \return TRUE if the point is a midpoint of the OBJECT. FALSE
230 * if the point is not a midpoinit or if the OBJECT is not a
231 * NET a PIN or a BUS or if the OBJECT
232 * has neither horizontal nor vertical orientation.
234 OBJECT *s_conn_check_midpoint(OBJECT *o_current, int x, int y)
236 int min_x, min_y, max_x, max_y;
238 switch(o_current->type) {
239 case(OBJ_NET):
240 case(OBJ_PIN):
241 case(OBJ_BUS):
242 min_y = min(o_current->line->y[0],
243 o_current->line->y[1]);
244 max_y = max(o_current->line->y[0],
245 o_current->line->y[1]);
247 /* vertical */
248 if ( (o_current->line->x[0] == x) &&
249 (y > min_y) && (y < max_y) &&
250 (o_current->line->x[0] ==
251 o_current->line->x[1]) ) {
252 #if DEBUG
253 printf("Found vertical point\n");
254 #endif
255 return(o_current);
258 min_x = min(o_current->line->x[0],
259 o_current->line->x[1]);
260 max_x = max(o_current->line->x[0],
261 o_current->line->x[1]);
263 /* horizontal */
264 if ( (o_current->line->y[0] == y) &&
265 (x > min_x) && (x < max_x) &&
266 (o_current->line->y[0] ==
267 o_current->line->y[1]) ) {
268 #if DEBUG
269 printf("Found horizontal point\n");
270 #endif
271 return(o_current);
274 break;
276 return(NULL);
279 /*! \brief adds a GList of OBJECTs to the connection system
281 * \par Function Description
282 * This function adds all connections from and to the OBJECTS
283 * of the given GList.
285 * \param toplevel (currently not used)
286 * \param obj_list GList of OBJECTs to add into the connection system
288 void s_conn_update_glist (TOPLEVEL *toplevel, GList *obj_list)
290 OBJECT *o_current;
291 GList *iter;
293 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
294 o_current = iter->data;
295 s_conn_update_object (toplevel, o_current);
300 /*! \brief Checks if an object is bus, or a bus pin
302 * \par Function Description
303 * Checks if an object is a bus or a bus pin
305 * \param object The OBJECT to test
306 * \return TRUE if the objects is a bis, or bus pin
308 static int is_bus_related (OBJECT *object)
310 return (object->type == OBJ_BUS ||
311 (object->type == OBJ_PIN && object->pin_type == PIN_TYPE_BUS));
315 /*! \brief Checks if two objects are of compatible types to be connected
317 * \par Function Description
318 * Checks if two objects are legal to be connected together
320 * \param object1 First OBJECT
321 * \param object2 Second OBJECT
322 * \return TRUE if the objects are compatible, FALSE if not
324 static int check_direct_compat (OBJECT *object1, OBJECT *object2)
326 return (is_bus_related (object1) == is_bus_related (object2));
330 static void add_connection (OBJECT *object, OBJECT *other_object,
331 int type, int x, int y,
332 int whichone, int other_whichone)
334 /* Describe the connection */
335 CONN *new_conn = s_conn_return_new (other_object, type, x, y,
336 whichone, other_whichone);
337 /* Do uniqness check */
338 if (s_conn_uniq (object->conn_list, new_conn)) {
339 object->conn_list = g_list_append (object->conn_list, new_conn);
340 } else {
341 g_free (new_conn);
345 /*! \brief add a line OBJECT to the connection system
346 * \par Function Description
347 * This function searches for all geometrical conections of the OBJECT
348 * <b>object</b> to all other connectable objects. It adds connections
349 * to the object and from all other
350 * objects to this one.
351 * \param toplevel (currently not used)
352 * \param object OBJECT to add into the connection system
354 static void s_conn_update_line_object (TOPLEVEL *toplevel, OBJECT *object)
356 TILE *t_current;
357 GList *tl_current;
358 GList *object_list;
359 OBJECT *other_object;
360 OBJECT *found;
361 int j, k;
363 /* loop over all tiles which object appears in */
364 for (tl_current = object->tiles;
365 tl_current != NULL;
366 tl_current = g_list_next (tl_current)) {
367 t_current = tl_current->data;
369 for (object_list = t_current->objects;
370 object_list != NULL;
371 object_list = g_list_next (object_list)) {
372 other_object = object_list->data;
374 if (object == other_object)
375 continue;
377 /* Here is where you check the end points */
378 /* Check both end points of the other object */
379 for (k = 0; k < 2; k++) {
381 /* If the other object is a pin, only check the correct end */
382 if (other_object->type == OBJ_PIN && other_object->whichend != k)
383 continue;
385 /* Check both end points of the object */
386 for (j = 0; j < 2; j++) {
388 /* If the object is a pin, only check the correct end */
389 if (object->type == OBJ_PIN && object->whichend != j)
390 continue;
392 /* Check for coincidence and compatability between
393 the objects being tested. */
394 if (object->line->x[j] == other_object->line->x[k] &&
395 object->line->y[j] == other_object->line->y[k] &&
396 check_direct_compat (object, other_object)) {
398 o_emit_pre_change_notify (toplevel, other_object);
400 add_connection (object, other_object, CONN_ENDPOINT,
401 other_object->line->x[k],
402 other_object->line->y[k], j, k);
404 add_connection (other_object, object, CONN_ENDPOINT,
405 object->line->x[j],
406 object->line->y[j], k, j);
408 o_emit_change_notify (toplevel, other_object);
413 /* Check both end points of the object against midpoints of the other */
414 for (k = 0; k < 2; k++) {
416 /* If the object is a pin, only check the correct end */
417 if (object->type == OBJ_PIN && object->whichend != k)
418 continue;
420 /* check for midpoint of other object, k endpoint of current obj*/
421 found = s_conn_check_midpoint (other_object, object->line->x[k],
422 object->line->y[k]);
424 /* Pins are not allowed midpoint connections onto them. */
425 /* Allow nets to connect to the middle of buses. */
426 /* Allow compatible objects to connect. */
427 if (found && other_object->type != OBJ_PIN &&
428 ((object->type == OBJ_NET && other_object->type == OBJ_BUS) ||
429 check_direct_compat (object, other_object))) {
431 add_connection (object, other_object, CONN_MIDPOINT,
432 object->line->x[k],
433 object->line->y[k], k, -1);
435 add_connection (other_object, object, CONN_MIDPOINT,
436 object->line->x[k],
437 object->line->y[k], -1, k);
441 /* Check both end points of the other object against midpoints of the first */
442 for (k = 0; k < 2; k++) {
444 /* If the other object is a pin, only check the correct end */
445 if (other_object->type == OBJ_PIN && other_object->whichend != k)
446 continue;
448 /* do object's endpoints cross the middle of other_object? */
449 /* check for midpoint of other object, k endpoint of current obj*/
450 found = s_conn_check_midpoint (object, other_object->line->x[k],
451 other_object->line->y[k]);
453 /* Pins are not allowed midpoint connections onto them. */
454 /* Allow nets to connect to the middle of buses. */
455 /* Allow compatible objects to connect. */
456 if (found && object->type != OBJ_PIN &&
457 ((object->type == OBJ_BUS && other_object->type == OBJ_NET) ||
458 check_direct_compat (object, other_object))) {
460 add_connection (object, other_object, CONN_MIDPOINT,
461 other_object->line->x[k],
462 other_object->line->y[k], -1, k);
464 add_connection (other_object, object, CONN_MIDPOINT,
465 other_object->line->x[k],
466 other_object->line->y[k], k, -1);
473 #if DEBUG
474 s_conn_print(object->conn_list);
475 #endif
478 /*! \brief add an OBJECT to the connection system
480 * \par Function Description
481 * This function searches for all geometrical conections of the OBJECT
482 * <b>object</b> to all other connectable objects. It adds connections
483 * to the object and from all other objects to this one.
485 * \param toplevel (currently not used)
486 * \param object OBJECT to add into the connection system
488 void s_conn_update_object (TOPLEVEL *toplevel, OBJECT *object)
490 switch (object->type) {
491 case OBJ_PIN:
492 case OBJ_NET:
493 case OBJ_BUS:
494 s_conn_update_line_object (toplevel, object);
495 break;
497 case OBJ_COMPLEX:
498 case OBJ_PLACEHOLDER:
499 s_conn_update_glist (toplevel, object->complex->prim_objs);
500 break;
504 /*! \brief print all connections of a connection list
505 * \par Function Description
506 * This is a debugging function to print a List of connections.
507 * \param conn_list GList of connection objects
509 void s_conn_print(GList * conn_list)
511 CONN *conn;
512 GList *cl_current;
514 printf("\nStarting s_conn_print\n");
515 cl_current = conn_list;
516 while (cl_current != NULL) {
518 conn = (CONN *) cl_current->data;
519 printf("-----------------------------------\n");
520 printf("other object: %s\n", conn->other_object->name);
521 printf("type: %d\n", conn->type);
522 printf("x: %d y: %d\n", conn->x, conn->y);
523 printf("whichone: %d\n", conn->whichone);
524 printf("other_whichone: %d\n", conn->other_whichone);
525 printf("-----------------------------------\n");
527 cl_current = g_list_next(cl_current);
532 /*! \brief Search for net in existing connections.
533 * \par Function Description
534 * This method searches the connection list for the first matching
535 * connection with the given x, y, and whichone endpoint.
537 * \param [in] new_net Net OBJECT to compare to.
538 * \param [in] whichone The connection number to check.
539 * \param [in] conn_list List of existing connections to compare
540 * <B>new_net</B> to.
541 * \return TRUE if a matching connection is found, FALSE otherwise.
543 int s_conn_net_search(OBJECT* new_net, int whichone, GList * conn_list)
545 CONN *conn;
546 GList *cl_current;
548 cl_current = conn_list;
549 while (cl_current != NULL) {
551 conn = (CONN *) cl_current->data;
552 if (conn != NULL && conn->whichone == whichone &&
553 conn->x == new_net->line->x[whichone] &&
554 conn->y == new_net->line->y[whichone])
556 return TRUE;
559 cl_current = g_list_next(cl_current);
562 return FALSE;
565 /*! \brief get a list of all objects connected to a list of OBJECTs.
567 * \par Function Description
568 * This function gets all other_object from the connection
569 * list of the OBJECTs in the pased list.
571 * \param [in] input_list GList of OBJECT's or NULL
572 * \param [in] obj_list The GList of OBJECT to get connections from
573 * \return A GList of objects
575 * \warning
576 * Caller must g_list_free returned GList pointer.
577 * Do not free individual data items in list.
579 static GList *s_conn_return_glist_others (GList *input_list, GList *obj_list)
581 GList *return_list;
582 GList *iter;
583 OBJECT *o_current;
585 return_list = input_list;
587 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
588 o_current = iter->data;
589 return_list = s_conn_return_others (return_list, o_current);
592 return return_list;
595 /*! \brief get a list of all objects connected to this one
597 * \par Function Description
598 * This function gets all other_object from the connection list of the current object.
599 * COMPLEX objects are entered, and their prim_objs processed. If an <b>input_list</b>
600 * is given, the other objects are appended to that list.
602 * \param [in] input_list GList of OBJECT's
603 * \param [in] object OBJECT to get other OBJECTs from
604 * \return A GList of OBJECTs
606 * \warning
607 * Caller must g_list_free returned GList pointer.
608 * Do not free individual data items in list.
610 GList *s_conn_return_others(GList *input_list, OBJECT *object)
612 GList *c_iter;
613 GList *return_list;
615 return_list = input_list;
617 switch (object->type) {
618 case OBJ_PIN:
619 case OBJ_NET:
620 case OBJ_BUS:
621 for (c_iter = object->conn_list;
622 c_iter != NULL; c_iter = g_list_next (c_iter)) {
623 CONN *conn = c_iter->data;
625 if (conn->other_object && conn->other_object != object) {
626 return_list = g_list_append(return_list, conn->other_object);
629 break;
631 case OBJ_COMPLEX:
632 case OBJ_PLACEHOLDER:
633 return_list = s_conn_return_glist_others (return_list,
634 object->complex->prim_objs);
635 break;
638 return return_list;