Updated po files using make update-po
[geda-gaf/peter-b.git] / libgeda / src / o_attrib.c
blobc9f5c58fc187eeadb59b8cadc92dbc0744cc4f3c
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 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 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
26 #include <math.h>
28 #include <gtk/gtk.h>
29 #include <libguile.h>
31 #include "defines.h"
32 #include "struct.h"
33 #include "globals.h"
34 #include "o_types.h"
35 #include "colors.h"
37 #include "../include/prototype.h"
39 #ifdef HAVE_LIBDMALLOC
40 #include <dmalloc.h>
41 #endif
43 /*! Basic string splitting delimiters */
44 #define DELIMITERS ",; "
46 /*! \note
47 * No special type for attributes
48 * You can only edit text attributes
50 * be sure in o_copy o_move o_delete you maintain the attributes
51 * delete is a bare, because you will have to unattach the other end
52 * and in o_save o_read as well
53 * and in o_select when selecting objects, select the attributes
55 * \todo there needs to be a modifier (in struct.h, such as a flag) which
56 * signifies that this is an attribute (really? why?)
58 * \note
59 * return pointer from attrib_list
62 /*! \brief Update an attribute's uref.
63 * \par Function Description
64 * Update an attribute's uref.
66 * \param [in] w_current The TOPLEVEL object
67 * \param [in] o_current The object to update.
69 * \note
70 * Martin Benes' auto uref renumber code
72 void o_attrib_update_urefBM (TOPLEVEL *w_current, OBJECT *o_current)
74 OBJECT *list_head,*obj;
75 char *uref;
76 int i = -1, name_conflict,len;
77 char *index_list;
78 int index_list_len=1;
80 if (strncmp(o_current->text->string,"uref=",5)) /* deprecated */
81 return;
83 len=strlen(o_current->text->string);
84 uref=g_malloc(len+10);
85 strcpy(uref,o_current->text->string);
87 while (o_current->text->string[len-1]<='9' &&
88 o_current->text->string[len-1]>='0')
89 --len;
91 list_head=return_head(o_current);
92 for (obj=list_head->next;obj;obj=obj->next) {
93 if (obj->type==OBJ_TEXT && obj->attribute)
94 ++index_list_len;
97 index_list=calloc(index_list_len,1); /* convert to g_new maybe... */
98 name_conflict=0;
100 for (obj=list_head->next;obj;obj=obj->next) {
101 if (obj->type==OBJ_TEXT && obj->attribute && obj!=o_current) {
102 if (strncmp(uref,obj->text->string,len)==0) {
103 if (strcmp(uref+len,obj->text->string+len)==0) {
104 name_conflict=1;
106 i=atoi(obj->text->string+len);
107 if (i<index_list_len)
108 index_list[i]=1;
113 if (name_conflict) {
114 for (i=0;index_list[i];++i);
115 sprintf(uref+len,"%d", i);
116 g_free(o_current->text->string);
117 o_current->text->string=uref;
118 o_text_recreate(w_current, o_current);
121 g_free(index_list);
124 /*! \brief Search for an item in an attribute list.
125 * \par Function Description
126 * Search for an item in an attribute list.
128 * \param [in] list ATTRIB pointer to the list to be searched.
129 * \param [in] item item to be found.
131 ATTRIB *o_attrib_search(ATTRIB *list, OBJECT *item)
133 ATTRIB *a_current;
135 if (item == NULL) {
136 return(NULL);
139 a_current = list;
141 while(a_current != NULL) {
142 if (a_current->object != NULL) {
143 if (item->sid == a_current->object->sid) {
144 return(a_current);
148 a_current = a_current->next;
151 return(NULL);
154 /*! \brief Get the last attribute in the list.
155 * \par Function Description
156 * Get the last attribute in the list.
158 * \param [in] head ATTRIB pointer to beginning of list.
159 * \return Returns an ATTRIB pointer to the last attribute in the list.
161 ATTRIB *o_attrib_return_tail(ATTRIB *head)
163 ATTRIB *a_current=NULL;
164 ATTRIB *current=NULL;
166 a_current = head;
167 while ( a_current != NULL ) { /* goto end of list */
168 current = a_current;
169 a_current = a_current->next;
171 return(current);
174 /*! \brief Create an attribute list head item.
175 * \par Function Description
176 * Create an attribute list head item.
178 * \param [in] parent OBJECT pointer that will become the parent
179 * of this new head item.
180 * \return Returns an ATTRIB pointer to the newly created head item.
182 * \todo Rename this function to be consistant.
184 ATTRIB *add_attrib_head(OBJECT *parent)
186 ATTRIB *head = NULL;
188 head = (ATTRIB *) g_malloc(sizeof(ATTRIB));
189 head->next = NULL;
191 /* highly experimental hack */
192 head->object = parent;
193 head->copied_to = NULL;
194 head->prev = NULL;
196 /* \todo
197 * why the grief? well everywhere a attribute is refered to
198 * you have to skip over the head, you really ought to robustify
199 * all references to this object pointer when talking to attributes
200 * hack of course I think this is okay now though
203 return(head);
206 /*! \brief Add an attribute to an existing attribute list.
207 * \par Function Description
208 * Add an attribute to an existing attribute list.
210 * \param [in] w_current The TOPLEVEL object.
211 * \param [in,out] list_head The list where you want to add item to.
212 * \param [in] item The item you want to add as an attribute.
213 * \return An ATTRIB pointer to the newly created attribute.
215 ATTRIB *o_attrib_add(TOPLEVEL *w_current, ATTRIB *list_head, OBJECT *item)
217 ATTRIB *end = NULL;
218 ATTRIB *new = NULL;
220 /* get tail of list_head */
221 end = o_attrib_return_tail(list_head);
223 /* create an new st_attrib object */
224 new = (ATTRIB *) g_malloc(sizeof(ATTRIB));
226 /* fill item with correct data (mainly item) */
227 new->next = NULL;
228 new->prev = end;
229 new->object = item;
230 new->copied_to = NULL;
231 new->object->attribute = 1; /* Set the attribute to true, hack define */
232 /* Show that that item is an attribute */
233 new->object->color = w_current->attribute_color;
235 if (new->object->type == OBJ_TEXT) {
236 o_complex_set_color(new->object->text->prim_objs,
237 new->object->color);
238 } else if (new->object->type == OBJ_COMPLEX ||
239 new->object->type == OBJ_PLACEHOLDER) {
240 o_complex_set_color(new->object->complex->prim_objs,
241 new->object->color);
244 /* Add link from item to attrib listing */
245 new->object->attached_to = new;
247 /* set next of tail of end->attrib to item */
248 if (end) {
249 end->next = new;
250 return(new);
251 } else {
252 return(new);
256 /*! \brief Free single item in attribute list.
257 * \par Function Description
258 * Free single item in attribute list.
260 * \param [in] w_current The TOPLEVEL object.
261 * \param [in] current ATTRIB pointer to free.
263 * \note
264 * this routine is not nice to next and prev
265 * this routine is only called from free_all
267 void o_attrib_free(TOPLEVEL *w_current, ATTRIB *current)
269 if (current != NULL) {
271 /* \todo this makes me nervous... very nervous */
272 if (current->object != NULL && current->prev != NULL) {
273 current->object->attribute = 0;
274 current->object->attached_to=NULL;
275 current->object->color = w_current->detachedattr_color;
277 if (current->object->type == OBJ_TEXT) {
278 o_complex_set_color(current->object->text->prim_objs,
279 current->object->color);
280 } else {
281 printf("Tried to set the color on a complex!\nlibgeda/src/o_attrib_free 1\n");
284 /* \todo not sure on this */
285 if (current->object->saved_color != -1) {
286 if (current->object->type == OBJ_TEXT) {
287 o_complex_set_saved_color_only(
288 current->object->text->prim_objs,
289 w_current->detachedattr_color);
290 } else {
291 printf("Tried to set the color on a complex!\nlibgeda/src/o_attrib_free 2\n");
293 current->object->saved_color = w_current->
294 detachedattr_color;
298 /* \todo were do we detach the object->attached_to? above */
299 current->object=NULL;
301 g_free(current);
306 /*! \brief Attach existing attribute to an object.
307 * \par Function Description
308 * Attach existing attribute to an object.
310 * \param [in] w_current The TOPLEVEL object.
311 * \param [in] parent_list List where actual attribute objects live.
312 * \param [in] text_object The attribute to be added.
313 * \param [out] object The object where you want to add item as an attribute.
315 * \par IMPORTANT:
316 * Lists first then specific single item.
318 * \note
319 * typically parent_list is object_parent (object_head), but it is
320 * overridden in o_complex_add so that it points to head node of the complex
323 void o_attrib_attach(TOPLEVEL *w_current, OBJECT *parent_list,
324 OBJECT *text_object, OBJECT *object)
326 OBJECT *o_current = NULL;
328 ATTRIB *found = NULL;
329 OBJECT *found2 = NULL; /* object in main list */
331 o_current = text_object;
333 if (object == NULL) {
334 printf("ah.. object was not found in the parent list!\n");
335 return;
338 /* is the object already part of the list ? */
339 found = o_attrib_search(object->attribs, o_current);
340 if (!found) { /* no it's not, add it to the list */
342 found2 = (OBJECT *) o_list_search(parent_list, o_current);
344 /* check to see if found2 is not null hack */
345 if (found2) {
346 if (found2->type == OBJ_TEXT) {
348 if (object->attribs == NULL) {
349 object->attribs =
350 add_attrib_head(object);
354 if (found2->attached_to) {
355 fprintf(stderr, "You cannot attach this attribute [%s] to more than one object\n", found2->text->string);
356 } else {
358 o_attrib_add(w_current,
359 object->attribs,
360 found2);
362 o_current->color = w_current->
363 attribute_color;
365 o_complex_set_color(
366 o_current->text->prim_objs,
367 o_current->color);
369 if (o_current->saved_color != -1) {
370 o_complex_set_saved_color_only(
371 o_current->text->prim_objs,
372 o_current->color);
373 o_current->saved_color =
374 o_current->color;
376 /* can't do this here since just selecting something */
377 /* will cause this to be set */
378 /* w_current->page_current->CHANGED=1;*/
380 #ifdef MARTIN_BENES
381 o_attrib_update_urefBM (w_current, o_current);
382 #endif
384 } else {
385 fprintf(stderr, "You cannot attach non text items as attributes!\n");
388 } else {
389 if (o_current->text->string) {
390 printf("Attribute [%s] already attached\n",
391 o_current->text->string);
396 /*! \todo Empty function.
397 * \brief
398 * \par Function Description
400 * \param [in] w_current The TOPLEVEL object.
401 * \param [in] list
402 * \param [in] items
404 void
405 o_attrib_detach_test(TOPLEVEL *w_current, OBJECT *list, OBJECT *items)
408 /* this all needs to be rethought out */
409 /* loop over items till NULL */
410 /* Search for item in object->attrib */
411 /* o_attrib_search(list->attribs, current_item) */
412 /* if found */
413 /*call o_attrib_remove(object->attributes, current_item->attrib_struct);*/
414 /* if not found */
415 /* do nothing */
419 /*! \todo Empty function.
420 * \brief
421 * \par Function Description
423 * \param [in] list
424 * \param [in] item
426 /* only can edit a text, special case of edit text */
427 void o_attrib_edit(OBJECT *list, OBJECT *item)
432 /*! \todo Empty function.
433 * \brief
434 * \par Function Description
436 * \param [in] list
438 * \note
439 * should this be st_attrib or st_object?
441 void o_attrib_select_draw(ATTRIB *list)
443 /* draw list */
444 /* either white */
445 /* or a white bounding box? */
448 /*! \todo Empty function.
449 * \brief
450 * \par Function Description
452 * \param [in] list
454 * \note
455 * should this be st_attrib or st_object?
457 void o_attrib_unselect_draw(ATTRIB *list)
459 /* draw list */
460 /* either white */
461 /* or a white bounding box? */
465 /*! \brief Free all attribute items in a list.
466 * \par Function Description
467 * Free all attribute items in a list.
469 * \param [in] w_current The TOPLEVEL object.
470 * \param [in,out] list The list to free.
472 * \note
473 * this routine uses o_attrib_free (which isn't nice to next, prev)
474 * so it should only be used when an object is being destroyed
475 * goes backwards
477 void o_attrib_free_all(TOPLEVEL *w_current, ATTRIB *list)
479 ATTRIB *a_current;
480 ATTRIB *a_next;
482 a_current = list;
484 while (a_current != NULL) {
485 a_next = a_current->next;
486 o_attrib_free(w_current, a_current);
487 a_current = a_next;
491 /*! \brief Print all attributes to a Postscript document.
492 * \par Function Description
493 * Print all attributes to a Postscript document.
495 * \param [in] attributes List of attributes to print.
497 void o_attrib_print(ATTRIB *attributes)
499 ATTRIB *a_current;
501 a_current = attributes;
503 while (a_current != NULL) {
504 printf("Attribute points to: %s\n", a_current->object->name);
505 if (a_current->object && a_current->object->text) {
506 printf("\tText is: %s\n", a_current->object->text->string);
509 if (!a_current->object) {
510 printf("oops found a null attrib object\n");
512 a_current = a_current->next;
516 /*! \brief Print all attributes in reverse order to a Postscript document.
517 * \par Function Description
518 * Print all attributes in reverse order to a Postscript document.
520 * \param [in] attributes List of attributes to print.
522 void o_attrib_print_reverse(ATTRIB *attributes)
524 ATTRIB *a_current;
526 a_current = o_attrib_return_tail(attributes);
528 while (a_current != NULL) {
529 printf("Attribute points to: %s\n", a_current->object->name);
530 if (a_current->object && a_current->object->text) {
531 printf("\tText is: %s\n", a_current->object->text->string);
534 if (!a_current->object) {
535 printf("oops found a null attrib object\n");
537 a_current = a_current->prev;
541 /*! \todo Empty function.
542 * \brief
543 * \par Function Description
545 * \param [in] list The attribute list to copy.
546 * \return Always NULL.
548 * \note
549 * very hard, I don't think we need it though
551 ATTRIB *o_attrib_copy(ATTRIB *list)
553 return(NULL);
556 /*! \brief Delete an attribute.
557 * \par Function Description
558 * This function goes out and removes the current attribute,
559 * while preserving the next, prev pointers.
560 * This function should be used when detaching an attribute.
562 * \param [in] a_current The attribute to be deleted.
564 void o_attrib_delete(ATTRIB *a_current)
566 if (a_current != NULL) {
568 if (a_current->next)
569 a_current->next->prev = a_current->prev;
570 else
571 a_current->next = NULL;
573 if (a_current->prev)
574 a_current->prev->next = a_current->next;
575 else
576 a_current->prev = NULL;
578 if (a_current->object) {
579 a_current->object->attribute=0;
580 a_current->object->attached_to=NULL;
582 a_current->object = NULL;
584 g_free(a_current);
588 /*! \todo Finish function.
589 * \brief Remove an attribute item from an attribute list.
590 * \par Function Description
591 * This function goes out and removes an attribute from a list.
592 * It searches for the attribute and then removes it using the
593 * good #o_attrib_delete() routine.
595 * \param [in] list ATTRIB list to remove attribute from.
596 * \param [in] remove The ATTRIB to remove from list.
598 * \note
599 * This function is the detach_all routine.
600 * It is not currently being used.
601 * It is not even done.
603 void o_attrib_remove(ATTRIB *list, ATTRIB *remove)
605 ATTRIB *a_current;
607 a_current = list;
609 while (a_current != NULL) {
611 if (a_current == remove) {
614 a_current = a_current->next;
618 /*! \todo Is this function used?
619 * \deprecated
620 * \brief Detach all attributes from a list.
621 * \par Function Description
622 * Detach all attributes from a list.
624 * \param [in] w_current The TOPLEVEL object.
625 * \param [in] object_list Attribute list to delete.
626 * \param [in] main_head The head of the attribute list.
628 void o_attrib_detach_all(TOPLEVEL *w_current, OBJECT *object_list, OBJECT *main_head)
630 #if 0 /* not used */
631 OBJECT *o_current=NULL;
633 o_current = object_list;
635 while(o_current != NULL) {
637 X = (OBJECT *) o_list_search(main_head, o_current);
639 if (X) {
640 if (X->attribs != NULL) {
641 o_attrib_free_all(w_current, X->attribs);
642 X->attribs = NULL; /* leak possible? */
643 w_current->page_current->CHANGED=1;
646 o_current = o_current->next;
648 #endif
651 /*! \brief Read attributes from a buffer.
652 * \par Function Description
653 * Read attributes from a TextBuffer.
655 * \param [in] w_current The TOPLEVEL object.
656 * \param [out] object_to_get_attribs Storage for attributes.
657 * \param [in] tb The text buffer to read from.
658 * \param [in] release_ver libgeda release version number.
659 * \param [in] fileformat_ver file format version number.
660 * \return Pointer to object_to_get_attribs.
662 OBJECT *o_read_attribs(TOPLEVEL *w_current,
663 OBJECT *object_to_get_attribs,
664 TextBuffer *tb,
665 unsigned int release_ver, unsigned int fileformat_ver)
667 OBJECT *object_list=NULL;
668 char *line = NULL;
669 char objtype;
670 int ATTACH=FALSE;
671 int saved_color = -1;
673 object_list = object_to_get_attribs;
675 while (1) {
677 line = s_textbuffer_next_line (tb);
678 if (line == NULL) break;
680 sscanf(line, "%c", &objtype);
681 switch (objtype) {
683 case(OBJ_LINE):
684 object_list = (OBJECT *) o_line_read(w_current,
685 object_list,
686 line,
687 release_ver, fileformat_ver);
688 break;
691 case(OBJ_NET):
692 object_list = (OBJECT *) o_net_read(w_current,
693 object_list,
694 line,
695 release_ver, fileformat_ver);
696 break;
698 case(OBJ_BUS):
699 object_list = (OBJECT *) o_bus_read(w_current,
700 object_list,
701 line,
702 release_ver, fileformat_ver);
703 break;
705 case(OBJ_BOX):
706 object_list = (OBJECT *) o_box_read(w_current,
707 object_list,
708 line,
709 release_ver, fileformat_ver);
710 break;
712 case(OBJ_CIRCLE):
713 object_list = (OBJECT *) o_circle_read(
714 w_current,
715 object_list,
716 line,
717 release_ver, fileformat_ver);
718 break;
720 case(OBJ_COMPLEX):
721 case(OBJ_PLACEHOLDER):
723 object_list = (OBJECT *) o_complex_read(
724 w_current,
725 object_list,
726 line,
727 release_ver, fileformat_ver);
729 /* this is necessary because complex may add
730 attributes which float */
731 /* still needed? */
732 object_list = (OBJECT *) return_tail(
733 object_list);
734 break;
736 case(OBJ_PIN):
737 object_list = (OBJECT *) o_pin_read(w_current,
738 object_list,
739 line,
740 release_ver, fileformat_ver);
741 break;
743 case(OBJ_ARC):
744 object_list = (OBJECT *) o_arc_read(w_current,
745 object_list,
746 line,
747 release_ver, fileformat_ver);
748 break;
750 case(OBJ_TEXT):
751 line = g_strdup (line);
752 object_list = (OBJECT *) o_text_read(w_current,
753 object_list,
754 line,
756 release_ver, fileformat_ver);
757 g_free (line);
758 saved_color = object_list->color;
759 ATTACH=TRUE;
761 break;
763 case(ENDATTACH_ATTR):
764 return(object_list);
765 break;
769 if (ATTACH) {
770 o_attrib_attach(w_current,
771 w_current->page_current->object_parent,
772 object_list, object_to_get_attribs);
773 /* check color to set it to the right value */
774 if (object_list->color != saved_color) {
775 object_list->color = saved_color;
777 if (object_list->type == OBJ_TEXT) {
778 o_complex_set_color(
779 object_list->text->prim_objs,
780 object_list->color);
781 } else {
782 printf("Tried to set the color on a complex in libgeda/src/o_read_attribs\n");
785 ATTACH=FALSE;
786 } else {
787 fprintf(stderr, "Tried to attach a non-text item as an attribute\n");
790 return(object_list);
793 /*! \brief Save attributes to a file.
794 * \par Function Description
795 * Save attributes to a file.
797 * \param [in] fp FILE pointer to write attributes to.
798 * \param [in] attribs attributes to write.
799 * \todo
800 * this should be trimmed down to only save attributes which are text items
802 void o_save_attribs(FILE *fp, ATTRIB *attribs)
804 ATTRIB *a_current=NULL;
805 OBJECT *o_current=NULL;
806 char *out;
808 a_current = attribs;
810 fprintf(fp, "{\n");
812 while ( a_current != NULL ) {
814 o_current = a_current->object;
816 if (o_current->type != OBJ_HEAD) {
818 #if DEBUG
819 printf("type: %d %c ref: %d %c\n", o_current->type, o_current->type,
820 OBJ_PIN, OBJ_PIN);
821 #endif
823 switch (o_current->type) {
825 case(OBJ_LINE):
826 out = (char *) o_line_save(o_current);
827 break;
829 case(OBJ_NET):
830 out = (char *) o_net_save(o_current);
831 break;
833 case(OBJ_BUS):
834 out = (char *) o_bus_save(o_current);
835 break;
837 case(OBJ_BOX):
838 out = (char *) o_box_save(o_current);
839 break;
841 case(OBJ_CIRCLE):
842 out = (char *) o_circle_save(o_current);
843 break;
845 case(OBJ_COMPLEX):
846 case(OBJ_PLACEHOLDER): /* new type -- SDB 1.20.2005 */
847 out = (char *) o_complex_save(o_current);
848 break;
850 case(OBJ_TEXT):
851 out = (char *) o_text_save(o_current);
852 break;
854 case(OBJ_PIN):
855 out = (char *) o_pin_save(o_current);
856 break;
858 case(OBJ_ARC):
859 out = (char *) o_arc_save(o_current);
860 break;
862 case(OBJ_PICTURE):
863 out = (char *) o_picture_save(o_current);
864 break;
866 default:
867 fprintf(stderr, "Error type!\n");
868 exit(-1);
869 break;
871 /* output the line */
872 fprintf(fp, "%s\n", out);
873 g_free(out);
875 a_current = a_current->next;
878 fprintf(fp, "}\n");
881 /*! \brief Get name and value from name=value attribute.
882 * \par Function Description
883 * Get name and value from a name=value attribute.
885 * \param [in] string String to split into name/value pair.
886 * \param [out] name_ptr Name if found in string, NULL otherwise.
887 * \param [out] value_ptr Value if found in string, NULL otherwise.
888 * \return TRUE if string had equals in it, FALSE otherwise.
890 * \note
891 * both name and value must be pre allocated
892 * And if you get an invalid attribute (improper) with a name and no
893 * value, then it is NOT an attribute.
894 * Also, there cannot be any spaces beside the equals sign
895 * Changed: now it allocates memory for name and value strings.
896 * \warning
897 * Caller must g_free these strings when not needed.
899 int o_attrib_get_name_value(char *string, char **name_ptr, char **value_ptr )
901 char *equal_ptr;
902 char **str_array;
904 if (name_ptr == NULL || value_ptr == NULL) {
905 return(FALSE);
908 *name_ptr = NULL; /* force these values to null */
909 *value_ptr = NULL;
911 if (!string) {
912 return(FALSE);
915 /* make sure there are no spaces in between equals */
916 equal_ptr = strchr(string, '=');
917 if (equal_ptr == NULL) {
918 return(FALSE);
922 /*! \todo Technically this isn't a correct if statement. This if will
923 * cause an invalid read for strings: =name and value=
925 if ( (*(equal_ptr + 1) == ' ') || (*(equal_ptr - 1) == ' ') ) {
926 /* sometimes you have text with an ='s in it, it shouldn't be */
927 /* treated like an attribute */
929 #if DEBUG
930 s_log_message("Found attrib/text with spaces beside the ='s [%s]\n",
931 string);
932 s_log_message("You can ignore the above message if the text is not intended to be an attribute\n");
933 fprintf(stderr, "Found an attribute with spaces beside the ='s [%s]\n",
934 string);
935 #endif
937 return(FALSE);
940 str_array = g_strsplit (string, "=", 2);
942 *name_ptr = g_strdup(str_array[0]);
943 *value_ptr = g_strdup(str_array[1]);
944 g_strfreev(str_array);
946 if (*value_ptr && (*value_ptr)[0] == '\0') {
947 s_log_message("Found an improper attribute: _%s_\n", string);
948 #if 0 /* for now leak this memory till this is verified correct everywhere */
949 g_free(*name_ptr); *name_ptr = NULL;
950 g_free(*value_ptr); *value_ptr = NULL;
951 #endif
952 return(FALSE);
953 } else {
954 return(TRUE);
958 /*! \brief Free the currently selected attribute.
959 * \par Function Description
960 * Free the currently selected attribute.
962 * \param [in] w_current The TOPLEVEL object containing current attribute.
965 void o_attrib_free_current(TOPLEVEL *w_current)
967 if (w_current->current_attribute) {
968 g_free(w_current->current_attribute);
970 w_current->current_attribute=NULL;
973 /*! \brief Set current show flag.
974 * \par Function Description
975 * Set current show flag.
977 * \param [in] w_current The TOPLEVEL object.
978 * \param [in] flag Any value which show_name_value takes.
979 * #SHOW_NAME_VALUE
980 * #SHOW_VALUE
981 * #SHOW_NAME
983 void o_attrib_set_show(TOPLEVEL *w_current, int flag)
985 w_current->current_show = flag;
988 /*! \brief Set current visibility flag.
989 * \par Function Description
990 * Set current visibility flag.
992 * \param [in] w_current The TOPLEVEL object.
993 * \param [in] flag Allowed values are:
994 * #VISIBLE
995 * #INVISIBLE
997 void
998 o_attrib_set_visible(TOPLEVEL *w_current, int flag)
1000 w_current->current_visible = flag;
1003 /*! \brief Set an attribute's string.
1004 * \par Function Description
1005 * Set an attribute's string.
1007 * \param [in] w_current The TOPLEVEL object that holds the attribute.
1008 * \param [in] string The value to set attribute string to.
1010 * \note
1011 * The user of this function must g_free the
1012 * <B>w_current->current_attribute</B> string after done using it.
1013 * They must also free the input string.
1015 void o_attrib_set_string(TOPLEVEL *w_current, char *string)
1017 int len;
1019 /* need to put an error messages here */
1020 if (string == NULL) {
1021 fprintf(stderr, "error! string in set_string was NULL\n");
1022 return;
1025 if (w_current->current_attribute != NULL) {
1026 g_free(w_current->current_attribute);
1027 w_current->current_attribute=NULL;
1030 len = strlen(string);
1032 w_current->current_attribute = (char *) g_malloc(sizeof(char)*len+1);
1034 strcpy(w_current->current_attribute,string);
1036 /* be sure to g_free this string somewhere and free the input string */
1039 /*! \brief Get the parent OBJECT of an attribute.
1040 * \par Function Description
1041 * Get the parent OBJECT of an attribute.
1043 * \param [in] attribute ATTRIB pointer to get parent of.
1044 * \return The parent OBJECT if it exists, otherwise NULL.
1046 OBJECT *o_attrib_return_parent(ATTRIB *attribute)
1048 ATTRIB *a_current;
1050 a_current = attribute;
1052 if (!a_current) {
1053 return(NULL);
1056 while (a_current->prev != NULL) {
1057 a_current = a_current->prev;
1060 /* should be pointing to the parent */
1062 return(a_current->object);
1065 /*! \brief Copy all attributes.
1066 * \par Function Description
1067 * This function will copy all attributes from the provided list
1068 * by attaching them to the provided OBJECT list.
1070 * \param [in] w_current The TOPLEVEL object.
1071 * \param [out] attached_to OBJECT list to copy attributes to.
1072 * \param [in] attributes ATTRIB list to copy attributes from.
1073 * \return new attribute list.
1075 ATTRIB *o_attrib_copy_all(TOPLEVEL *w_current, OBJECT *attached_to,
1076 ATTRIB *attributes)
1078 ATTRIB *a_current=NULL;
1079 ATTRIB *a_head=NULL;
1080 ATTRIB *a_new=NULL;
1081 ATTRIB *a_prev=NULL;
1083 a_current = attributes;
1085 while (a_current != NULL) {
1087 a_new = (ATTRIB *) g_malloc(sizeof(ATTRIB));
1089 /* in the case of the head attrib node, object points to
1090 * the parent which the attributes are attached to */
1091 if (a_head == NULL) {
1092 a_new->object = attached_to;
1093 } else {
1094 a_new->object = a_current->object;
1099 /* object is not null and a_start is not null (ie we are not
1100 * messing with the head attrib node)
1102 if (a_new->object && a_head != NULL) {
1103 a_new->object->attached_to = a_new;
1106 a_new->copied_to = a_current->copied_to;
1108 a_new->prev = a_prev;
1110 /* set previous's next pointer */
1111 /* if it's null that means we are at the first attrib */
1112 if (a_prev) {
1113 a_prev->next = a_new;
1114 } else {
1115 a_head = a_new;
1118 a_new->next = NULL;
1119 a_prev = a_new;
1120 a_current = a_current->next;
1123 /* should be pointing to the head node */
1124 return(a_head);
1127 /*! \brief Reattach attributes.
1128 * \par Function Description
1129 * Reattach attributes.
1131 * \param [in] attributes ATTRIB list to reattach.
1133 void o_attrib_reattach(ATTRIB *attributes)
1135 ATTRIB *a_current=NULL;
1137 a_current = attributes;
1139 /* skip over head node */
1140 if (a_current)
1141 a_current = a_current->next;
1143 while (a_current != NULL) {
1144 if (a_current->object) {
1145 a_current->object->attached_to = a_current;
1146 a_current->object->attribute = 1;
1148 a_current = a_current->next;
1152 /*! \brief Set attribute color
1153 * \par Function Description
1154 * This function sets all attribute objects to the right
1155 * color (attribute_color).
1157 * \param [in] w_current The TOPLEVEL object.
1158 * \param [in,out] attributes ATTRIB list to set colors on.
1161 void o_attrib_set_color(TOPLEVEL *w_current, ATTRIB *attributes)
1163 ATTRIB *a_current;
1165 a_current = attributes;
1167 /* skip over head */
1168 if (a_current)
1169 a_current = a_current->next;
1171 while (a_current != NULL) {
1173 if (a_current->object) {
1175 if (a_current->object->type == OBJ_TEXT &&
1176 a_current->object->text->prim_objs) {
1178 /* I'm not terribly happy with this */
1180 if (a_current->object->saved_color != -1) {
1182 /* if the object is selected, make */
1183 /* sure it it say selected */
1184 o_complex_set_color(
1185 a_current->object->text->prim_objs,
1186 SELECT_COLOR);
1187 a_current->object->color =
1188 SELECT_COLOR;
1190 o_complex_set_saved_color_only(
1191 a_current->object->text->prim_objs,
1192 w_current->attribute_color);
1193 a_current->object->saved_color = w_current->
1194 attribute_color;
1196 } else {
1197 o_complex_set_color(
1198 a_current->object->text->prim_objs,
1199 w_current->attribute_color);
1200 a_current->object->color =
1201 w_current->attribute_color;
1205 a_current = a_current->next;
1210 /*! \brief Search for attibute by name.
1211 * \par Function Description
1212 * Search for attribute by name.
1214 * \warning
1215 * The list is the top level list. Do not pass it an object_head list
1216 * unless you know what you are doing.
1218 * Counter is the n'th occurance of the attribute, and starts searching
1219 * from zero. Zero is the first occurance of an attribute.
1221 * \param [in] list OBJECT list to search.
1222 * \param [in] name Character string with attribute name to search for.
1223 * \param [in] counter Which occurance to return.
1224 * \return Character string with attribute value, NULL otherwise.
1226 * \warning
1227 * Caller must g_free returned character string.
1229 char *o_attrib_search_name(OBJECT *list, char *name, int counter)
1231 OBJECT *o_current;
1232 ATTRIB *a_current;
1233 OBJECT *found;
1234 int val;
1235 int internal_counter=0;
1236 char *found_name = NULL;
1237 char *found_value = NULL;
1238 char *return_string = NULL;
1240 o_current = list;
1242 while(o_current != NULL) {
1243 if (o_current->attribs != NULL) {
1244 a_current = o_current->attribs;
1246 while(a_current != NULL) {
1247 found = a_current->object;
1248 if (found != NULL) {
1249 if (found->type == OBJ_TEXT) {
1250 val = o_attrib_get_name_value(found->text->string,
1251 &found_name, &found_value);
1253 if (val) {
1254 if (strcmp(name, found_name) == 0) {
1255 if (counter != internal_counter) {
1256 internal_counter++;
1257 } else {
1258 return_string = (char *)
1259 g_malloc(sizeof(char)*strlen(found_value)+1);
1260 strcpy(return_string, found_value);
1261 if (found_name) g_free(found_name);
1262 if (found_value) g_free(found_value);
1263 return(return_string);
1266 if (found_name) { g_free(found_name); found_name = NULL; }
1267 if (found_value) { g_free(found_value); found_value = NULL; }
1270 #if DEBUG
1271 printf("0 _%s_\n", found->text->string);
1272 printf("1 _%s_\n", found_name);
1273 printf("2 _%s_\n", found_value);
1274 #endif
1277 a_current=a_current->next;
1281 /* search for attributes outside */
1283 if (o_current->type == OBJ_TEXT) {
1284 if (found_name) g_free(found_name);
1285 if (found_value) g_free(found_value);
1286 val = o_attrib_get_name_value(o_current->text->string,
1287 &found_name, &found_value);
1288 if (val) {
1289 if (strcmp(name, found_name) == 0) {
1290 if (counter != internal_counter) {
1291 internal_counter++;
1292 } else {
1293 return_string = (char *)
1294 g_malloc(sizeof(char)* strlen(found_value)+1);
1295 strcpy(return_string, found_value);
1296 if (found_name) g_free(found_name);
1297 if (found_value) g_free(found_value);
1298 return(return_string);
1301 if (found_name) { g_free(found_name); found_name = NULL; }
1302 if (found_value) { g_free(found_value); found_value = NULL; }
1306 o_current=o_current->next;
1309 if (found_name) g_free(found_name);
1310 if (found_value) g_free(found_value);
1311 return (NULL);
1314 /*! \brief Search OBJECT list for text string.
1315 * \par Function Description
1316 * Given an OBJECT list (i.e. OBJECTs on schematic page or
1317 * inside symbol), search for the attribute called out in
1318 * "string". It iterates over all objects in the OBJECT list
1319 * and dives into the attached ATTRIB list for
1320 * each OBJECT if it finds one.
1321 * Inside the ATTRIB list it looks for an attached text
1322 * attribute matching "string". It returns the
1323 * pointer to the associated OBJECT if found. If the attribute
1324 * string is not found in the ATTRIB list, then the fcn
1325 * looks on the OBJECT itself for the attribute. Then it
1326 * iterates to the next OBJECT.
1328 * \warning
1329 * The list is the top level list. Do not pass it an object_head list
1330 * unless you know what you are doing.
1332 * \param [in] list OBJECT list to search.
1333 * \param [in] string Character string to search for.
1334 * \return A matching OBJECT if found, NULL otherwise.
1336 OBJECT *o_attrib_search_string_list(OBJECT *list, char *string)
1338 OBJECT *o_current;
1339 ATTRIB *a_current;
1340 OBJECT *found;
1342 o_current = list;
1344 while(o_current != NULL) {
1345 /* first search attribute list */
1346 if (o_current->attribs != NULL) {
1347 a_current = o_current->attribs;
1349 while(a_current != NULL) {
1350 found = a_current->object;
1351 if (found != NULL) {
1352 if (found->type == OBJ_TEXT) {
1353 #if DEBUG
1354 printf("libgeda:o_attrib.c:o_attrib_search_string_list --");
1355 printf("found OBJ_TEXT, string = %s\n", found->text->string);
1356 #endif
1357 if (strcmp(string, found->text->string) == 0) {
1358 return(found);
1362 a_current=a_current->next;
1366 /* search for attributes outside (ie the actual object) */
1367 if (o_current->type == OBJ_TEXT) {
1368 if (strcmp(string, o_current->text->string) == 0) {
1369 return(o_current);
1373 o_current=o_current->next;
1376 return (NULL);
1379 /*! \brief Search list for partial string match.
1380 * \par Function Description
1381 * Search list for partial string match.
1383 * Counter is the n'th occurance of the attribute, and starts searching
1384 * from zero. Zero is the first occurance of an attribute.
1386 * \param [in] object The OBJECT list to search.
1387 * \param [in] search_for Partial character string to search for.
1388 * \param [in] counter Which occurance to return.
1389 * \return Matching object value if found, NULL otherwise.
1391 * \warning
1392 * Caller must g_free returned character string.
1394 char *o_attrib_search_string_partial(OBJECT *object, char *search_for,
1395 int counter)
1397 OBJECT *o_current;
1398 int val;
1399 int internal_counter=0;
1400 char *found_name = NULL;
1401 char *found_value = NULL;
1402 char *return_string = NULL;
1404 o_current = object;
1406 if (o_current == NULL) {
1407 return(NULL);
1410 if (o_current->type == OBJ_TEXT) {
1411 if (strstr(o_current->text->string, search_for)) {
1412 if (counter != internal_counter) {
1413 internal_counter++;
1414 } else {
1415 val = o_attrib_get_name_value(o_current->text->string,
1416 &found_name, &found_value);
1417 if (val) {
1418 return_string = g_strdup(found_value);
1419 if (found_name) g_free(found_name);
1420 if (found_value) g_free(found_value);
1421 return(return_string);
1427 if (found_name) g_free(found_name);
1428 if (found_value) g_free(found_value);
1429 return (NULL);
1432 /*! \brief Check if object matches string.
1433 * \par Function Description
1434 * This function will check if the text->string value of
1435 * the passed OBJECT matches the <B>search_for</B> parameter.
1436 * If not, it then searches the object's ATTRIB list (if
1437 * it has one.)
1438 * Only this single OBJECT and its ATTRIB list is
1439 * checked, and other OBJECTs on the page are not checked.
1440 * \param [in] object The OBJECT to compare.
1441 * \param [in] search_for Character string to compare against.
1442 * Usually name=value
1443 * \return The OBJECT passed in <B>object</B> parameter, NULL otherwise.
1445 OBJECT *o_attrib_search_string_single(OBJECT *object, char *search_for)
1447 OBJECT *o_current;
1448 OBJECT *found;
1449 ATTRIB *a_current;
1451 o_current = object;
1453 #if DEBUG
1454 printf("In libgeda:o_attrib.c:o_attrib_search_string_single\n");
1455 printf(" Examining object->name = %s\n", object->name);
1456 #endif
1458 if (o_current == NULL) {
1459 return(NULL);
1462 /* First check to see if this OBJECT itself is the attribute we want */
1463 if (o_current->type == OBJ_TEXT) {
1464 if (strcmp(o_current->text->string, search_for) == 0) {
1465 #if DEBUG
1466 printf(" This object is searched-for attribute\n");
1467 #endif
1468 return(o_current);
1472 /* Next check to see if this OBJECT has an ATTRIB list we */
1473 /* can search. If not return NULL. If so, search it. */
1474 if (o_current->attribs == NULL)
1475 return(NULL);
1477 a_current = o_current->attribs;
1478 while(a_current != NULL) {
1479 found = a_current->object;
1480 if (found != NULL) {
1481 if (found->type == OBJ_TEXT) {
1482 if(strcmp(found->text->string, search_for) == 0) {
1483 return(found);
1487 a_current=a_current->next;
1490 return (NULL);
1493 /*! \brief Search for attribute by value and name.
1494 * \par Function Description
1495 * Search for attribute by value and name.
1497 * Counter is the n'th occurance of the attribute, and starts searching
1498 * from zero. Zero is the first occurance of an attribute.
1500 * The value is the primary search key, but name is checked before
1501 * an OBJECT is returned to ensure the correct OBJECT has been found.
1503 * \param [in] list The ATTRIB list to search.
1504 * \param [in] value Character string with value to search for.
1505 * \param [in] name Character string with name to compare.
1506 * \param [in] counter Which occurance to return.
1507 * \return The attribute OBJECT if found, NULL otherwise.
1510 OBJECT *o_attrib_search_attrib_value(ATTRIB *list, char *value, char *name,
1511 int counter)
1513 OBJECT *found;
1514 ATTRIB *a_current;
1515 int val;
1516 int internal_counter=0;
1517 char *found_name = NULL;
1518 char *found_value = NULL;
1520 a_current = list;
1522 if (!value)
1523 return(NULL);
1525 if (!name)
1526 return(NULL);
1528 while(a_current != NULL) {
1529 found = a_current->object;
1530 if (found != NULL) {
1531 if (found->type == OBJ_TEXT) {
1532 val = o_attrib_get_name_value(found->text->string,
1533 &found_name, &found_value);
1535 if (val) {
1536 #if DEBUG
1537 printf("found value: %s\n", found_value);
1538 printf("looking for: %s\n", value);
1539 #endif
1540 if (strcmp(value, found_value) == 0) {
1541 if (counter != internal_counter) {
1542 internal_counter++;
1543 } else {
1544 if (strstr(found_name, name)) {
1545 if (found_name) g_free(found_name);
1546 if (found_value) g_free(found_value);
1547 return(found);
1551 if (found_name) { g_free(found_name); found_name = NULL; }
1552 if (found_value) { g_free(found_value); found_value = NULL; }
1557 a_current=a_current->next;
1560 if (found_name) g_free(found_name);
1561 if (found_value) g_free(found_value);
1562 return (NULL);
1565 /*! \brief Search for an attribute by name.
1566 * \par Function Description
1567 * Search for an attribute by name.
1569 * Counter is the n'th occurance of the attribute, and starts searching
1570 * from zero. Zero is the first occurance of an attribute.
1572 * \param [in] list ATTRIB list to search.
1573 * \param [in] name Character string with attribute name to search for.
1574 * \param [in] counter Which occurance to return.
1575 * \return Character string with attribute value, NULL otherwise.
1577 * \warning
1578 * Caller must g_free returned character string.
1580 char *
1581 o_attrib_search_attrib_name(ATTRIB *list, char *name, int counter)
1583 OBJECT *found;
1584 ATTRIB *a_current;
1585 int val;
1586 int internal_counter=0;
1587 char *found_name = NULL;
1588 char *found_value = NULL;
1589 char *return_string = NULL;
1591 a_current = list;
1593 while(a_current != NULL) {
1594 found = a_current->object;
1595 if (found != NULL) {
1596 if (found->type == OBJ_TEXT) {
1597 val = o_attrib_get_name_value(found->text->string,
1598 &found_name, &found_value);
1600 if (val) {
1601 #if DEBUG
1602 printf("found name: %s\n", found_name);
1603 printf("looking for: %s\n", name);
1604 #endif
1605 if (strcmp(name, found_name) == 0) {
1606 if (counter != internal_counter) {
1607 internal_counter++;
1608 } else {
1609 return_string = (char *)
1610 g_malloc(sizeof(char)* strlen(found_value)+1);
1611 strcpy(return_string, found_value);
1612 if (found_name) g_free(found_name);
1613 if (found_value) g_free(found_value);
1614 return(return_string);
1617 if (found_name) { g_free(found_name); found_name = NULL; }
1618 if (found_value) { g_free(found_value); found_value = NULL; }
1622 a_current=a_current->next;
1625 if (found_name) g_free(found_name);
1626 if (found_value) g_free(found_value);
1627 return (NULL);
1630 /*! \brief Search TOPLEVEL attributes.
1631 * \par Function Description
1632 * This function should only be used to search for TOPLEVEL attributes.
1633 * \warning
1634 * The list is the top level list. Do not pass it an object_head list
1635 * unless you know what you are doing.
1637 * Counter is the n'th occurance of the attribute, and starts searching
1638 * from zero. Zero is the first occurance of an attribute.
1640 * \param [in] list The OBJECT list to search (TOPLEVEL only).
1641 * \param [in] name Character string of attribute name to search for.
1642 * \param [in] counter Which occurance to return.
1643 * \return Character string with attribute value, NULL otherwise.
1645 * \warning
1646 * Caller must g_free returned character string.
1648 char *o_attrib_search_toplevel(OBJECT *list, char *name, int counter)
1650 OBJECT *o_current;
1651 int val;
1652 int internal_counter=0;
1653 char *found_name = NULL;
1654 char *found_value = NULL;
1655 char *return_string = NULL;
1657 o_current = list;
1659 while(o_current != NULL) {
1661 /* search for attributes outside */
1663 if (o_current->type == OBJ_TEXT) {
1664 val = o_attrib_get_name_value(o_current->text->string,
1665 &found_name, &found_value);
1666 if (val) {
1667 if (strcmp(name, found_name) == 0) {
1668 if (counter != internal_counter) {
1669 internal_counter++;
1670 } else {
1671 return_string = (char *)
1672 g_malloc(sizeof(char)* strlen(found_value)+1);
1673 strcpy(return_string, found_value);
1674 if (found_name) g_free(found_name);
1675 if (found_value) g_free(found_value);
1676 return(return_string);
1679 if (found_name) { g_free(found_name); found_name = NULL; }
1680 if (found_value) { g_free(found_value); found_value = NULL; }
1684 o_current=o_current->next;
1687 if (found_name) g_free(found_name);
1688 if (found_value) g_free(found_value);
1689 return (NULL);
1692 /*! \brief Search for special attributes.
1693 * \par Function Description
1694 * This function will search an OBJECT list for the special
1695 * attributes <EM>"gnd"</EM> and <EM>"vdd"</EM>.
1697 * \param [in] o_current The OBJECT list to search.
1698 * \return Character string with attribute value, NULL otherwise.
1700 * \warning
1701 * Caller must g_free returned character string.
1703 /* be sure caller free's return value */
1704 char *o_attrib_search_special(OBJECT *o_current)
1706 char *return_value;
1708 return_value = o_attrib_search_name(o_current->complex->prim_objs,
1709 "gnd", 0);
1711 if (return_value) {
1712 return(return_value);
1715 return_value = o_attrib_search_name(o_current->complex->prim_objs,
1716 "vdd", 0);
1718 if (return_value) {
1719 return(return_value);
1722 return(NULL);
1725 /*! \brief Search for first occurance of a named attribute.
1726 * \par Function Description
1727 * Search for first occurance of a named attribute.
1729 * \param [in] object The OBJECT list to search.
1730 * \param [in] name Character string of attribute name to search for.
1731 * \param [out] return_found Contains attribute OBJECT if found, NULL otherwise.
1732 * \return Character string with attribute value, NULL otherwise.
1734 * \warning
1735 * Caller must g_free returned character string.
1737 char *o_attrib_search_name_single(OBJECT *object, char *name,
1738 OBJECT **return_found)
1740 OBJECT *o_current;
1741 ATTRIB *a_current;
1742 OBJECT *found=NULL;
1743 int val;
1744 char *found_name = NULL;
1745 char *found_value = NULL;
1746 char *return_string = NULL;
1748 o_current = object;
1750 if (o_current == NULL) {
1751 return(NULL);
1754 if (o_current->attribs != NULL) {
1755 a_current = o_current->attribs;
1757 while(a_current != NULL) {
1758 found = a_current->object;
1759 if (found != NULL) {
1760 if (found->type == OBJ_TEXT) {
1761 val = o_attrib_get_name_value(found->text->string,
1762 &found_name, &found_value);
1764 if (val) {
1765 if (strcmp(name, found_name) == 0) {
1766 return_string = (char *)
1767 g_malloc(sizeof(char)* strlen(found_value)+1);
1768 strcpy(return_string, found_value);
1769 if (return_found) {
1770 *return_found = found;
1772 if (found_name) g_free(found_name);
1773 if (found_value) g_free(found_value);
1774 return(return_string);
1776 if (found_name) { g_free(found_name); found_name = NULL; }
1777 if (found_value) { g_free(found_value); found_value = NULL; }
1780 #if DEBUG
1781 printf("0 _%s_\n", found->text->string);
1782 printf("1 _%s_\n", found_name);
1783 printf("2 _%s_\n", found_value);
1784 #endif
1787 a_current=a_current->next;
1790 /* search for attributes outside */
1792 if (o_current->type == OBJ_TEXT) {
1793 if (found_name) g_free(found_name);
1794 if (found_value) g_free(found_value);
1795 val = o_attrib_get_name_value(o_current->text->string,
1796 &found_name, &found_value);
1798 if (val) {
1799 if (strcmp(name, found_name) == 0) {
1800 return_string = (char *)
1801 g_malloc(sizeof(char)* strlen(found_value)+1);
1802 strcpy(return_string, found_value);
1803 if (return_found) {
1804 *return_found = found;
1806 if (found_name) g_free(found_name);
1807 if (found_value) g_free(found_value);
1808 return(return_string);
1810 if (found_name) { g_free(found_name); found_name = NULL; }
1811 if (found_value) { g_free(found_value); found_value = NULL; }
1815 if (return_found) {
1816 *return_found = NULL;
1819 if (found_name) g_free(found_name);
1820 if (found_value) g_free(found_value);
1821 return (NULL);
1824 /*! \brief Search for N'th occurance of a named attribute.
1825 * \par Function Description
1826 * Search for N'th occurance of a named attribute.
1828 * \param [in] object The OBJECT list to search.
1829 * \param [in] name Character string of attribute name to search for.
1830 * \param [in] counter Which occurance to return.
1831 * \return Character string with attribute value, NULL otherwise.
1833 * \warning
1834 * Caller must g_free returned character string.
1836 /* be sure caller free's return value */
1837 /* this function is like above, except that it returns the n'th occurance */
1838 /* of the attribute. counter starts counting at zero */
1839 char *o_attrib_search_name_single_count(OBJECT *object, char *name,
1840 int counter)
1842 OBJECT *o_current;
1843 ATTRIB *a_current;
1844 OBJECT *found=NULL;
1845 int val;
1846 char *found_name = NULL;
1847 char *found_value = NULL;
1848 char *return_string = NULL;
1849 int internal_counter=0;
1852 o_current = object;
1854 if (o_current == NULL) {
1855 return(NULL);
1858 if (o_current->attribs != NULL) {
1859 a_current = o_current->attribs;
1861 while(a_current != NULL) {
1862 found = a_current->object;
1863 if (found != NULL) {
1864 if (found->type == OBJ_TEXT) {
1865 val = o_attrib_get_name_value(found->text->string,
1866 &found_name, &found_value);
1868 if (val) {
1869 if (strcmp(name, found_name) == 0) {
1870 if (counter != internal_counter) {
1871 internal_counter++;
1872 } else {
1873 return_string = (char *)
1874 g_malloc(sizeof(char)* strlen(found_value)+1);
1875 strcpy(return_string, found_value);
1876 if (found_name) g_free(found_name);
1877 if (found_value) g_free(found_value);
1878 return(return_string);
1881 if (found_name) { g_free(found_name); found_name = NULL; }
1882 if (found_value) { g_free(found_value); found_value = NULL; }
1885 #if DEBUG
1886 printf("0 _%s_\n", found->text->string);
1887 printf("1 _%s_\n", found_name);
1888 printf("2 _%s_\n", found_value);
1889 #endif
1892 a_current=a_current->next;
1896 /* search for attributes outside */
1898 if (o_current->type == OBJ_TEXT) {
1899 if (found_name) g_free(found_name);
1900 if (found_value) g_free(found_value);
1901 val = o_attrib_get_name_value(o_current->text->string,
1902 &found_name, &found_value);
1904 if (val) {
1905 if (strcmp(name, found_name) == 0) {
1906 if (counter != internal_counter) {
1907 internal_counter++;
1908 } else {
1909 return_string = (char *)
1910 g_malloc(sizeof(char)* strlen(found_value)+1);
1911 strcpy(return_string, found_value);
1912 if (found_name) g_free(found_name);
1913 if (found_value) g_free(found_value);
1914 return(return_string);
1917 if (found_name) { g_free(found_name); found_name = NULL; }
1918 if (found_value) { g_free(found_value); found_value = NULL; }
1922 if (found_name) g_free(found_name);
1923 if (found_value) g_free(found_value);
1924 return (NULL);
1927 /*! \brief Search for slot attribute.
1928 * \par Function Description
1929 * Search for slot attribute.
1931 * \param [in] object OBJECT list to search.
1932 * \param [in] return_found slot attribute if found, NULL otherwise.
1933 * \return Character string with attribute value, NULL otherwise.
1935 * \warning
1936 * Caller must g_free returned character string
1938 char *o_attrib_search_slot(OBJECT *object, OBJECT **return_found)
1940 char *return_value;
1942 /* search for default value attribute buried inside the complex */
1943 return_value = o_attrib_search_name_single(object, "slot", return_found);
1945 /* I'm confused here does the next if get ever called? */
1946 if (return_value) {
1947 return(return_value);
1950 if (return_found) {
1951 *return_found = NULL;
1953 return(NULL);
1956 /*! \brief Search for numslots attribute.
1957 * \par Function Description
1958 * Search for numslots attribute.
1960 * \param [in] object OBJECT to search.
1961 * \param [in] return_found numslots attribute if found, NULL otherwise.
1962 * \return Character string with attribute value, NULL otherwise.
1964 * \note
1965 * Caller must g_free returned character string.
1967 char *o_attrib_search_numslots(OBJECT *object, OBJECT **return_found)
1969 char *return_value = NULL;
1971 /* search for numslots attribute buried inside the complex */
1972 if (object->type == OBJ_COMPLEX) {
1973 return_value = o_attrib_search_name(object->complex->prim_objs,
1974 "numslots", 0);
1977 if (return_value) {
1978 return(return_value);
1981 if (return_found) {
1982 *return_found = NULL;
1984 return(NULL);
1987 /*! \brief Search for default slot attribute.
1988 * \par Function Description
1989 * Search for default slot attribute.
1991 * \param [in] object OBJECT list to search.
1992 * \return Character string with attribute value, NULL otherwise.
1994 * \warning
1995 * Caller must g_free returned character string.
1997 char *o_attrib_search_default_slot(OBJECT *object)
1999 char *return_value;
2001 /* search for default value attribute buried inside the complex */
2002 return_value = o_attrib_search_name(object->complex->prim_objs,
2003 "slot", 0);
2005 if (return_value) {
2006 return(return_value);
2009 return(NULL);
2012 /*! \brief Search pinseq attribute.
2013 * \par Function Description
2014 * Given list of objects (generally a pin with attached attribs),
2015 * and a pinnumber,
2016 * search for and return pinseq= attrib (object).
2018 * \param [in] list OBJECT list to search.
2019 * \param [in] pin_number pin number to search for.
2020 * \return OBJECT containing pinseq data, NULL otherwise.
2022 OBJECT *o_attrib_search_pinseq(OBJECT *list, int pin_number)
2024 OBJECT *pinseq_text_object;
2025 char *search_for;
2027 /* The 9 is the number of allowed digits plus null */
2028 search_for = (char *) g_malloc(sizeof(char)*(strlen("pinseq=")+9));
2029 sprintf(search_for, "pinseq=%d", pin_number);
2031 pinseq_text_object = o_attrib_search_string_list(list, search_for);
2032 g_free(search_for);
2034 if (pinseq_text_object && pinseq_text_object->attached_to) {
2035 return(o_attrib_return_parent(pinseq_text_object->attached_to));
2038 return(NULL);
2041 /*! \brief Search for slotdef attribute.
2042 * \par Function Description
2043 * Search for slotdef attribute.
2045 * \param [in] object The OBJECT list to search.
2046 * \param [in] slotnumber The slot number to search for.
2047 * \return Character string with attribute value, NULL otherwise.
2049 * \warning
2050 * Caller must g_free returned character string.
2052 char *o_attrib_search_slotdef(OBJECT *object, int slotnumber)
2054 char *return_value=NULL;
2055 char *search_for=NULL;
2056 OBJECT *o_current;
2058 /* The 9 is the number of digits plus null */
2059 search_for = (char *) g_malloc(sizeof(char)*(strlen("slotdef=:")+9));
2061 sprintf(search_for, "slotdef=%d:", slotnumber);
2063 o_current = object->complex->prim_objs;
2064 while (o_current != NULL) {
2065 return_value = o_attrib_search_string_partial(o_current, search_for, 0);
2066 if (return_value) {
2067 break;
2069 o_current = o_current->next;
2071 g_free(search_for);
2073 if (return_value) {
2074 return(return_value);
2077 return(NULL);
2080 /*! \brief Search for component.
2081 * \par Function Description
2082 * Search for component.
2084 * \param [in] object The OBJECT list to search.
2085 * \param [in] name Character string containing component name to match.
2086 * \return Character string with the component value, NULL otherwise.
2088 char *o_attrib_search_component(OBJECT *object, char *name)
2090 char *return_value = NULL;
2092 if (!name) {
2093 return(NULL);
2096 if (object->type != OBJ_COMPLEX && object->type != OBJ_PLACEHOLDER) {
2097 return(NULL);
2100 /* first look inside the complex object */
2101 return_value = o_attrib_search_name(object->complex->prim_objs,
2102 name, 0);
2104 if (return_value) {
2105 return(return_value);
2108 /* now look outside to see if it was attached externally */
2109 return_value = o_attrib_search_name_single(object, name, NULL);
2111 if (return_value) {
2112 return(return_value);
2115 return(NULL);
2118 /*! \brief Update all slot attributes in an object.
2119 * \par Function Description
2120 * Update pinnumber attributes in a graphic object.
2121 * The interesting case is where the object is an
2122 * instantiation of a slotted part. This means that
2123 * o_attrib_slot_update iterates through all pins
2124 * found on object and sets the pinnumber= attrib
2125 * on each. This doesn't matter for non-slotted
2126 * parts, but on slotted parts, this is what sets the
2127 * pinnumber= attribute on slots 2, 3, 4....
2129 * \param [in] w_current The TOPLEVEL object.
2130 * \param [in,out] object The OBJECT to update.
2132 void o_attrib_slot_update(TOPLEVEL *w_current, OBJECT *object)
2134 OBJECT *o_current; /* o_current points to the sch level complex object */
2135 OBJECT *o_slot_attrib;
2136 OBJECT *o_pin_object;
2137 OBJECT *o_pinnum_object;
2138 OBJECT *o_pinseq_object;
2139 char *string;
2140 char *slotdef;
2141 int slot;
2142 int pin_counter; /* Internal pin counter private to this fcn. */
2143 char *new_pinseq; /* New pinseq = (slot*(number of pins -1) + pin_count */
2144 int numpins; /* Total number of pins on this slot */
2145 char* current_pin; /* text from slotdef= to be made into pinnumber= */
2146 char* cptr; /* char pointer pointing to pinnumbers in slotdef=#:#,#,# string */
2148 o_current = object;
2149 /* For this particular graphic object (component instantiation) */
2150 /* get the slot number as a string */
2151 string = o_attrib_search_slot(o_current, &o_slot_attrib);
2153 if (!string) {
2154 /* s_log_message("Did not find slot= attribute\n"); */
2155 /* not a serious error */
2156 return;
2158 slot = atoi(string);
2159 g_free(string);
2161 /* OK, now that we have the slot number, use it to get the */
2162 /* corresponding slotdef=#:#,#,# string. */
2163 slotdef = o_attrib_search_slotdef(o_current, slot);
2165 if (!slotdef) {
2166 s_log_message("Did not find slotdef=#:#,#,#... attribute\n");
2167 return;
2170 if (!strstr(slotdef, ":")) {
2171 /* Didn't find proper slotdef=#:... put warning into log */
2172 s_log_message("Improper slotdef syntax: missing \":\".\n");
2173 g_free(slotdef);
2174 return;
2177 /* skip over slotdef number */
2178 /* slotdef is in the form #:#,#,# */
2179 /* this code skips first #: */
2180 cptr = slotdef;
2181 while (*cptr != '\0' && *cptr != ':') {
2182 cptr++;
2184 cptr++; /* skip colon */
2186 if (*cptr == '\0') {
2187 s_log_message("Did not find proper slotdef=#:#,#,#... attribute\n");
2188 g_free(slotdef);
2189 return;
2192 /* loop on all pins found in slotdef= attribute */
2193 pin_counter = 1; /* internal pin_counter */
2194 /* get current pinnumber= from slotdef= attrib */
2195 current_pin = strtok(cptr, DELIMITERS);
2196 while(current_pin != NULL) {
2197 /* get pin on this component with pinseq == pin_counter */
2198 o_pin_object = o_attrib_search_pinseq(o_current->complex->prim_objs,
2199 pin_counter);
2201 if (o_pin_object) {
2202 /* Now rename pinnumber= attrib on this part with value found */
2203 /* in slotdef attribute */
2204 string = o_attrib_search_name_single(o_pin_object, "pinnumber",
2205 &o_pinnum_object);
2207 if (string && o_pinnum_object && o_pinnum_object->type == OBJ_TEXT &&
2208 o_pinnum_object->text->string) {
2209 g_free(o_pinnum_object->text->string);
2211 /* 9 is the size of one number plus null character */
2212 o_pinnum_object->text->string = (char *)
2213 g_malloc(sizeof(char)*(strlen("pinnumber=")+strlen(current_pin)+9));
2215 /* removed _int from current_pin */
2216 sprintf(o_pinnum_object->text->string, "pinnumber=%s", current_pin);
2218 o_text_recreate(w_current, o_pinnum_object);
2220 if (string) {
2221 g_free(string);
2225 /* Now update pinseq= attrib on this part. */
2226 /* Algorithm:
2227 * 1. Get pointer to pinseq= attrib (graphic object) on this part.
2228 * 2. Verify it has a pinseq= string attached.
2229 * 3. free pinseq string.
2230 * 4. figure out how many pins are on this part.
2231 * 5. Write new string pinseq=(slot * (number of pins-1)) + pin_counter
2232 * into pinseq= object.
2234 string = o_attrib_search_name_single(o_pin_object, "pinseq",
2235 &o_pinseq_object);
2237 if (string && o_pinseq_object && o_pinseq_object->type == OBJ_TEXT &&
2238 o_pinseq_object->text->string) {
2239 g_free(o_pinseq_object->text->string); /* free old pinseq text */
2241 /* I need to check that the return is non-zero! */
2242 numpins = o_complex_count_pins(o_current);
2244 #if DEBUG
2245 printf("libgeda:o_attrib.c:o_attrib_slot_update -- name = %s\n", o_current->name);
2246 printf(" numpins = %d\n", numpins);
2247 #endif
2249 /* Now put new pinseq attrib onto pin. */
2250 new_pinseq = g_malloc(sizeof(char)*((numpins-1)*slot)+pin_counter);
2251 sprintf(new_pinseq, "%d", numpins*(slot-1)+pin_counter);
2252 /* Add 1 for EOL char */
2253 o_pinseq_object->text->string = (char *)
2254 g_malloc(sizeof(char)*(strlen("pinseq=") +
2255 strlen(new_pinseq) +1 ));
2257 sprintf(o_pinseq_object->text->string, "pinseq=%s", new_pinseq);
2258 g_free(new_pinseq);
2259 #if DEBUG
2260 printf("libgeda:o_attrib.c:o_attrib_slot_update -- ");
2261 printf("new_pinseq attrib = %s \n", o_pinseq_object->text->string);
2262 #endif
2264 o_text_recreate(w_current, o_pinseq_object);
2266 if (string) {
2267 g_free(string);
2270 pin_counter++;
2271 } else {
2272 s_log_message("component missing pinseq= attribute\n");
2275 current_pin = strtok(NULL, DELIMITERS);
2278 g_free(slotdef);
2281 /*! \brief Copy attributes from OBJECT to OBJECT.
2282 * \par Function Description
2283 * This function will perform a slot copy of the <B>original</B> OBJECT
2284 * to the <B>target</B> OBJECT.
2286 * \param [in] w_current The TOPLEVEL object.
2287 * \param [in] original The original OBJECT to slot copy from.
2288 * \param [out] target The target OBJECT to slot copy to.
2290 void o_attrib_slot_copy(TOPLEVEL *w_current, OBJECT *original, OBJECT *target)
2293 OBJECT *o_current;
2294 OBJECT *o_slot_attrib;
2295 OBJECT *o_pin_object;
2296 OBJECT *o_pinnum_object;
2297 char *string;
2298 char *slotdef;
2299 int slot;
2300 int pin_counter;
2301 char* current_pin;
2302 char* cptr;
2304 o_current = original;
2306 string = o_attrib_search_slot(o_current, &o_slot_attrib);
2308 if (!string) {
2309 /* s_log_message("Did not find slot= attribute\n"); */
2310 /* not a serious error */
2311 return;
2313 slot = atoi(string);
2314 g_free(string);
2316 slotdef = o_attrib_search_slotdef(o_current, slot);
2318 if (!slotdef) {
2319 s_log_message("Did not find slotdef=#:#,#,#... attribute\n");
2320 return;
2323 if (!strstr(slotdef, ":")) {
2324 /*! \todo didn't proper slotdef=#:... TODO into log*/
2325 return;
2328 /* skip over slotdef number */
2329 /* slotdef is in the form #:#,#,# */
2330 /* this code skips first #: */
2331 cptr = slotdef;
2332 while (*cptr != '\0' && *cptr != ':') {
2333 cptr++;
2335 cptr++; /* skip colon */
2337 if (*cptr == '\0') {
2338 s_log_message("Did not find proper slotdef=#:#,#,#... attribute\n");
2339 return;
2342 pin_counter = 1;
2343 current_pin = strtok(cptr, DELIMITERS);
2344 while(current_pin != NULL) {
2346 o_pin_object = o_attrib_search_pinseq(target->complex->prim_objs,
2347 pin_counter);
2349 if (o_pin_object) {
2351 string = o_attrib_search_name_single(o_pin_object, "pinnumber",
2352 &o_pinnum_object);
2354 if (string && o_pinnum_object && o_pinnum_object->type == OBJ_TEXT &&
2355 o_pinnum_object->text->string) {
2357 g_free(string);
2358 g_free(o_pinnum_object->text->string);
2360 /* 9 is the size of one number plus null character */
2361 o_pinnum_object->text->string = (char *)
2362 g_malloc(sizeof(char)*(strlen("pinnumber=")+strlen(current_pin)+9));
2364 /* removed _int from current_pin */
2365 sprintf(o_pinnum_object->text->string, "pinnumber=%s", current_pin);
2367 o_text_recreate(w_current, o_pinnum_object);
2370 pin_counter++;
2371 } else {
2372 s_log_message("component missing pinseq= attribute\n");
2375 current_pin = strtok(NULL, DELIMITERS);
2378 g_free(slotdef);
2381 /*! \brief Get the number of TOPLEVEL attributes in all loaded pages.
2382 * \par Function Description
2383 * This function will return the number of TOPLEVEL attributes
2384 * in all loaded pages.
2386 * \param [in] w_current The TOPLEVEL object to search.
2387 * \param [in] name Attribute name to search for.
2388 * \return Count of TOPLEVEL attributes in all loaded pages.
2390 /* returns the number of toplevel attributes in all loaded pages */
2391 int o_attrib_count_toplevel(TOPLEVEL *w_current, char *name)
2393 int ret_value=0;
2394 int counter=0;
2395 PAGE *p_current;
2396 char *string;
2398 p_current = w_current->page_head;
2400 while(p_current != NULL) {
2402 counter = 0;
2403 string = o_attrib_search_name(p_current->object_head,
2404 name, counter);
2405 printf("%s %d\n", name, counter);
2406 while(string) {
2407 printf("inside\n");
2408 ret_value++;
2409 g_free(string);
2410 string=NULL;
2411 counter++;
2413 string = o_attrib_search_name(p_current->object_head,
2414 name, counter);
2417 p_current=p_current->next;
2419 return(ret_value);
2422 /*! \brief Search for first TOPLEVEL attribute.
2423 * \par Function Description
2424 * This function searches all loaded pages for the first
2425 * TOPLEVEL attribute found.
2426 * The caller is responsible for freeing the returned value.
2427 * See #o_attrib_search_toplevel() for other comments.
2429 * \param [in] page_head PAGE head object to search through.
2430 * \param [in] name Character string name to search for.
2431 * \return Character string from the found attribute, NULL otherwise.
2433 char *o_attrib_search_toplevel_all(PAGE *page_head, char *name)
2435 PAGE *p_current;
2436 char *ret_value=NULL;
2438 p_current = page_head;
2440 while (p_current != NULL) {
2443 /* don't look into the head of page_head */
2444 if (p_current->pid != -1) {
2446 /* only look for first occurrance of the attribute */
2447 ret_value = o_attrib_search_toplevel(
2448 p_current->object_head,
2449 name, 0);
2452 if (ret_value != NULL) {
2453 return(ret_value);
2456 p_current = p_current->next;
2459 return(NULL);
2462 /*! \brief Get all attached attributes to specified OBJECT.
2463 * \par Function Description
2464 * This function returns all attached attribute objects to the
2465 * specified object.
2466 * The returned list is an array of objects and should be freed using the
2467 * #o_attrib_free_returned() function.
2468 * This function will only look for attached attributes and not
2469 * unattached free floating attribs.
2471 * \param [in] object_list OBJECT list to search.
2472 * \param [in] sel_object OBJECT to search for.
2473 * \return An array of objects that matched sel_object, NULL otherwise.
2475 OBJECT ** o_attrib_return_attribs(OBJECT *object_list, OBJECT *sel_object)
2477 OBJECT **found_objects;
2478 int num_attribs=0;
2479 int i=0;
2480 ATTRIB *a_current;
2481 OBJECT *o_current;
2482 OBJECT *object;
2484 object = (OBJECT *) o_list_search(object_list, sel_object);
2486 if (!object) {
2487 return(NULL);
2490 if (!object->attribs) {
2491 return(NULL);
2494 if (!object->attribs->next) {
2495 return(NULL);
2499 /* first go through and count the number of attribs */
2500 a_current = object->attribs->next;
2501 while(a_current != NULL) {
2502 num_attribs++;
2503 a_current = a_current->next;
2506 found_objects = (OBJECT **) g_malloc(sizeof(OBJECT *)*(num_attribs+1));
2508 /* now actually fill the array of objects */
2509 a_current = object->attribs->next;
2510 while(a_current != NULL) {
2511 if (a_current->object != NULL) {
2512 o_current = a_current->object;
2513 if (o_current->type == OBJ_TEXT &&
2514 o_current->text->string) {
2515 found_objects[i] = o_current;
2516 i++;
2519 a_current = a_current->next;
2522 found_objects[i] = NULL;
2524 #if DEBUG
2525 i=0;
2526 while(found_objects[i] != NULL) {
2527 /*for (i = 0 ; i < num_attribs; i++) {*/
2528 printf("%d : %s\n", i, found_objects[i]->text->string);
2529 i++;
2531 #endif
2533 return(found_objects);
2536 /*! \brief Free attached attribute list.
2537 * \par Function Description
2538 * Free attached attribute list. Use only on a list created
2539 * by #o_attrib_return_attribs().
2541 * \param [in] found_objects List returned by #o_attrib_return_attribs().
2543 void o_attrib_free_returned(OBJECT **found_objects)
2545 int i=0;
2547 if (!found_objects) {
2548 return;
2551 /* don't free the insides of found_objects, since the contents are */
2552 /* just pointers into the real object list */
2553 while(found_objects[i] != NULL) {
2554 found_objects[i] = NULL;
2555 i++;
2558 g_free(found_objects);