libgeda
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * libgeda - gEDA's library 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00043 #include <config.h> 00044 #include <missing.h> 00045 00046 #include <stdio.h> 00047 #ifdef HAVE_STRING_H 00048 #include <string.h> 00049 #endif 00050 #include <math.h> 00051 00052 #include "libgeda_priv.h" 00053 00054 #ifdef HAVE_LIBDMALLOC 00055 #include <dmalloc.h> 00056 #endif 00057 00058 00068 void o_attrib_add(TOPLEVEL *toplevel, OBJECT *object, OBJECT *item) 00069 { 00070 /* Add link from item to attrib listing */ 00071 item->attached_to = object; 00072 object->attribs = g_list_append (object->attribs, item); 00073 00074 o_attrib_emit_attribs_changed (toplevel, object); 00075 } 00076 00077 00088 gboolean o_attrib_is_attached (TOPLEVEL *toplevel, 00089 OBJECT *attrib, OBJECT *object) 00090 { 00091 if (attrib == NULL || object == NULL) 00092 return FALSE; 00093 00094 if (attrib->attached_to == object) 00095 return TRUE; 00096 00097 return FALSE; 00098 } 00099 00100 00110 void o_attrib_attach (TOPLEVEL *toplevel, OBJECT *attrib, OBJECT *object, 00111 int set_color) 00112 { 00113 g_return_if_fail (attrib != NULL); 00114 g_return_if_fail (object != NULL); 00115 00116 /* is the object already part of the list ? */ 00117 if (g_list_find (object->attribs, attrib)) { 00118 g_warning ("Attribute [%s] already attached\n", attrib->text->string); 00119 return; 00120 } 00121 00122 if (attrib->type != OBJ_TEXT) { 00123 g_warning (_("Attempt to attach non text item as an attribute!\n")); 00124 return; 00125 } 00126 00127 if (attrib->attached_to != NULL) { 00128 g_warning (_("Attempt to attach attribute [%s] to more than one object\n"), 00129 attrib->text->string); 00130 return; 00131 } 00132 00133 o_attrib_add (toplevel, object, attrib); 00134 00135 if (set_color) 00136 o_set_color (toplevel, attrib, ATTRIBUTE_COLOR); 00137 } 00138 00139 00149 void o_attrib_attach_list (TOPLEVEL *toplevel, 00150 GList *attr_list, OBJECT *object, int set_color) 00151 { 00152 GList *iter; 00153 00154 for (iter = attr_list; iter != NULL; iter = g_list_next (iter)) 00155 o_attrib_attach (toplevel, iter->data, object, set_color); 00156 } 00157 00158 00166 void o_attrib_detach_all(TOPLEVEL *toplevel, OBJECT *object) 00167 { 00168 OBJECT *a_current; 00169 GList *a_iter; 00170 00171 o_attrib_freeze_hooks (toplevel, object); 00172 00173 for (a_iter = object->attribs; a_iter != NULL; 00174 a_iter = g_list_next (a_iter)) { 00175 a_current = a_iter->data; 00176 00177 a_current->attached_to = NULL; 00178 o_set_color (toplevel, a_current, DETACHED_ATTRIBUTE_COLOR); 00179 o_attrib_emit_attribs_changed (toplevel, object); 00180 } 00181 00182 g_list_free (object->attribs); 00183 object->attribs = NULL; 00184 00185 o_attrib_thaw_hooks (toplevel, object); 00186 } 00187 00194 void o_attrib_print(GList *attributes) 00195 { 00196 OBJECT *a_current; 00197 GList *a_iter; 00198 00199 a_iter = attributes; 00200 00201 while (a_iter != NULL) { 00202 a_current = a_iter->data; 00203 printf("Attribute points to: %s\n", a_current->name); 00204 if (a_current->text) { 00205 printf("\tText is: %s\n", a_current->text->string); 00206 } 00207 00208 a_iter = g_list_next (a_iter); 00209 } 00210 } 00211 00222 void o_attrib_remove(TOPLEVEL *toplevel, GList **list, OBJECT *remove) 00223 { 00224 OBJECT *attached_to; 00225 00226 g_return_if_fail (remove != NULL); 00227 00228 attached_to = remove->attached_to; 00229 remove->attached_to = NULL; 00230 00231 *list = g_list_remove (*list, remove); 00232 00233 o_attrib_emit_attribs_changed (toplevel, attached_to); 00234 } 00235 00247 GList *o_read_attribs (TOPLEVEL *toplevel, 00248 OBJECT *object_to_get_attribs, 00249 TextBuffer *tb, 00250 unsigned int release_ver, unsigned int fileformat_ver, GError ** err) 00251 { 00252 GList *object_list = NULL; 00253 OBJECT *new_obj; 00254 const char *line = NULL; 00255 char objtype; 00256 int ATTACH=FALSE; 00257 00258 while (1) { 00259 00260 line = s_textbuffer_next_line (tb); 00261 if (line == NULL) break; 00262 00263 sscanf(line, "%c", &objtype); 00264 switch (objtype) { 00265 00266 case(OBJ_LINE): 00267 if ((new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00268 goto error; 00269 object_list = g_list_prepend (object_list, new_obj); 00270 break; 00271 00272 00273 case(OBJ_NET): 00274 if ((new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00275 goto error; 00276 object_list = g_list_prepend (object_list, new_obj); 00277 break; 00278 00279 case(OBJ_BUS): 00280 if ((new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00281 goto error; 00282 object_list = g_list_prepend (object_list, new_obj); 00283 break; 00284 00285 case(OBJ_BOX): 00286 if ((new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00287 goto error; 00288 object_list = g_list_prepend (object_list, new_obj); 00289 break; 00290 00291 case(OBJ_CIRCLE): 00292 if ((new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00293 goto error; 00294 object_list = g_list_prepend (object_list, new_obj); 00295 break; 00296 00297 case(OBJ_COMPLEX): 00298 case(OBJ_PLACEHOLDER): 00299 if ((new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00300 goto error; 00301 object_list = g_list_prepend (object_list, new_obj); 00302 break; 00303 00304 case(OBJ_PATH): 00305 new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err); 00306 if (new_obj == NULL) 00307 goto error; 00308 object_list = g_list_prepend (object_list, new_obj); 00309 break; 00310 00311 case(OBJ_PIN): 00312 if ((new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00313 goto error; 00314 object_list = g_list_prepend (object_list, new_obj); 00315 break; 00316 00317 case(OBJ_ARC): 00318 if ((new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) 00319 goto error; 00320 object_list = g_list_prepend (object_list, new_obj); 00321 break; 00322 00323 case(OBJ_TEXT): 00324 new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err); 00325 if (new_obj == NULL) 00326 goto error; 00327 object_list = g_list_prepend (object_list, new_obj); 00328 ATTACH=TRUE; 00329 00330 break; 00331 00332 case(ENDATTACH_ATTR): 00333 return object_list; 00334 break; 00335 } 00336 00337 if (ATTACH) { 00338 o_attrib_attach (toplevel, new_obj, object_to_get_attribs, FALSE); 00339 ATTACH=FALSE; 00340 } else { 00341 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Tried to attach a non-text item as an attribute")); 00342 goto error; 00343 } 00344 } 00345 00346 /* The attribute list wasn't terminated, so it's a parse error! */ 00347 g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, 00348 _("Unexpected end-of-file in attribute list")); 00349 00350 error: 00351 s_delete_object_glist(toplevel, object_list); 00352 return NULL; 00353 } 00354 00355 00378 gboolean 00379 o_attrib_string_get_name_value (const gchar *string, gchar **name_ptr, gchar **value_ptr) 00380 { 00381 gchar *ptr, *prev_char, *next_char; 00382 00383 if (name_ptr != NULL) 00384 *name_ptr = NULL; 00385 if (value_ptr != NULL) 00386 *value_ptr = NULL; 00387 00388 g_return_val_if_fail (string != NULL, FALSE); 00389 00390 ptr = g_utf8_strchr (string, -1, g_utf8_get_char ("=")); 00391 if (ptr == NULL) { 00392 return FALSE; 00393 } 00394 00395 prev_char = g_utf8_find_prev_char (string, ptr); 00396 next_char = g_utf8_find_next_char (ptr, NULL); 00397 if (prev_char == NULL || *prev_char == ' ' || 00398 next_char == NULL || *next_char == ' ' || *next_char == '\0' ) { 00399 return FALSE; 00400 } 00401 00402 if (name_ptr != NULL) { 00403 *name_ptr = g_strndup (string, (ptr - string)); 00404 } 00405 00406 if (value_ptr != NULL) { 00407 *value_ptr = g_strdup (next_char); 00408 } 00409 00410 return TRUE; 00411 } 00412 00413 00423 gboolean 00424 o_attrib_get_name_value (OBJECT *attrib, gchar **name_ptr, gchar **value_ptr) 00425 { 00426 g_return_val_if_fail (attrib->type == OBJ_TEXT, FALSE); 00427 00428 return o_attrib_string_get_name_value (attrib->text->string, 00429 name_ptr, value_ptr); 00430 } 00431 00432 00443 GList *o_attrib_find_floating_attribs (const GList *list) 00444 { 00445 GList *floating_attributes = NULL; 00446 const GList *iter; 00447 OBJECT *o_current; 00448 00449 for (iter = list; iter != NULL; iter = g_list_next (iter)) { 00450 o_current = iter->data; 00451 00452 /* Skip non text objects, attached attributes and text which doesn't 00453 * constitute a valid attributes (e.g. general text placed on the page) 00454 */ 00455 if (o_current->type == OBJ_TEXT && 00456 o_current->attached_to == NULL && 00457 o_attrib_get_name_value (o_current, NULL, NULL)) { 00458 00459 floating_attributes = g_list_prepend (floating_attributes, o_current); 00460 } 00461 } 00462 00463 return g_list_reverse (floating_attributes); 00464 } 00465 00466 00479 OBJECT *o_attrib_find_attrib_by_name (const GList *list, char *name, int count) 00480 { 00481 OBJECT *a_current; 00482 const GList *iter; 00483 char *found_name; 00484 int internal_counter = 0; 00485 00486 for (iter = list; iter != NULL; iter = g_list_next (iter)) { 00487 a_current = iter->data; 00488 00489 g_return_val_if_fail (a_current->type == OBJ_TEXT, NULL); 00490 00491 if (!o_attrib_get_name_value (a_current, &found_name, NULL)) 00492 continue; 00493 00494 if (strcmp (name, found_name) == 0) { 00495 if (internal_counter == count) { 00496 g_free (found_name); 00497 return a_current; 00498 } 00499 internal_counter++; 00500 } 00501 00502 g_free (found_name); 00503 } 00504 00505 return NULL; 00506 } 00507 00508 00521 static char *o_attrib_search_attrib_list_by_name (const GList *list, char *name, int counter) 00522 { 00523 OBJECT *attrib; 00524 char *value = NULL; 00525 00526 attrib = o_attrib_find_attrib_by_name (list, name, counter); 00527 00528 if (attrib != NULL) 00529 o_attrib_get_name_value (attrib, NULL, &value); 00530 00531 return value; 00532 } 00533 00534 00550 char *o_attrib_search_floating_attribs_by_name (const GList *list, char *name, int counter) 00551 { 00552 char *result; 00553 GList *attributes; 00554 00555 attributes = o_attrib_find_floating_attribs (list); 00556 result = o_attrib_search_attrib_list_by_name (attributes, name, counter); 00557 g_list_free (attributes); 00558 00559 return result; 00560 } 00561 00562 00578 char *o_attrib_search_attached_attribs_by_name (OBJECT *object, char *name, int counter) 00579 { 00580 return o_attrib_search_attrib_list_by_name (object->attribs, name, counter); 00581 } 00582 00583 00599 char *o_attrib_search_inherited_attribs_by_name (OBJECT *object, char *name, int counter) 00600 { 00601 g_return_val_if_fail (object->type == OBJ_COMPLEX || 00602 object->type == OBJ_PLACEHOLDER, NULL); 00603 00604 return o_attrib_search_floating_attribs_by_name (object->complex->prim_objs, name, counter); 00605 } 00606 00607 00623 char *o_attrib_search_object_attribs_by_name (OBJECT *object, char *name, int counter) 00624 { 00625 char *result; 00626 GList *attributes; 00627 00628 attributes = o_attrib_return_attribs (object); 00629 result = o_attrib_search_attrib_list_by_name (attributes, name, counter); 00630 g_list_free (attributes); 00631 00632 return result; 00633 } 00634 00635 00650 GList * o_attrib_return_attribs (OBJECT *object) 00651 { 00652 GList *attribs = NULL; 00653 GList *inherited_attribs; 00654 OBJECT *a_current; 00655 GList *a_iter; 00656 00657 g_return_val_if_fail (object != NULL, NULL); 00658 00659 /* Directly attached attributes */ 00660 for (a_iter = object->attribs; a_iter != NULL; 00661 a_iter = g_list_next (a_iter)) { 00662 a_current = a_iter->data; 00663 00664 if (a_current->type != OBJ_TEXT) 00665 continue; 00666 00667 /* Don't add invalid attributes to the list */ 00668 if (!o_attrib_get_name_value (a_current, NULL, NULL)) 00669 continue; 00670 00671 attribs = g_list_prepend (attribs, a_current); 00672 } 00673 00674 attribs = g_list_reverse (attribs); 00675 00676 /* Inherited attributes (inside complex objects) */ 00677 if (object->type == OBJ_COMPLEX || 00678 object->type == OBJ_PLACEHOLDER) { 00679 00680 inherited_attribs = 00681 o_attrib_find_floating_attribs (object->complex->prim_objs); 00682 00683 attribs = g_list_concat (attribs, inherited_attribs); 00684 } 00685 00686 return attribs; 00687 } 00688 00689 00698 int o_attrib_is_inherited (OBJECT *attrib) 00699 { 00700 return (attrib->attached_to == NULL && 00701 attrib->parent != NULL); 00702 } 00703 00704 00705 typedef struct { 00706 AttribsChangedFunc func; 00707 void *data; 00708 } AttribsChangedHook; 00709 00710 00711 void o_attrib_append_attribs_changed_hook (TOPLEVEL *toplevel, 00712 AttribsChangedFunc func, 00713 void *data) 00714 { 00715 AttribsChangedHook *new_hook; 00716 00717 new_hook = g_new0 (AttribsChangedHook, 1); 00718 new_hook->func = func; 00719 new_hook->data = data; 00720 00721 toplevel->attribs_changed_hooks = 00722 g_list_append (toplevel->attribs_changed_hooks, new_hook); 00723 } 00724 00725 00726 static void call_attribs_changed_hook (gpointer data, gpointer user_data) 00727 { 00728 AttribsChangedHook *hook = data; 00729 OBJECT *object = user_data; 00730 00731 hook->func (hook->data, object); 00732 } 00733 00734 00735 void o_attrib_emit_attribs_changed (TOPLEVEL *toplevel, OBJECT *object) 00736 { 00737 if (object->attrib_notify_freeze_count > 0) { 00738 object->attrib_notify_pending = 1; 00739 return; 00740 } 00741 00742 // printf ("The attributes of object %p have changed\n", object); 00743 00744 object->attrib_notify_pending = 0; 00745 00746 g_list_foreach (toplevel->attribs_changed_hooks, 00747 call_attribs_changed_hook, object); 00748 } 00749 00750 void o_attrib_freeze_hooks (TOPLEVEL *toplevel, OBJECT *object) 00751 { 00752 object->attrib_notify_freeze_count ++; 00753 } 00754 00755 void o_attrib_thaw_hooks (TOPLEVEL *toplevel, OBJECT *object) 00756 { 00757 g_return_if_fail (object->attrib_notify_freeze_count > 0); 00758 00759 object->attrib_notify_freeze_count --; 00760 00761 if (object->attrib_notify_freeze_count == 0 && 00762 object->attrib_notify_pending) 00763 o_attrib_emit_attribs_changed (toplevel, object); 00764 }