Print the desired object's description.
[geda-gaf/berndj.git] / gattrib / src / s_toplevel.c
blobbf24266d83bddad2539c8ae4c0f176df48322933
1 /* gEDA - GPL Electronic Design Automation
2 * gattrib -- gEDA component and net attribute manipulation using spreadsheet.
3 * Copyright (C) 2003 -- 2006-2007 Stuart D. Brorson.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 /*------------------------------------------------------------------
21 * This file holds fcns involved in manipulating the TOPLEVEL data
22 * structure. TOPLEVEL is the data structure inherited from gEDA's
23 * other programs, and holds all info about a project in a form
24 * native to gEDA.
25 *------------------------------------------------------------------*/
27 #include <config.h>
29 #include <stdio.h>
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #endif
33 #include <math.h>
35 /*------------------------------------------------------------------
36 * Gattrib specific includes
37 *------------------------------------------------------------------*/
38 #include <libgeda/libgeda.h> /* geda library fcns */
39 #include "../include/struct.h" /* typedef and struct declarations */
40 #include "../include/prototype.h" /* function prototypes */
41 #include "../include/globals.h"
43 #ifdef HAVE_LIBDMALLOC
44 #include <dmalloc.h>
45 #endif
48 /* =================== Public Functions ====================== */
51 /*! \brief Reads in a page & calls f_open, which fills out the
52 * pr_current structure.
54 * \param [in] filename file to be opened
55 * \returns 1 on success, 0 on failure
57 int s_toplevel_read_page(char *filename)
59 int file_return_code;
60 GError *err = NULL;
62 /* Set the new filename */
63 pr_current->page_current->page_filename = g_strdup(filename);
65 /* read in and fill out pr_current using f_open and its callees */
66 file_return_code = f_open(pr_current, pr_current->page_current,
67 filename, &err);
69 /* If an error occurred, print message */
70 if (err != NULL) {
71 g_warning ("%s", err->message);
72 g_error_free (err);
75 return file_return_code;
78 static enum visit_result
79 notice_placeholder_one(OBJECT *o_current, void *userdata)
81 int *missing_sym_flag = userdata;
83 /* --- look for object, and verify that it has a symbol file attached. ---- */
84 if (o_current->type == OBJ_PLACEHOLDER) {
85 *missing_sym_flag = 1; /* flag to signal that problem exists. */
88 return VISIT_RES_OK;
91 /*! \brief This function loops through all components in the
92 * design looking for components which are placeholders.
94 * Placeholders are inserted into the object list when
95 * no symbol file is found. If this function finds a
96 * placeholder, it warns the user.
98 * \param [in] toplevel a toplevel object
100 void s_toplevel_verify_design(TOPLEVEL *toplevel)
102 int missing_sym_flag = 0;
104 s_visit_toplevel(toplevel, &notice_placeholder_one, &missing_sym_flag,
105 VISIT_ANY, 1);
107 if (missing_sym_flag) {
108 x_dialog_missing_sym(); /* dialog gives user option to quit */
112 /*------------------------------------------------------------------
113 * This fcn is called when the user invokes "save". It first
114 * places all data from gtksheet into SHEET_DATA. Then it
115 * loops through all pages & calls s_toplevel_sheetdata_to_toplevel to place all
116 * stuff in SHEET_DATA into the libgeda TOPLEVEL structure.
117 *------------------------------------------------------------------*/
118 void
119 s_toplevel_gtksheet_to_toplevel()
121 GList *iter;
122 PAGE *p_current;
124 if (GEDA_DEBUG) {
125 printf("--------------------- Entering s_toplevel_gtksheet_to_toplevel -------------------\n");
128 s_sheet_data_gtksheet_to_sheetdata(); /* read data from gtksheet into SHEET_DATA */
129 if (GEDA_DEBUG) {
130 printf("In s_toplevel_gtksheet_to_toplevel -- done writing stuff from gtksheet into SHEET_DATA.\n");
133 /* must iterate over all pages in design */
134 for ( iter = geda_list_get_glist( pr_current->pages );
135 iter != NULL;
136 iter = g_list_next( iter ) ) {
138 p_current = (PAGE *)iter->data;
139 /* only traverse pages which are toplevel */
140 if (p_current->object_head && p_current->page_control == 0) {
141 s_toplevel_sheetdata_to_toplevel(sheet_head, p_current); /* adds all objects from page */
145 if (GEDA_DEBUG) {
146 printf("In s_toplevel_gtksheet_to_toplevel -- done writing SHEEET_DATA text back into pr_currnet.\n");
151 /*------------------------------------------------------------------
152 * This fcn gets called when the user has entered a new attrib name,
153 * and clicked the OK button. It does this:
154 * 1. It figures out which attrib/sheet is being added to
155 * 2. It destroys the old table in preparation for the new attrib.
156 * 3. It adds the new attrib to the master lists.
157 * 4. It creates a new table with the new attrib.
158 * 5. It then adds the appropriate col to the gtksheet.
159 *------------------------------------------------------------------*/
160 void s_toplevel_add_new_attrib(gchar *new_attrib_name) {
161 gint cur_page; /* current page in notebook */
162 gint old_comp_attrib_count;
164 if (strcmp(new_attrib_name, "_cancel") == 0) {
165 return; /* user pressed cancel or closed window with no value in entry */
168 /* Next must figure out which sheet the attrib belongs to. */
169 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(main_notebook));
170 if (GEDA_DEBUG) {
171 printf("In s_toplevel_add_new_attrib, adding new attrib to page %d.\n",
172 cur_page);
175 switch (cur_page) {
176 case 0: /* component attribute */
178 /* Eventually, I want to just resize the table to accommodate the
179 * new attrib. However, that is difficult. Therefore, I will just
180 * destroy the old table and recreate it for now. */
183 s_table_destroy(sheet_head->component_table,
184 sheet_head->comp_count, sheet_head->comp_attrib_count);
186 old_comp_attrib_count = sheet_head->comp_attrib_count;
187 if (GEDA_DEBUG) {
188 printf("In s_toplevel_add_new_attrib, before adding new comp attrib.\n");
189 printf(" comp_attrib_count = %d\n", old_comp_attrib_count);
192 s_string_list_add_item(sheet_head->master_comp_attrib_list_head,
193 &(sheet_head->comp_attrib_count),
194 new_attrib_name);
195 s_string_list_sort_master_comp_attrib_list();
197 if (GEDA_DEBUG) {
198 printf("In s_toplevel_add_new_attrib, just updated comp_attrib string list.\n");
199 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
202 /* Now create new table */
203 /* sheet_head->component_table = s_table_new(sheet_head->comp_count,
204 sheet_head->comp_attrib_count);
207 /* resize table to accommodate new attrib col */
208 sheet_head->component_table =
209 s_table_resize(sheet_head->component_table,
210 sheet_head->comp_count,
211 old_comp_attrib_count, sheet_head->comp_attrib_count);
213 if (GEDA_DEBUG) {
214 printf("In s_toplevel_add_new_attrib, just resized component table.\n");
217 /* Fill out new sheet with new stuff from gtksheet */
218 gtk_sheet_insert_columns(GTK_SHEET(sheets[0]), sheet_head->comp_attrib_count, 1);
219 x_gtksheet_add_col_labels(GTK_SHEET(sheets[0]),
220 sheet_head->comp_attrib_count,
221 sheet_head->master_comp_attrib_list_head);
223 if (GEDA_DEBUG) {
224 printf("In s_toplevel_add_new_attrib, just updated gtksheet.\n");
227 break;
229 case 1: /* net attribute */
230 /* insert into net attribute list */
231 break;
233 case 2: /* pin attribute */
234 /* insert into pin attribute list */
235 break;
236 } /* switch */
240 /*------------------------------------------------------------------
241 * This fcn gets called when the user has selected a single attrib
242 * column, selected the edit->delete attrib item from the pull-down
243 * menu, and then said "yes" to the confirm dialog.
244 *------------------------------------------------------------------*/
245 void s_toplevel_delete_attrib_col() {
246 gint cur_page; /* current page in notebook */
247 gint mincol, maxcol;
248 GtkSheet *sheet;
249 gchar *attrib_name;
251 /* Repeat previous checks */
252 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(main_notebook));
253 sheet = GTK_SHEET(sheets[cur_page]);
254 if (sheet == NULL) {
255 return;
257 mincol = x_gtksheet_get_min_col(sheet);
258 maxcol = x_gtksheet_get_max_col(sheet);
259 if ( (mincol != maxcol) || (mincol == -1) || (maxcol == -1) ) {
260 return;
263 if (GEDA_DEBUG) {
264 printf("In s_toplevel_delete_attrib_col, checks were OK, now do real work\n");
267 /* Rebuild the gattrib-specific data structures */
268 switch (cur_page) {
270 case 0: /* component attribute */
272 /* Eventually, I want to just resize the table after deleting the
273 * attrib. However, that is difficult. Therefore, I will just
274 * destroy the old table and recreate it for now. */
276 s_table_destroy(sheet_head->component_table,
277 sheet_head->comp_count, sheet_head->comp_attrib_count);
279 /* Get name (label) of the col to delete from the gtk sheet */
280 attrib_name = g_strdup( gtk_sheet_column_button_get_label(sheet, mincol) );
282 if (attrib_name != NULL) {
283 if (GEDA_DEBUG) {
284 printf("In s_toplevel_delete_attrib_col, attrib to delete = %s\n", attrib_name);
286 } else {
287 fprintf(stderr, "In s_toplevel_delete_attrib_col, can't get attrib name\n");
288 return;
291 if (GEDA_DEBUG) {
292 printf("In s_toplevel_delete_attrib_col, before deleting comp attrib.\n");
293 printf(" comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
295 s_string_list_delete_item(&(sheet_head->master_comp_attrib_list_head),
296 &(sheet_head->comp_attrib_count),
297 attrib_name);
298 s_string_list_sort_master_comp_attrib_list(); /* this renumbers list also */
299 g_free(attrib_name);
301 if (GEDA_DEBUG) {
302 printf("In s_toplevel_delete_attrib_col, just updated comp_attrib string list.\n");
303 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
306 /* Now create new table with new attrib count*/
307 sheet_head->component_table = s_table_new(sheet_head->comp_count,
308 sheet_head->comp_attrib_count);
311 if (GEDA_DEBUG) {
312 printf("In s_toplevel_delete_attrib_col, just updated SHEET_DATA info.\n");
314 break;
316 case 1: /* net attribute */
317 /* insert into net attribute list */
318 break;
320 case 2: /* pin attribute */
321 /* insert into pin attribute list */
322 break;
323 } /* switch */
326 /* Delete col on gtksheet */
327 if (GEDA_DEBUG) {
328 printf("In s_toplevel_delete_attrib_col, about to delete col in gtksheet.\n");
330 gtk_sheet_delete_columns (sheet, mincol, 1);
331 if (GEDA_DEBUG) {
332 printf("In s_toplevel_delete_attrib_col, done deleting col in gtksheet.\n");
335 sheet_head->CHANGED = TRUE; /* Set changed flag so user is prompted when exiting */
338 /* ======================= Private fcns ====================== */
340 static enum visit_result
341 update_component_one(OBJECT *o_current, void *userdata)
343 SHEET_DATA *sheet = userdata;
344 char *temp_uref;
345 STRING_LIST *new_comp_attrib_pair_list;
347 /* ------- Object is a component. Handle component attributes. ------- */
348 if (o_current->type == OBJ_COMPLEX) { /* Note that OBJ_COMPLEX = component + attribs */
349 #if 0
350 if ( o_attrib_search_component(o_current, "graphical") ) {
351 return; /* Ignore graphical components */
353 #endif
355 temp_uref = s_attrib_get_refdes(o_current);
356 if (temp_uref != NULL) {
357 /* Must create a name=value pair list for each particular component
358 * which we can pass to fcn updating o_current. This fcn places all attribs
359 * found in the row into new_comp_attrib_pair_list. */
360 new_comp_attrib_pair_list = s_table_create_attrib_pair(temp_uref,
361 sheet->component_table,
362 sheet->master_comp_list_head,
363 sheet->comp_attrib_count);
365 /* Now update attribs in toplevel using this list. */
366 s_toplevel_update_component_attribs_in_toplevel(o_current,
367 new_comp_attrib_pair_list);
369 g_free(temp_uref);
370 } else {
371 if (GEDA_DEBUG) {
372 printf("In s_toplevel_sheetdata_to_toplevel, found complex with no refdes. name = %s\n",
373 o_current->name);
376 } /* if (o_current->type == OBJ_COMPLEX) */
378 return VISIT_RES_OK;
381 static enum visit_result
382 update_pin_one_pin(OBJECT *comp_prim_obj, void *userdata)
384 char *temp_uref = userdata;
385 STRING_LIST *new_pin_attrib_list;
387 if (comp_prim_obj->type == OBJ_PIN) {
388 new_pin_attrib_list = s_toplevel_get_pin_attribs_in_sheet(temp_uref, comp_prim_obj);
389 s_toplevel_update_pin_attribs_in_toplevel(temp_uref, comp_prim_obj, new_pin_attrib_list);
392 return VISIT_RES_OK;
395 static enum visit_result
396 update_pin_one_component(OBJECT *o_current, void *userdata)
398 char *temp_uref;
400 /* ------- Object is a complex. Handle pins by looking ------ */
401 /* ------- for all pins attached to a component. ------ */
402 if (o_current->type == OBJ_COMPLEX) {
403 /* Upon finding a component, here's what to do:
404 * 0. Get refdes of component.
405 * 1. Loop over prim_objects, looking for pins.
406 * 2. When a pin is found, create refdes:pinnumber pair
407 * used in searching TABLE.
408 * 3. Search TABLE using refdes:pinnumber as key, and get list of
409 * attribs corresponding to this refdes:pinnumber
410 * 4. Stick the attribs into the TOPLEVEL data structure.
412 temp_uref = s_attrib_get_refdes(o_current);
413 if (temp_uref != NULL) { /* make sure object complex has a refdes */
414 s_visit_object(o_current, &update_pin_one_pin, temp_uref,
415 VISIT_DETERMINISTIC, 1);
416 } /* if(temp_uref */
418 g_free(temp_uref);
421 return VISIT_RES_OK;
424 /*------------------------------------------------------------------
425 * This fcn
426 * loops through all objects on (PAGE page)->(OBJECT *start_obj).
427 * It takes the updated SHEET_DATA->TABLE data and then updates the
428 * objects with the new attribs & attrib values.
429 * For each component, it updates the attached
430 * attrib values using the updated values held in the SHEET_DATA->TABLE
431 * structure. It does so in three steps:
432 * 1. First find and update component attribs.
433 * 2. Then find and update net attribs.
434 * 3. Finally find and update pin attribs.
435 *------------------------------------------------------------------*/
436 void
437 s_toplevel_sheetdata_to_toplevel(SHEET_DATA *sheet, PAGE *page)
439 /* ----- First deal with all components on the page. ----- */
440 if (GEDA_DEBUG) {
441 printf("----- In s_toplevel_sheetdata_to_toplevel, handling components\n");
443 s_visit_page(page, &update_component_one, sheet, VISIT_ANY, 1);
445 #if 0
446 /* ----- Next deal with all nets on the page. ----- */
447 /* This is TBD */
449 #endif
452 /* ----- Finally deal with all pins on the page. ----- */
453 /* ----- Next deal with all nets on the page. ----- */
454 if (GEDA_DEBUG) {
455 printf("----- In s_toplevel_sheetdata_to_toplevel, handling pins\n");
457 /* XXX This is suspect; there's no convention for persisting pin attribs. */
458 s_visit_page(page, &update_pin_one_component, NULL, VISIT_ANY, 1);
462 /*------------------------------------------------------------------
463 * This fcn returns a list of attributes attached to obj_name = comp
464 * refdes or netlist. The returned list is a STRING_LIST where the
465 * ->data holds a name=value string.
466 *------------------------------------------------------------------*/
467 STRING_LIST *s_toplevel_get_component_attribs_in_sheet(char *refdes)
469 STRING_LIST *new_attrib_list;
470 STRING_LIST *local_attrib_list;
471 int i;
472 int row = -1;
473 int count = 0;
474 char *name_value_pair;
475 char *new_attrib_value;
476 char *new_attrib_name;
478 if (GEDA_DEBUG) {
479 printf("----- Entering s_toplevel_get_component_attribs_in_sheet.\n");
483 /* First find pos of this refdes in the master list */
484 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
486 /* Sanity check */
487 if (row == -1) {
488 /* we didn't find the item in the list */
489 fprintf(stderr,
490 "In s_toplevel_get_component_attribs_in_sheet, we didn't find the refdes in the master list!\n");
491 return NULL;
494 /* Now get all attribs associated with this refdes (in TABLE, indexed
495 * by position), and insert them into new_attrib_list. */
496 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
498 i = 0;
499 local_attrib_list = sheet_head->master_comp_attrib_list_head;
500 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
501 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
503 if ( ((sheet_head->component_table)[row][i]).attrib_value ) {
504 new_attrib_value = g_strdup( ((sheet_head->component_table)[row][i]).attrib_value );
505 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
506 g_free(new_attrib_value);
507 } else {
508 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
510 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
511 g_free(new_attrib_name);
512 g_free(name_value_pair);
514 /* Sanity check */
515 if (count != i+1) {
516 /* for some reason, we have lost a name_value_pair somewhere . . . */
517 fprintf(stderr,
518 "In s_toplevel_get_component_attribs_in_sheet, count != i! Exiting . . . .\n");
519 exit(-1);
522 /* iterate */
523 i++;
524 local_attrib_list = local_attrib_list->next;
525 } /* while (local_attrib_list != NULL) */
527 return new_attrib_list;
532 /*------------------------------------------------------------------
533 * For each attrib string attached to the component, update it using the value
534 * held in new_comp_attrib_list. Algorithm:
535 * 1. Form list of all component attribs held on both the component
536 * (o_current), as well as in the attrib list (SHEET_DATA).
537 * 2. Loop over name=value pairs held in complete_comp_attrib_list.
538 * 3. For each name=value pair, look for corresponding attrib on o_current.
539 * 4. For each name=value pair, look for the corresponding attrib in
540 * new_comp_attrib_list.
541 * 5. If the attrib exists on o_current and in new_comp_attrib_list, write the
542 * new value (from new_comp_attrib_list) into o_current.
543 * 6. If the attrib exists on o_current, but is null in name=value pair,
544 * delete the attrib from o_current.
545 * 7. If the attribs doesn't exist on o_current, but is non-null in
546 * the name=value pair, create an attrib object and add it to the part
547 * on o_current.
549 * Calling args: OBJECT *o_current -- component (complex) to be updated.
550 * STRING_LIST *new_comp... -- list of name=value attribute pairs
551 * from SHEET_DATA.
552 * Returns: Returns nothing because the changes are made in o_current, which
553 * is part of the global TOPLEVEL pr_current.
554 *------------------------------------------------------------------*/
555 void s_toplevel_update_component_attribs_in_toplevel(OBJECT *o_current,
556 STRING_LIST *new_comp_attrib_list)
558 STRING_LIST *local_list;
559 STRING_LIST *complete_comp_attrib_list;
560 char const *old_name_value_pair;
561 char *new_attrib_name;
562 char *new_attrib_value;
563 char *old_attrib_name;
564 char *old_attrib_value;
565 gchar *refdes;
566 GList *a_iter;
567 OBJECT *a_current;
568 int count = 0; /* This is to fake out a fcn called later */
569 gint row, col;
570 gint visibility = 0;
571 gint show_name_value = 0;
573 if (GEDA_DEBUG) {
574 printf("----- Entering s_toplevel_update_component_attribs_in_toplevel.\n");
578 * To remove dead attribs from o_current, we need to form a complete list of unique
579 * attribs by taking the union of the new attribs from the SHEET_DATA, and
580 * the old attribs living on o_current. That's what we're doing here.
581 * Later, we can delete those attribs in o_current which don't appear in
582 * new_comp_attrib_list.
584 /* First duplicate new_comp_attrib_list */
585 complete_comp_attrib_list = s_string_list_duplicate_string_list(new_comp_attrib_list);
587 /* Now create a complete list of unique attribute names. This will be used in
588 * the loop below when updating attributes. */
589 a_iter = o_current->attribs;
590 while (a_iter != NULL) {
591 a_current = a_iter->data;
592 if (a_current->type == OBJ_TEXT
593 && a_current->text != NULL) { /* found a name=value attribute pair. */
594 /* may need to check more thoroughly here. . . . */
595 old_name_value_pair = o_text_get_string(a_current);
597 /* Else clause is suggestion from Ales */
598 #if 1
599 old_attrib_name = u_basic_breakup_string(old_name_value_pair, '=', 0);
600 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
601 (strcmp(old_attrib_name, "net") != 0) &&
602 (strcmp(old_attrib_name, "slot") != 0) &&
603 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
604 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
606 #else
607 /* might not compile now, but this #if'd out branch isn't being built */
608 gint status;
609 status = o_attrib_get_name_value(old_name_value_pair, &old_attrib_name, &old_attrib_value);
610 if (status == 0) {
611 /* Don't put "refdes" or "slot" into list. Don't put old name=value pair into list if a new
612 * one is already in there. */
613 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
614 (strcmp(old_attrib_name, "net") != 0) &&
615 (strcmp(old_attrib_name, "slot") != 0) &&
616 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
617 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
619 g_free (old_attrib_name);
620 g_free (old_attrib_value);
622 #endif
623 g_free(old_attrib_name);
625 a_iter = g_list_next (a_iter);
626 } /* while (a_current != NULL) */
630 *Now the main business of this fcn: updating the attribs attached to this o_current.
631 * Loop on name=value pairs held in complete_comp_attrib_list , and then use this to get the
632 * name=value pairs out of new_comp_attrib_list and from o_current.
635 /* First handle a special case: the component has no attribs (beside refdes). */
636 if (complete_comp_attrib_list->data == NULL)
637 return;
639 /* Now the normal case. . . . */
640 local_list = complete_comp_attrib_list;
641 while (local_list != NULL) {
642 if (GEDA_DEBUG) {
643 printf("\n\n");
644 printf(" In s_toplevel_update_component_attribs_in_toplevel, handling entry in complete list %s .\n",
645 local_list->data);
648 /* Now get the old attrib name & value from complete_comp_attrib_list
649 * and value from o_current */
650 old_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
651 old_attrib_value = o_attrib_search_name_single_count(o_current, old_attrib_name, 0);
653 if (GEDA_DEBUG) {
654 printf(" In s_toplevel_update_component_attribs_in_toplevel, old name = \"%s\" .\n",
655 old_attrib_name);
656 printf(" In s_toplevel_update_component_attribs_in_toplevel, old value = \"%s\" .\n",
657 old_attrib_value);
660 /* Next try to get this attrib from new_comp_attrib_list */
661 new_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
662 if (s_string_list_in_list(new_comp_attrib_list, local_list->data)) {
663 new_attrib_value = s_misc_remaining_string(local_list->data, '=', 1);
664 } else {
665 new_attrib_value = NULL;
667 if (GEDA_DEBUG) {
668 printf(" In s_toplevel_update_component_attribs_in_toplevel, new name = \"%s\" .\n",
669 new_attrib_name);
670 printf(" In s_toplevel_update_component_attribs_in_toplevel, new value = \"%s\" .\n",
671 new_attrib_value);
674 /* Now get row and col where this new attrib lives. Then get
675 * visibility of the new attrib stored in the component table */
676 /* We'll need this later */
677 refdes = g_strdup(s_attrib_get_refdes(o_current));
678 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
679 col = s_table_get_index(sheet_head->master_comp_attrib_list_head, new_attrib_name);
680 /* if attribute has been deleted from the sheet, here is where we detect that */
681 if ( (row == -1) || (col == -1) ) {
682 new_attrib_value = NULL; /* attrib will be deleted below */
683 } else { /* we need a better place to get this info since the TABLE can be out of date */
684 visibility = sheet_head->component_table[row][col].visibility;
685 show_name_value = sheet_head->component_table[row][col].show_name_value;
687 g_free(refdes);
690 /* ------- Four cases to consider: Case 1 ----- */
691 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
692 /* simply write new attrib into place of old one. */
693 if (GEDA_DEBUG) {
694 printf(" -- In s_toplevel_update_component_attribs_in_toplevel,\n");
695 printf(" about to replace old attrib with name= %s, value= %s\n",
696 new_attrib_name, new_attrib_value);
697 printf(" visibility = %d, show_name_value = %d.\n",
698 visibility, show_name_value);
700 s_object_replace_attrib_in_object(o_current,
701 new_attrib_name,
702 new_attrib_value,
703 visibility,
704 show_name_value);
707 /* ------- Four cases to consider: Case 2 ----- */
708 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
709 /* remove attrib from component*/
710 if (GEDA_DEBUG) {
711 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
712 old_attrib_name, old_attrib_value);
714 s_object_remove_attrib_in_object(o_current, old_attrib_name);
717 /* ------- Four cases to consider: Case 3 ----- */
718 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
719 /* add new attrib to component. */
720 if (GEDA_DEBUG) {
721 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
722 new_attrib_name, new_attrib_value);
725 s_object_add_comp_attrib_to_object(o_current,
726 new_attrib_name,
727 new_attrib_value,
728 visibility,
729 show_name_value);
731 /* ------- Four cases to consider: Case 4 ----- */
732 } else {
733 /* Do nothing. */
734 if (GEDA_DEBUG) {
735 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, nothing needs to be done.\n");
739 /* Toggle attribute visibility and name/value setting */
741 /* free everything and iterate */
742 g_free(new_attrib_name);
743 g_free(new_attrib_value);
744 g_free(old_attrib_name);
745 g_free(old_attrib_value);
746 local_list = local_list->next;
747 } /* while (local_list != NULL) */
750 /*------------------------------------------------------------------
751 * This fcn takes a pointer to the OBJECT pin, and returns a list
752 * of attribs found attached to the pin. The returned list is a
753 * STRING_LIST where the ->data holds a name=value string.
754 * The algorithm is as follows:
755 * 1. Form refdes:pinnumber label for this pin.
756 * 2. Get row number of this refdes:pinnumber
757 * 3. Create a list of name=value pairs from entries in the pin_table
758 * on this row.
759 * 4. Return list of name=value pairs found.
760 *------------------------------------------------------------------*/
761 STRING_LIST *s_toplevel_get_pin_attribs_in_sheet(char *refdes, OBJECT *pin)
763 STRING_LIST *new_attrib_list;
764 STRING_LIST *local_attrib_list;
765 int i;
766 int row = -1;
767 int count = 0;
768 char *pinnumber;
769 char *row_label;
770 char *name_value_pair;
771 char *new_attrib_value;
772 char *new_attrib_name;
774 if (GEDA_DEBUG) {
775 printf("----- Entering s_toplevel_get_pin_attribs_in_sheet.\n");
778 /* First find pos of this pin in the master pin list */
779 /* first convert refdes, pin to refdes:pinno text string. Then call table_get_index. */
781 pinnumber = o_attrib_search_name_single(pin, "pinnumber", NULL);
783 if ( (refdes != NULL) && (pinnumber != NULL) ) {
784 row_label = g_strconcat(refdes, ":", pinnumber, NULL);
785 } else {
786 fprintf(stderr,
787 "In s_toplevel_get_pin_attribs_in_sheet, either refdes or pinnumber of object missing!\n");
788 return NULL;
790 row = s_table_get_index(sheet_head->master_pin_list_head, row_label);
792 /* Sanity check */
793 if (row == -1) {
794 /* we didn't find the item in the list */
795 fprintf(stderr,
796 "In s_toplevel_get_pin_attribs_in_sheet, we didn't find the refdes:pin in the master list!\n");
797 return NULL;
800 /* Now get all attribs associated with this refdes (in TABLE, indexed
801 * by position), and insert them into new_attrib_list. */
802 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
804 i = 0;
805 local_attrib_list = sheet_head->master_pin_attrib_list_head;
806 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
807 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
809 if ( ((sheet_head->pin_table)[row][i]).attrib_value ) {
810 new_attrib_value = g_strdup( ((sheet_head->pin_table)[row][i]).attrib_value );
811 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
812 g_free(new_attrib_value);
813 } else {
814 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
816 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
817 g_free(new_attrib_name);
818 g_free(name_value_pair);
820 /* Sanity check */
821 if (count != i+1) {
822 /* for some reason, we have lost a name_value_pair somewhere . . . */
823 fprintf(stderr,
824 "In s_toplevel_get_pin_attribs_in_sheet, count != i! Exiting . . . .\n");
825 exit(-1);
828 /* iterate */
829 i++;
830 local_attrib_list = local_attrib_list->next;
831 } /* while (local_attrib_list != NULL) */
833 return new_attrib_list;
838 /*------------------------------------------------------------------
839 * For each attrib string attached to the pin, update it using the value
840 * held in new_pin_attrib_list. Algorithm:
841 * 1. Loop over name=value pairs held in new_pin_attrib_list.
842 * 2. For each name=value pair, look for corresponding attrib on pin.
843 * 3. If the attrib exists on pin and in name=value pair, write the
844 * new value in.
845 * 4. If the attrib exists on pin, but is null in name=value pair,
846 * delete the attrib.
847 * 5. If the attribs doesn't exist on pin, but is non-null in
848 * the name=value pair, create an attrib object and add it to the pin.
849 * Returns: Returns nothing because the changes are made in o_pin, which
850 * is part of the global TOPLEVEL pr_current.
851 *------------------------------------------------------------------*/
852 void s_toplevel_update_pin_attribs_in_toplevel(char *refdes, OBJECT *o_pin,
853 STRING_LIST *new_pin_attrib_list)
855 STRING_LIST *local_list;
856 char *new_name_value_pair;
857 char *new_attrib_name;
858 char *new_attrib_value;
859 char *old_attrib_value;
861 if (GEDA_DEBUG) {
862 printf("----- Entering s_toplevel_update_pin_attribs_in_toplevel.\n");
865 /* loop on name=value pairs held in new_pin_attrib_list */
866 local_list = new_pin_attrib_list;
867 while (local_list != NULL) {
868 new_name_value_pair = g_strdup(local_list->data);
869 if (GEDA_DEBUG) {
870 printf(" In s_toplevel_update_pin_attribs_in_toplevel, handling entry in master list %s .\n", new_name_value_pair);
873 new_attrib_name = u_basic_breakup_string(new_name_value_pair, '=', 0);
874 new_attrib_value = u_basic_breakup_string(new_name_value_pair, '=', 1);
876 if (strlen(new_attrib_value) == 0) {
877 g_free(new_attrib_value);
878 new_attrib_value = NULL; /* s_misc_remaining_string doesn't return NULL for empty substring. */
880 old_attrib_value = o_attrib_search_name_single_count(o_pin, new_attrib_name, 0);
882 /* ------- Four cases to consider: Case 1: old and new attribs exist ----- */
883 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
884 /* simply write new attrib into place of old one. */
885 if (GEDA_DEBUG) {
886 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to replace old attrib with new one: name= %s, value= %s\n",
887 new_attrib_name, new_attrib_value);
889 s_object_replace_attrib_in_object(o_pin,
890 new_attrib_name,
891 new_attrib_value,
892 LEAVE_VISIBILITY_ALONE,
893 LEAVE_NAME_VALUE_ALONE);
896 /* ------- Four cases to consider: Case 2: old attrib exists, new one doesn't ----- */
897 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
898 /* remove attrib from pin */
899 if (GEDA_DEBUG) {
900 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
901 new_attrib_name, old_attrib_value);
903 s_object_remove_attrib_in_object(o_pin, new_attrib_name);
906 /* ------- Four cases to consider: Case 3: No old attrib, new one exists. ----- */
907 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
908 /* add new attrib to pin. */
909 if (GEDA_DEBUG) {
910 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
911 new_attrib_name, new_attrib_value);
914 s_object_add_pin_attrib_to_object(o_pin, new_attrib_name, new_attrib_value);
916 /* ------- Four cases to consider: Case 4 ----- */
917 } else {
918 /* Do nothing. */
919 if (GEDA_DEBUG) {
920 printf("In s_toplevel_update_pin_attribs_in_toplevel, nothing needs to be done.\n");
924 /* free everything and iterate */
925 g_free(new_name_value_pair);
926 g_free(new_attrib_name);
927 g_free(new_attrib_value);
928 g_free(old_attrib_value);
929 local_list = local_list->next;
930 } /* while (local_list != NULL) */