Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / libgeda / src / s_conn.c
blob4985071f1bb1bcfab3c45ce0f9838d573c1886fe
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., 59 Temple Place, Suite 330, Boston, MA 02111 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 c_current = other_object->conn_list;
125 while (c_current != NULL) {
126 conn = (CONN *) c_current->data;
128 if (conn->other_object == to_remove) {
129 other_object->conn_list =
130 g_list_remove(other_object->conn_list, conn);
132 #if DEBUG
133 printf("Found other_object in remove_other\n");
134 printf("Freeing other: %s %d %d\n", conn->other_object->name,
135 conn->x, conn->y);
136 #endif
138 /* Do not write modify c_current like this, since this will cause */
139 /* very nasty data corruption and upset glib's memory slice */
140 /* allocator. */
141 /* c_current->data = NULL; Do not comment in */
143 g_free(conn);
145 #if 0 /* this does not work right */
146 if (other_object->type == OBJ_BUS &&
147 other_object->conn_list == NULL) {
148 other_object->bus_ripper_direction = 0;
150 #endif
152 return (TRUE);
155 c_current = g_list_next(c_current);
158 return (FALSE);
161 /*! \brief removes a GList of OBJECTs from the connection system
163 * \par Function Description
164 * This function removes all connections from and to the OBJECTS
165 * of the given GList.
167 * \param toplevel (currently not used)
168 * \param obj_list GList of OBJECTs to unconnected from all other objects
170 static void s_conn_remove_glist (TOPLEVEL *toplevel, GList *obj_list)
172 OBJECT *o_current;
173 GList *iter;
175 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
176 o_current = iter->data;
177 s_conn_remove_object (toplevel, o_current);
181 /*! \brief remove an OBJECT from the connection system
182 * \par Function Description
183 * This function removes all connections from and to the OBJECT
184 * <b>to_remove</b>.
185 * \param toplevel (currently not used)
186 * \param to_remove OBJECT to unconnected from all other objects
188 void s_conn_remove_object (TOPLEVEL *toplevel, OBJECT *to_remove)
190 GList *c_iter;
191 CONN *conn;
193 switch (to_remove->type) {
194 case OBJ_PIN:
195 case OBJ_NET:
196 case OBJ_BUS:
197 for (c_iter = to_remove->conn_list;
198 c_iter != NULL;
199 c_iter = g_list_next (c_iter)) {
200 conn = c_iter->data;
202 /* keep calling this till it returns false (all refs removed) */
203 /* there is NO body to this while loop */
204 while (s_conn_remove_other (toplevel, conn->other_object, to_remove));
206 c_iter->data = NULL;
207 g_free (conn);
210 g_list_free (to_remove->conn_list);
211 to_remove->conn_list = NULL;
212 break;
214 case OBJ_COMPLEX:
215 case OBJ_PLACEHOLDER:
216 s_conn_remove_glist (toplevel, to_remove->complex->prim_objs);
217 break;
221 /*! \brief Checks if a point is a midpoint of an OBJECT
222 * \par Function Description
223 * Checks if the point (<b>x</b>,<b>y</b>) is on the OBJECT
224 * and between it's endpoints.
225 * \return TRUE if the point is a midpoint of the OBJECT. FALSE
226 * if the point is not a midpoinit or if the OBJECT is not a
227 * NET a PIN or a BUS or if the OBJECT
228 * has neither horizontal nor vertical orientation.
230 OBJECT *s_conn_check_midpoint(OBJECT *o_current, int x, int y)
232 int min_x, min_y, max_x, max_y;
234 switch(o_current->type) {
235 case(OBJ_NET):
236 case(OBJ_PIN):
237 case(OBJ_BUS):
238 min_y = min(o_current->line->y[0],
239 o_current->line->y[1]);
240 max_y = max(o_current->line->y[0],
241 o_current->line->y[1]);
243 /* vertical */
244 if ( (o_current->line->x[0] == x) &&
245 (y > min_y) && (y < max_y) &&
246 (o_current->line->x[0] ==
247 o_current->line->x[1]) ) {
248 #if DEBUG
249 printf("Found vertical point\n");
250 #endif
251 return(o_current);
254 min_x = min(o_current->line->x[0],
255 o_current->line->x[1]);
256 max_x = max(o_current->line->x[0],
257 o_current->line->x[1]);
259 /* horizontal */
260 if ( (o_current->line->y[0] == y) &&
261 (x > min_x) && (x < max_x) &&
262 (o_current->line->y[0] ==
263 o_current->line->y[1]) ) {
264 #if DEBUG
265 printf("Found horizontal point\n");
266 #endif
267 return(o_current);
270 break;
272 return(NULL);
275 /*! \brief adds a GList of OBJECTs to the connection system
277 * \par Function Description
278 * This function adds all connections from and to the OBJECTS
279 * of the given GList.
281 * \param toplevel (currently not used)
282 * \param obj_list GList of OBJECTs to add into the connection system
284 void s_conn_update_glist (TOPLEVEL *toplevel, GList *obj_list)
286 OBJECT *o_current;
287 GList *iter;
289 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
290 o_current = iter->data;
291 s_conn_update_object (toplevel, o_current);
296 /*! \brief Checks if an object is bus, or a bus pin
298 * \par Function Description
299 * Checks if an object is a bus or a bus pin
301 * \param object The OBJECT to test
302 * \return TRUE if the objects is a bis, or bus pin
304 static int is_bus_related (OBJECT *object)
306 return (object->type == OBJ_BUS ||
307 (object->type == OBJ_PIN && object->pin_type == PIN_TYPE_BUS));
311 /*! \brief Checks if two objects are of compatible types to be connected
313 * \par Function Description
314 * Checks if two objects are legal to be connected together
316 * \param object1 First OBJECT
317 * \param object2 Second OBJECT
318 * \return TRUE if the objects are compatible, FALSE if not
320 static int check_direct_compat (OBJECT *object1, OBJECT *object2)
322 return (is_bus_related (object1) == is_bus_related (object2));
326 static void add_connection (OBJECT *object, OBJECT *other_object,
327 int type, int x, int y,
328 int whichone, int other_whichone)
330 /* Describe the connection */
331 CONN *new_conn = s_conn_return_new (other_object, type, x, y,
332 whichone, other_whichone);
333 /* Do uniqness check */
334 if (s_conn_uniq (object->conn_list, new_conn)) {
335 object->conn_list = g_list_append (object->conn_list, new_conn);
336 } else {
337 g_free (new_conn);
341 /*! \brief add a line OBJECT to the connection system
342 * \par Function Description
343 * This function searches for all geometrical conections of the OBJECT
344 * <b>object</b> to all other connectable objects. It adds connections
345 * to the object and from all other
346 * objects to this one.
347 * \param toplevel (currently not used)
348 * \param object OBJECT to add into the connection system
350 static void s_conn_update_line_object (TOPLEVEL *toplevel, OBJECT *object)
352 TILE *t_current;
353 GList *tl_current;
354 GList *object_list;
355 OBJECT *other_object;
356 OBJECT *found;
357 int j, k;
359 /* loop over all tiles which object appears in */
360 for (tl_current = object->tiles;
361 tl_current != NULL;
362 tl_current = g_list_next (tl_current)) {
363 t_current = tl_current->data;
365 for (object_list = t_current->objects;
366 object_list != NULL;
367 object_list = g_list_next (object_list)) {
368 other_object = object_list->data;
370 if (object == other_object)
371 continue;
373 /* Here is where you check the end points */
374 /* Check both end points of the other object */
375 for (k = 0; k < 2; k++) {
377 /* If the other object is a pin, only check the correct end */
378 if (other_object->type == OBJ_PIN && other_object->whichend != k)
379 continue;
381 /* Check both end points of the object */
382 for (j = 0; j < 2; j++) {
384 /* If the object is a pin, only check the correct end */
385 if (object->type == OBJ_PIN && object->whichend != j)
386 continue;
388 /* Check for coincidence and compatability between
389 the objects being tested. */
390 if (object->line->x[j] == other_object->line->x[k] &&
391 object->line->y[j] == other_object->line->y[k] &&
392 check_direct_compat (object, other_object)) {
394 add_connection (object, other_object, CONN_ENDPOINT,
395 other_object->line->x[k],
396 other_object->line->y[k], j, k);
398 add_connection (other_object, object, CONN_ENDPOINT,
399 object->line->x[j],
400 object->line->y[j], k, j);
405 /* Check both end points of the object against midpoints of the other */
406 for (k = 0; k < 2; k++) {
408 /* If the object is a pin, only check the correct end */
409 if (object->type == OBJ_PIN && object->whichend != k)
410 continue;
412 /* check for midpoint of other object, k endpoint of current obj*/
413 found = s_conn_check_midpoint (other_object, object->line->x[k],
414 object->line->y[k]);
416 /* Pins are not allowed midpoint connections onto them. */
417 /* Allow nets to connect to the middle of buses. */
418 /* Allow compatible objects to connect. */
419 if (found && other_object->type != OBJ_PIN &&
420 ((object->type == OBJ_NET && other_object->type == OBJ_BUS) ||
421 check_direct_compat (object, other_object))) {
423 add_connection (object, other_object, CONN_MIDPOINT,
424 object->line->x[k],
425 object->line->y[k], k, -1);
427 add_connection (other_object, object, CONN_MIDPOINT,
428 object->line->x[k],
429 object->line->y[k], -1, k);
433 /* Check both end points of the other object against midpoints of the first */
434 for (k = 0; k < 2; k++) {
436 /* If the other object is a pin, only check the correct end */
437 if (other_object->type == OBJ_PIN && other_object->whichend != k)
438 continue;
440 /* do object's endpoints cross the middle of other_object? */
441 /* check for midpoint of other object, k endpoint of current obj*/
442 found = s_conn_check_midpoint (object, other_object->line->x[k],
443 other_object->line->y[k]);
445 /* Pins are not allowed midpoint connections onto them. */
446 /* Allow nets to connect to the middle of buses. */
447 /* Allow compatible objects to connect. */
448 if (found && object->type != OBJ_PIN &&
449 ((object->type == OBJ_BUS && other_object->type == OBJ_NET) ||
450 check_direct_compat (object, other_object))) {
452 add_connection (object, other_object, CONN_MIDPOINT,
453 other_object->line->x[k],
454 other_object->line->y[k], -1, k);
456 add_connection (other_object, object, CONN_MIDPOINT,
457 other_object->line->x[k],
458 other_object->line->y[k], k, -1);
465 #if DEBUG
466 s_conn_print(object->conn_list);
467 #endif
470 /*! \brief add an OBJECT to the connection system
472 * \par Function Description
473 * This function searches for all geometrical conections of the OBJECT
474 * <b>object</b> to all other connectable objects. It adds connections
475 * to the object and from all other objects to this one.
477 * \param toplevel (currently not used)
478 * \param object OBJECT to add into the connection system
480 void s_conn_update_object (TOPLEVEL *toplevel, OBJECT *object)
482 switch (object->type) {
483 case OBJ_PIN:
484 case OBJ_NET:
485 case OBJ_BUS:
486 s_conn_update_line_object (toplevel, object);
487 break;
489 case OBJ_COMPLEX:
490 case OBJ_PLACEHOLDER:
491 s_conn_update_glist (toplevel, object->complex->prim_objs);
492 break;
496 /*! \brief print all connections of a connection list
497 * \par Function Description
498 * This is a debugging function to print a List of connections.
499 * \param conn_list GList of connection objects
501 void s_conn_print(GList * conn_list)
503 CONN *conn;
504 GList *cl_current;
506 printf("\nStarting s_conn_print\n");
507 cl_current = conn_list;
508 while (cl_current != NULL) {
510 conn = (CONN *) cl_current->data;
511 printf("-----------------------------------\n");
512 printf("other object: %s\n", conn->other_object->name);
513 printf("type: %d\n", conn->type);
514 printf("x: %d y: %d\n", conn->x, conn->y);
515 printf("whichone: %d\n", conn->whichone);
516 printf("other_whichone: %d\n", conn->other_whichone);
517 printf("-----------------------------------\n");
519 cl_current = g_list_next(cl_current);
524 /*! \brief Search for net in existing connections.
525 * \par Function Description
526 * This method searches the connection list for the first matching
527 * connection with the given x, y, and whichone endpoint.
529 * \param [in] new_net Net OBJECT to compare to.
530 * \param [in] whichone The connection number to check.
531 * \param [in] conn_list List of existing connections to compare
532 * <B>new_net</B> to.
533 * \return TRUE if a matching connection is found, FALSE otherwise.
535 int s_conn_net_search(OBJECT* new_net, int whichone, GList * conn_list)
537 CONN *conn;
538 GList *cl_current;
540 cl_current = conn_list;
541 while (cl_current != NULL) {
543 conn = (CONN *) cl_current->data;
544 if (conn != NULL && conn->whichone == whichone &&
545 conn->x == new_net->line->x[whichone] &&
546 conn->y == new_net->line->y[whichone])
548 return TRUE;
551 cl_current = g_list_next(cl_current);
554 return FALSE;
557 /*! \brief get a list of all objects connected to a list of OBJECTs.
559 * \par Function Description
560 * This function gets all other_object from the connection
561 * list of the OBJECTs in the pased list.
563 * \param [in] input_list GList of OBJECT's or NULL
564 * \param [in] obj_list The GList of OBJECT to get connections from
565 * \return A GList of objects
567 * \warning
568 * Caller must g_list_free returned GList pointer.
569 * Do not free individual data items in list.
571 static GList *s_conn_return_glist_others (GList *input_list, GList *obj_list)
573 GList *return_list;
574 GList *iter;
575 OBJECT *o_current;
577 return_list = input_list;
579 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
580 o_current = iter->data;
581 return_list = s_conn_return_others (return_list, o_current);
584 return return_list;
587 /*! \brief get a list of all objects connected to this one
589 * \par Function Description
590 * This function gets all other_object from the connection list of the current object.
591 * COMPLEX objects are entered, and their prim_objs processed. If an <b>input_list</b>
592 * is given, the other objects are appended to that list.
594 * \param [in] input_list GList of OBJECT's
595 * \param [in] object OBJECT to get other OBJECTs from
596 * \return A GList of OBJECTs
598 * \warning
599 * Caller must g_list_free returned GList pointer.
600 * Do not free individual data items in list.
602 GList *s_conn_return_others(GList *input_list, OBJECT *object)
604 GList *c_iter;
605 GList *return_list;
607 return_list = input_list;
609 switch (object->type) {
610 case OBJ_PIN:
611 case OBJ_NET:
612 case OBJ_BUS:
613 for (c_iter = object->conn_list;
614 c_iter != NULL; c_iter = g_list_next (c_iter)) {
615 CONN *conn = c_iter->data;
617 if (conn->other_object && conn->other_object != object) {
618 return_list = g_list_append(return_list, conn->other_object);
621 break;
623 case OBJ_COMPLEX:
624 case OBJ_PLACEHOLDER:
625 return_list = s_conn_return_glist_others (return_list,
626 object->complex->prim_objs);
627 break;
630 return return_list;