Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gattrib / src / s_toplevel.c
blobe8babd952824e831384fcb849c55cfa14a8c36ac
1 /* gEDA - GPL Electronic Design Automation
2 * gattrib -- gEDA component and net attribute manipulation using spreadsheet.
3 * Copyright (C) 2003-2010 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 /*! \file
22 * \brief Functions to manipulate the TOPLEVEL struct.
24 * This file holds functions involved in manipulating the TOPLEVEL data
25 * structure. TOPLEVEL is the data structure inherited from gEDA's
26 * other programs, and holds all info about a project in a form
27 * native to gEDA.
31 #include <config.h>
33 #include <stdio.h>
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #endif
37 #include <math.h>
39 /*------------------------------------------------------------------
40 * Gattrib specific includes
41 *------------------------------------------------------------------*/
42 #include <libgeda/libgeda.h> /* geda library functions */
43 #include "../include/struct.h" /* typdef and struct declarations */
44 #include "../include/prototype.h" /* function prototypes */
45 #include "../include/globals.h"
47 #ifdef HAVE_LIBDMALLOC
48 #include <dmalloc.h>
49 #endif
52 /* =================== Public Functions ====================== */
55 /*! \brief Read a schematic page
57 * Reads in a schematic page & calls f_open, which fills out the
58 * pr_current structure.
60 * \param filename file to be opened
61 * \returns 1 on success, 0 on failure
63 int s_toplevel_read_page(char *filename)
65 int file_return_code;
66 GError *err = NULL;
68 /* Set the new filename */
69 pr_current->page_current->page_filename = g_strdup(filename);
71 /* read in and fill out pr_current using f_open and its callees */
72 file_return_code = f_open(pr_current, filename, &err);
74 /* If an error occurred, print message */
75 if (err != NULL) {
76 g_warning ("%s", err->message);
77 g_error_free (err);
80 return file_return_code;
84 /*! \brief Verify the entire design
86 * This function loops through all components in the
87 * design looking for components which are placeholders.
89 * Placeholders are inserted into the object list when
90 * no symbol file is found. If this function finds a
91 * placeholder, it warns the user.
93 * \param pr_current pointer to the toplevel object to be verified
95 void s_toplevel_verify_design(TOPLEVEL *pr_current)
97 GList *p_iter;
98 const GList *o_iter;
100 int missing_sym_flag = 0;
102 for (p_iter = geda_list_get_glist (pr_current->pages);
103 p_iter != NULL;
104 p_iter = g_list_next (p_iter)) {
105 PAGE *p_current = p_iter->data;
107 for (o_iter = s_page_objects (p_current);
108 o_iter != NULL;
109 o_iter = g_list_next (o_iter)) {
110 OBJECT *o_current = o_iter->data;
112 /* --- look for object, and verify that it has a symbol file attached. ---- */
113 if (o_current->type == OBJ_PLACEHOLDER) {
114 missing_sym_flag = 1; /* flag to signal that problem exists. */
119 if (missing_sym_flag) {
120 x_dialog_missing_sym(); /* dialog gives user option to quit */
126 /*------------------------------------------------------------------*/
127 /*! \brief Detect empty project
129 * Test if there is data in the current project.
130 * \returns 1 if the project is empty (i.e. pr_current is
131 * not filled out yet), and 0 if the project is non-empty (i.e. there
132 * is some data in pr_current).
133 * \todo Doesn't do anything. Candidate for removal?
135 void s_toplevel_empty_project()
137 /* Nothing here yet. Is this necessary in current program
138 * architecture? */
143 /*------------------------------------------------------------------*/
144 /*! \brief Copy data from gtksheet into TOPLEVEL struct
146 * Called when the user invokes "save". It first
147 * places all data from gtksheet into SHEET_DATA. Then it
148 * loops through all pages & calls s_toplevel_sheetdata_to_toplevel()
149 * to place all
150 * stuff in SHEET_DATA into the libgeda TOPLEVEL structure.
152 void
153 s_toplevel_gtksheet_to_toplevel()
155 GList *iter;
156 PAGE *p_current;
158 #if DEBUG
159 printf("--------------------- Entering s_toplevel_gtksheet_to_toplevel -------------------\n");
160 #endif
162 s_sheet_data_gtksheet_to_sheetdata(); /* read data from gtksheet into SHEET_DATA */
163 #if DEBUG
164 printf("In s_toplevel_gtksheet_to_toplevel -- done writing stuff from gtksheet into SHEET_DATA.\n");
165 #endif
167 /* must iterate over all pages in design */
168 for ( iter = geda_list_get_glist( pr_current->pages );
169 iter != NULL;
170 iter = g_list_next( iter ) ) {
172 p_current = (PAGE *)iter->data;
173 pr_current->page_current = p_current;
174 /* only traverse pages which are toplevel */
175 if (p_current->page_control == 0) {
176 s_toplevel_sheetdata_to_toplevel (p_current); /* adds all objects from page */
180 #if DEBUG
181 printf("In s_toplevel_gtksheet_to_toplevel -- done writing SHEEET_DATA text back into pr_currnet.\n");
182 #endif
184 return;
189 /*------------------------------------------------------------------*/
190 /*! \brief Add a new attribute to the top level
192 * This function gets called when the user has entered a new attrib name,
193 * and clicked the OK button. It does this:
194 * -# It figures out which attrib/sheet is being added to
195 * -# It destroys the old table in preparation for the new attrib.
196 * -# It adds the new attrib to the master lists.
197 * -# It creates a new table with the new attrib.
198 * -# It then adds the appropriate col to the gtksheet.
199 * \param new_attrib_name attribute to be added
201 void s_toplevel_add_new_attrib(gchar *new_attrib_name) {
202 gint cur_page; /* current page in notbook */
203 gint old_comp_attrib_count;
205 if (strcmp(new_attrib_name, "_cancel") == 0) {
206 return; /* user pressed cancel or closed window with no value in entry */
209 /* Next must figure out which sheet the attrib belongs to. */
210 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
211 #ifdef DEBUG
212 printf("In s_toplevel_add_new_attrib, adding new attrib to page %d.\n",
213 cur_page);
214 #endif
216 switch (cur_page) {
217 case 0: /* component attribute */
219 /* Eventually, I want to just resize the table to accomodate the
220 * new attrib. However, that is difficult. Therefore, I will just
221 * destroy the old table and recreate it for now. */
224 s_table_destroy(sheet_head->component_table,
225 sheet_head->comp_count, sheet_head->comp_attrib_count);
227 old_comp_attrib_count = sheet_head->comp_attrib_count;
228 #ifdef DEBUG
229 printf("In s_toplevel_add_new_attrib, before adding new comp attrib.\n");
230 printf(" comp_attrib_count = %d\n", old_comp_attrib_count);
231 #endif
233 s_string_list_add_item(sheet_head->master_comp_attrib_list_head,
234 &(sheet_head->comp_attrib_count),
235 new_attrib_name);
236 s_string_list_sort_master_comp_attrib_list();
238 #ifdef DEBUG
239 printf("In s_toplevel_add_new_attrib, just updated comp_attrib string list.\n");
240 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
241 #endif
243 /* Now create new table */
244 /* sheet_head->component_table = s_table_new(sheet_head->comp_count,
245 sheet_head->comp_attrib_count);
248 /* resize table to accomodate new attrib col */
249 sheet_head->component_table =
250 s_table_resize(sheet_head->component_table,
251 sheet_head->comp_count,
252 old_comp_attrib_count, sheet_head->comp_attrib_count);
254 #ifdef DEBUG
255 printf("In s_toplevel_add_new_attrib, just resized component table.\n");
256 #endif
258 /* Fill out new sheet with new stuff from gtksheet */
259 gtk_sheet_insert_columns(GTK_SHEET(sheets[0]), sheet_head->comp_attrib_count, 1);
260 x_gtksheet_add_col_labels(GTK_SHEET(sheets[0]),
261 sheet_head->comp_attrib_count,
262 sheet_head->master_comp_attrib_list_head);
264 #ifdef DEBUG
265 printf("In s_toplevel_add_new_attrib, just updated gtksheet.\n");
266 #endif
268 break;
270 case 1: /* net attribute */
271 /* insert into net attribute list */
272 break;
274 case 2: /* pin attribute */
275 /* insert into pin attribute list */
276 break;
277 } /* switch */
279 return;
283 /*------------------------------------------------------------------*/
284 /*! \brief Delete an attribute column
286 * This function gets called when the user has selected a single attrib
287 * column, selected the edit->delete attrib item from the pull-down
288 * menu, and then said "yes" to the confirm dialog.
290 void s_toplevel_delete_attrib_col() {
291 gint cur_page; /* current page in notbook */
292 gint mincol, maxcol;
293 GtkSheet *sheet;
294 gchar *attrib_name;
296 /* Repeat previous checks */
297 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
298 sheet = GTK_SHEET(sheets[cur_page]);
299 if (sheet == NULL) {
300 return;
302 mincol = x_gtksheet_get_min_col(sheet);
303 maxcol = x_gtksheet_get_max_col(sheet);
304 if ( (mincol != maxcol) || (mincol == -1) || (maxcol == -1) ) {
305 return;
308 #ifdef DEBUG
309 printf("In s_toplevel_delete_attrib_col, checks were OK, now do real work\n");
310 #endif
312 /* Rebuild the gattrib-specific data structures */
313 switch (cur_page) {
315 case 0: /* component attribute */
317 /* Eventually, I want to just resize the table after deleting the
318 * attrib. However, that is difficult. Therefore, I will just
319 * destroy the old table and recreate it for now. */
321 s_table_destroy(sheet_head->component_table,
322 sheet_head->comp_count, sheet_head->comp_attrib_count);
324 /* Get name (label) of the col to delete from the gtk sheet */
325 attrib_name = g_strdup( gtk_sheet_column_button_get_label(sheet, mincol) );
327 if (attrib_name != NULL) {
328 #ifdef DEBUG
329 printf("In s_toplevel_delete_attrib_col, attrib to delete = %s\n", attrib_name);
330 #endif
331 } else {
332 fprintf(stderr, "In s_toplevel_delete_attrib_col, can't get attrib name\n");
333 return;
336 #ifdef DEBUG
337 printf("In s_toplevel_delete_attrib_col, before deleting comp attrib.\n");
338 printf(" comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
339 #endif
340 s_string_list_delete_item(&(sheet_head->master_comp_attrib_list_head),
341 &(sheet_head->comp_attrib_count),
342 attrib_name);
343 s_string_list_sort_master_comp_attrib_list(); /* this renumbers list also */
344 g_free(attrib_name);
346 #ifdef DEBUG
347 printf("In s_toplevel_delete_attrib_col, just updated comp_attrib string list.\n");
348 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
349 #endif
351 /* Now create new table with new attrib count*/
352 sheet_head->component_table = s_table_new(sheet_head->comp_count,
353 sheet_head->comp_attrib_count);
356 #ifdef DEBUG
357 printf("In s_toplevel_delete_attrib_col, just updated SHEET_DATA info.\n");
358 #endif
359 break;
361 case 1: /* net attribute */
362 /* insert into net attribute list */
363 break;
365 case 2: /* pin attribute */
366 /* insert into pin attribute list */
367 break;
368 } /* switch */
371 /* Delete col on gtksheet */
372 #ifdef DEBUG
373 printf("In s_toplevel_delete_attrib_col, about to delete col in gtksheet.\n");
374 #endif
375 gtk_sheet_delete_columns (sheet, mincol, 1);
376 #ifdef DEBUG
377 printf("In s_toplevel_delete_attrib_col, done deleting col in gtksheet.\n");
378 #endif
380 sheet_head->CHANGED = TRUE; /* Set changed flag so user is prompted when exiting */
382 return;
386 /*------------------------------------------------------------------*/
387 /*! \brief Select object in the top level.
389 * This function is a hack. It gives a non-NULL value to the select_func
390 * defined in globals.c for libgeda. A non-NULL value for this function
391 * makes sure that object->sel_func = 1 when the project is saved out,
392 * which keeps the objects selectable in gschem.
393 * Perhaps I should just set the variable myself when saving the
394 * project out . . . . .
395 * \todo Function is a NOP - candidate for removal?
397 void s_toplevel_select_object()
399 /* I don't know if I should do anything in here to prevent
400 * the function from being optimized away by gcc. */
404 /* ======================= Private functions ====================== */
406 /*------------------------------------------------------------------*/
407 /*! \brief Copy SHEET_DATA content to TOP_LEVEL
409 * This function
410 * loops through all objects on (PAGE page)->(OBJECT *start_obj).
411 * It takes the updated SHEET_DATA->TABLE data and then updates the
412 * objects with the new attribs & attrib values.
413 * For each component, it updates the attached
414 * attrib values using the updated values held in the SHEET_DATA->TABLE
415 * structure. It does so in three steps:
416 * -# First find and update component attribs.
417 * -# Then find and update net attribs.
418 * -# Finally find and update pin attribs.
419 * \param page schematic page to copy
421 void
422 s_toplevel_sheetdata_to_toplevel (PAGE *page)
424 GList *copy_list;
425 GList *o_iter, *prim_iter;
426 char *temp_uref;
427 STRING_LIST *new_comp_attrib_pair_list;
428 STRING_LIST *new_pin_attrib_list;
430 /* ----- First deal with all components on the page. ----- */
431 #ifdef DEBUG
432 printf("----- In s_toplevel_sheetdata_to_toplevel, handling components\n");
433 #endif
435 /* Work from a copy list, as objects can be deleted
436 * from the list during iteration over the list.
438 /* NB: g_list_copy doesn't declare its input const, so we cast */
439 copy_list = g_list_copy ((GList *)s_page_objects (page));
441 /* Iterate backwards since attributes are attached after their
442 * parent objects in the list. Attributes can get deleted during
443 * the iteration.
445 for (o_iter = g_list_last (copy_list);
446 o_iter != NULL;
447 o_iter = g_list_previous (o_iter)) {
448 OBJECT *o_current = o_iter->data;
450 /* ------- Object is a component. Handle component attributes. ------- */
451 if (o_current->type == OBJ_COMPLEX) { /* Note that OBJ_COMPLEX = component + attribs */
453 #if 0
454 if (o_attrib_search_object_attribs_by_name (o_current, "graphical", 0)) {
455 break; /* Ignore graphical components */
457 #endif
459 temp_uref = s_attrib_get_refdes(o_current);
460 if (temp_uref != NULL) {
461 /* Must create a name=value pair list for each particular component
462 * which we can pass to function updating o_current. This function
463 * places all attribs
464 * found in the row into new_comp_attrib_pair_list. */
465 new_comp_attrib_pair_list = s_table_create_attrib_pair(temp_uref,
466 sheet_head->component_table,
467 sheet_head->master_comp_list_head,
468 sheet_head->comp_attrib_count);
471 /* Now update attribs in toplevel using this list. */
472 s_toplevel_update_component_attribs_in_toplevel(o_current,
473 new_comp_attrib_pair_list);
475 g_free(temp_uref);
476 } else {
477 #ifdef DEBUG
478 printf("In s_toplevel_sheetdata_to_toplevel, found complex with no refdes. name = %s\n",
479 o_current->name);
480 #endif
482 } /* if (o_current->type == OBJ_COMPLEX) */
486 g_list_free (copy_list);
488 #if 0
489 /* ----- Next deal with all nets on the page. ----- */
490 /* This is TBD */
492 #endif
495 /* ----- Finally deal with all pins on the page. ----- */
496 /* ----- Next deal with all nets on the page. ----- */
497 #ifdef DEBUG
498 printf("----- In s_toplevel_sheetdata_to_toplevel, handling pins\n");
499 #endif
501 /* Work from a copy list in case objects are
502 * deleted from the list during its iteration.
504 /* NB: g_list_copy doesn't declare its input const, so we cast */
505 copy_list = g_list_copy ((GList *)s_page_objects (page));
507 for (o_iter = g_list_last (copy_list);
508 o_iter != NULL;
509 o_iter = g_list_previous (o_iter)) {
510 OBJECT *o_current = o_iter->data;
512 /* ------- Object is a complex. Handle pins by looking ------ */
513 /* ------- for all pins attached to a component. ------ */
514 if (o_current->type == OBJ_COMPLEX) {
515 /* Upon finding a component, here's what to do:
516 * 0. Get refdes of component.
517 * 1. Loop over prim_objects, looking for pins.
518 * 2. When a pin is found, create refdes:pinnumber pair
519 * used in searching TABLE.
520 * 3. Search TABLE using refdes:pinnumber as key, and get list of
521 * attribs corresponding to this refdes:pinnumber
522 * 4. Stick the attribs into the TOPLEVEL data structure.
524 temp_uref = s_attrib_get_refdes(o_current);
525 if ( (temp_uref != NULL) && (o_current->complex->prim_objs) ) { /* make sure object complex has a refdes */
527 for (prim_iter = o_current->complex->prim_objs;
528 prim_iter != NULL;
529 prim_iter = g_list_next (prim_iter)) {
530 OBJECT *comp_prim_obj = prim_iter->data;
532 if (comp_prim_obj->type == OBJ_PIN) {
533 new_pin_attrib_list = s_toplevel_get_pin_attribs_in_sheet(temp_uref, comp_prim_obj);
534 s_toplevel_update_pin_attribs_in_toplevel(temp_uref, comp_prim_obj, new_pin_attrib_list);
537 } /* if(temp_uref */
539 g_free(temp_uref);
543 g_list_free (copy_list);
545 return;
549 /*------------------------------------------------------------------*/
550 /*! \brief Get the component attributes from the top level
552 * This function returns a list of attributes attached to obj_name = comp
553 * refdes or netlist.
554 * \param refdes component refdes to return values from
555 * \returns a STRING_LIST where the data field holds a name=value string.
557 STRING_LIST *s_toplevel_get_component_attribs_in_sheet(char *refdes)
559 STRING_LIST *new_attrib_list;
560 STRING_LIST *local_attrib_list;
561 int i;
562 int row = -1;
563 int count = 0;
564 char *name_value_pair;
565 char *new_attrib_value;
566 char *new_attrib_name;
568 #if DEBUG
569 printf("----- Entering s_toplevel_get_component_attribs_in_sheet.\n");
570 #endif
573 /* First find pos of this refdes in the master list */
574 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
576 /* Sanity check */
577 if (row == -1) {
578 /* we didn't find the item in the list */
579 fprintf(stderr,
580 "In s_toplevel_get_component_attribs_in_sheet, we didn't find the refdes in the master list!\n");
581 return NULL;
584 /* Now get all attribs associated with this refdes (in TABLE, indexed
585 * by position), and insert them into new_attrib_list. */
586 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
588 i = 0;
589 local_attrib_list = sheet_head->master_comp_attrib_list_head;
590 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
591 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
593 if ( ((sheet_head->component_table)[row][i]).attrib_value ) {
594 new_attrib_value = g_strdup( ((sheet_head->component_table)[row][i]).attrib_value );
595 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
596 g_free(new_attrib_value);
597 } else {
598 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
600 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
601 g_free(new_attrib_name);
602 g_free(name_value_pair);
604 /* Sanity check */
605 if (count != i+1) {
606 /* for some reason, we have lost a name_value_pair somewhere . . . */
607 fprintf(stderr,
608 "In s_toplevel_get_component_attribs_in_sheet, count != i! Exiting . . . .\n");
609 exit(-1);
612 /* iterate */
613 i++;
614 local_attrib_list = local_attrib_list->next;
615 } /* while (local_attrib_list != NULL) */
617 return new_attrib_list;
622 /*------------------------------------------------------------------*/
623 /*! \brief Update component attributes in TOP_LEVEL
625 * For each attrib string attached to the component, update it using the value
626 * held in new_comp_attrib_list. Algorithm:
627 * -# Form list of all component attribs held on both the component
628 * (o_current), as well as in the attrib list (SHEET_DATA).
629 * -# Loop over name=value pairs held in complete_comp_attrib_list.
630 * -# For each name=value pair, look for corresponding attrib on o_current.
631 * -# For each name=value pair, look for the corresponding attrib in
632 * new_comp_attrib_list.
633 * -# If the attrib exists on o_current and in new_comp_attrib_list, write the
634 * new value (from new_comp_attrib_list) into o_current.
635 * -# If the attrib exists on o_current, but is null in name=value pair,
636 * delete the attrib from o_current.
637 * -# If the attribs doesn't exist on o_current, but is non-null in
638 * the name=value pair, create an attrib object and add it to the part
639 * on o_current.
640 * \param o_current Component (complex) to be updated.
641 * \param new_comp_attrib_list list of name=value attribute pairs
642 * from SHEET_DATA.
644 void s_toplevel_update_component_attribs_in_toplevel(OBJECT *o_current,
645 STRING_LIST *new_comp_attrib_list)
647 STRING_LIST *local_list;
648 STRING_LIST *complete_comp_attrib_list;
649 char *old_name_value_pair;
650 char *new_attrib_name;
651 char *new_attrib_value;
652 char *old_attrib_name;
653 char *old_attrib_value;
654 gchar *refdes;
655 GList *a_iter;
656 OBJECT *a_current;
657 int count = 0; /* This is to fake out a function called later */
658 gint row, col;
659 gint visibility = 0;
660 gint show_name_value = 0;
662 #if DEBUG
663 printf("----- Entering s_toplevel_update_component_attribs_in_toplevel.\n");
664 #endif
667 * To remove dead attribs from o_current, we need to form a complete list of unique
668 * attribs by taking the union of the new attribs from the SHEET_DATA, and
669 * the old attribs living on o_current. That's what we're doing here.
670 * Later, we can delete those attribs in o_current which don't apear in
671 * new_comp_attrib_list.
673 /* First duplicate new_comp_attrib_list */
674 complete_comp_attrib_list = s_string_list_duplicate_string_list(new_comp_attrib_list);
676 /* Now create a complete list of unique attribute names. This will be used in
677 * the loop below when updating attributes. */
678 a_iter = o_current->attribs;
679 while (a_iter != NULL) {
680 a_current = a_iter->data;
681 if (a_current->type == OBJ_TEXT
682 && a_current->text != NULL) { /* found a name=value attribute pair. */
683 /* may need to check more thoroughly here. . . . */
684 old_name_value_pair = g_strdup(a_current->text->string);
686 /* Else clause is suggestion from Ales */
687 #if 1
688 old_attrib_name = u_basic_breakup_string(old_name_value_pair, '=', 0);
689 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
690 (strcmp(old_attrib_name, "net") != 0) &&
691 (strcmp(old_attrib_name, "slot") != 0) &&
692 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
693 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
695 #else
696 /* might now compile now, but this #if'd out branch isn't being built */
697 gint status;
698 status = o_attrib_get_name_value (a_current, &old_attrib_name, &old_attrib_value);
699 if (status == 0) {
700 /* Don't put "refdes" or "slot" into list. Don't put old name=value pair into list if a new
701 * one is already in there. */
702 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
703 (strcmp(old_attrib_name, "net") != 0) &&
704 (strcmp(old_attrib_name, "slot") != 0) &&
705 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
706 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
708 g_free (old_attrib_name);
709 g_free (old_attrib_value);
711 #endif
712 g_free(old_name_value_pair);
713 g_free(old_attrib_name);
715 a_iter = g_list_next (a_iter);
716 } /* while (a_current != NULL) */
720 *Now the main business of this function: updating the attribs attached to this o_current.
721 * Loop on name=value pairs held in complete_comp_attrib_list , and then use this to get the
722 * name=value pairs out of new_comp_attrib_list and from o_current.
725 /* First handle a special case: the component has no attribs (beside refdes). */
726 if (complete_comp_attrib_list->data == NULL)
727 return;
729 /* Now the normal case. . . . */
730 local_list = complete_comp_attrib_list;
731 while (local_list != NULL) {
733 #if DEBUG
734 printf("\n\n");
735 printf(" In s_toplevel_update_component_attribs_in_toplevel, handling entry in complete list %s .\n",
736 local_list->data);
737 #endif
739 /* Now get the old attrib name & value from complete_comp_attrib_list
740 * and value from o_current */
741 old_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
742 old_attrib_value = o_attrib_search_attached_attribs_by_name (o_current, old_attrib_name, 0);
744 #if DEBUG
745 printf(" In s_toplevel_update_component_attribs_in_toplevel, old name = \"%s\" .\n",
746 old_attrib_name);
747 printf(" In s_toplevel_update_component_attribs_in_toplevel, old value = \"%s\" .\n",
748 old_attrib_value);
749 #endif
751 /* Next try to get this attrib from new_comp_attrib_list */
752 new_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
753 if (s_string_list_in_list(new_comp_attrib_list, local_list->data)) {
754 new_attrib_value = s_misc_remaining_string(local_list->data, '=', 1);
755 } else {
756 new_attrib_value = NULL;
758 #if DEBUG
759 printf(" In s_toplevel_update_component_attribs_in_toplevel, new name = \"%s\" .\n",
760 new_attrib_name);
761 printf(" In s_toplevel_update_component_attribs_in_toplevel, new value = \"%s\" .\n",
762 new_attrib_value);
763 #endif
765 /* Now get row and col where this new attrib lives. Then get
766 * visibility of the new attrib stored in the component table */
767 /* We'll need this later */
768 refdes = g_strdup(s_attrib_get_refdes(o_current));
769 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
770 col = s_table_get_index(sheet_head->master_comp_attrib_list_head, new_attrib_name);
771 /* if attribute has been deleted from the sheet, here is where we detect that */
772 if ( (row == -1) || (col == -1) ) {
773 new_attrib_value = NULL; /* attrib will be deleted below */
774 } else { /* we need a better place to get this info since the TABLE can be out of date */
775 visibility = sheet_head->component_table[row][col].visibility;
776 show_name_value = sheet_head->component_table[row][col].show_name_value;
778 g_free(refdes);
781 /* ------- Four cases to consider: Case 1 ----- */
782 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
783 /* simply write new attrib into place of old one. */
784 #if DEBUG
785 printf(" -- In s_toplevel_update_component_attribs_in_toplevel,\n");
786 printf(" about to replace old attrib with name= %s, value= %s\n",
787 new_attrib_name, new_attrib_value);
788 printf(" visibility = %d, show_name_value = %d.\n",
789 visibility, show_name_value);
790 #endif
791 s_object_replace_attrib_in_object(o_current,
792 new_attrib_name,
793 new_attrib_value,
794 visibility,
795 show_name_value);
798 /* ------- Four cases to consider: Case 2 ----- */
799 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
800 /* remove attrib from component*/
801 #if DEBUG
802 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
803 old_attrib_name, old_attrib_value);
804 #endif
805 s_object_remove_attrib_in_object(o_current, old_attrib_name);
808 /* ------- Four cases to consider: Case 3 ----- */
809 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
810 /* add new attrib to component. */
812 #if DEBUG
813 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
814 new_attrib_name, new_attrib_value);
815 #endif
817 s_object_add_comp_attrib_to_object(o_current,
818 new_attrib_name,
819 new_attrib_value,
820 visibility,
821 show_name_value);
823 /* ------- Four cases to consider: Case 4 ----- */
824 } else {
825 /* Do nothing. */
826 #if DEBUG
827 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, nothing needs to be done.\n");
828 #endif
831 /* Toggle attribute visibility and name/value setting */
834 /* free everything and iterate */
835 g_free(new_attrib_name);
836 g_free(new_attrib_value);
837 g_free(old_attrib_name);
838 g_free(old_attrib_value);
839 local_list = local_list->next;
840 } /* while (local_list != NULL) */
841 return;
845 /*------------------------------------------------------------------*/
847 * \todo Function doesn't do anything - candidate for removal?
849 STRING_LIST *s_toplevel_get_net_attribs_in_sheet(char *netname)
851 /* must be filled in */
852 return NULL;
856 /*------------------------------------------------------------------*/
858 * \todo Function doesn't do anything - candidate for removal?
860 void s_toplevel_update_net_attribs_in_toplevel(OBJECT *o_current,
861 STRING_LIST *new_net_attrib_list)
863 /* must be filled in */
864 return;
868 /*------------------------------------------------------------------*/
869 /*! \brief Get pin attributes
871 * This function takes a pointer to the OBJECT pin, and returns a list
872 * of attribs found attached to the pin. The returned list is a
873 * STRING_LIST where the ->data holds a name=value string.
874 * The algorithm is as follows:
875 * -# Form refdes:pinnumber label for this pin.
876 * -# Get row number of this refdes:pinnumber
877 * -# Create a list of name=value pairs from entries in the pin_table
878 * on this row.
879 * -# Return list of name=value pairs found.
881 * \param refdes Ref des string
882 * \param pin Pin object
883 * \returns name=value pair as a STRING_LIST
885 STRING_LIST *s_toplevel_get_pin_attribs_in_sheet(char *refdes, OBJECT *pin)
887 STRING_LIST *new_attrib_list;
888 STRING_LIST *local_attrib_list;
889 int i;
890 int row = -1;
891 int count = 0;
892 char *pinnumber;
893 char *row_label;
894 char *name_value_pair;
895 char *new_attrib_value;
896 char *new_attrib_name;
898 #if DEBUG
899 printf("----- Entering s_toplevel_get_pin_attribs_in_sheet.\n");
900 #endif
902 /* First find pos of this pin in the master pin list */
903 /* first convert refdes, pin to refdes:pinno text string. Then call table_get_index. */
905 pinnumber = o_attrib_search_object_attribs_by_name (pin, "pinnumber", 0);
907 if ( (refdes != NULL) && (pinnumber != NULL) ) {
908 row_label = g_strconcat(refdes, ":", pinnumber, NULL);
909 } else {
910 fprintf(stderr,
911 "In s_toplevel_get_pin_attribs_in_sheet, either refdes or pinnumber of object missing!\n");
912 return NULL;
914 row = s_table_get_index(sheet_head->master_pin_list_head, row_label);
916 /* Sanity check */
917 if (row == -1) {
918 /* we didn't find the item in the list */
919 fprintf(stderr,
920 "In s_toplevel_get_pin_attribs_in_sheet, we didn't find the refdes:pin in the master list!\n");
921 return NULL;
924 /* Now get all attribs associated with this refdes (in TABLE, indexed
925 * by position), and insert them into new_attrib_list. */
926 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
928 i = 0;
929 local_attrib_list = sheet_head->master_pin_attrib_list_head;
930 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
931 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
933 if ( ((sheet_head->pin_table)[row][i]).attrib_value ) {
934 new_attrib_value = g_strdup( ((sheet_head->pin_table)[row][i]).attrib_value );
935 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
936 g_free(new_attrib_value);
937 } else {
938 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
940 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
941 g_free(new_attrib_name);
942 g_free(name_value_pair);
944 /* Sanity check */
945 if (count != i+1) {
946 /* for some reason, we have lost a name_value_pair somewhere . . . */
947 fprintf(stderr,
948 "In s_toplevel_get_pin_attribs_in_sheet, count != i! Exiting . . . .\n");
949 exit(-1);
952 /* iterate */
953 i++;
954 local_attrib_list = local_attrib_list->next;
955 } /* while (local_attrib_list != NULL) */
957 return new_attrib_list;
962 /*------------------------------------------------------------------*/
963 /*! \brief Update pin attributes in toplevel
965 * For each attrib string attached to the pin, update it using the value
966 * held in new_pin_attrib_list. Algorithm:
967 * -# Loop over name=value pairs held in new_pin_attrib_list.
968 * -# For each name=value pair, look for corresponding attrib on pin.
969 * -# If the attrib exists on pin and in name=value pair, write the
970 * new value in.
971 * -# If the attrib exists on pin, but is null in name=value pair,
972 * delete the attrib.
973 * -# If the attribs doesn't exist on pin, but is non-null in
974 * the name=value pair, create an attrib object and add it to the pin.
975 * \param refdes Unused - needs refactored out
976 * \param [in,out] o_pin pin to update
977 * \param [in] new_pin_attrib_list New pin attribute list to apply
979 void s_toplevel_update_pin_attribs_in_toplevel(char *refdes, OBJECT *o_pin,
980 STRING_LIST *new_pin_attrib_list)
982 STRING_LIST *local_list;
983 char *new_name_value_pair;
984 char *new_attrib_name;
985 char *new_attrib_value;
986 char *old_attrib_value;
988 #if DEBUG
989 printf("----- Entering s_toplevel_update_pin_attribs_in_toplevel.\n");
990 #endif
992 /* loop on name=value pairs held in new_pin_attrib_list */
993 local_list = new_pin_attrib_list;
994 while (local_list != NULL) {
995 new_name_value_pair = g_strdup(local_list->data);
996 #if DEBUG
997 printf(" In s_toplevel_update_pin_attribs_in_toplevel, handling entry in master list %s .\n", new_name_value_pair);
998 #endif
1000 new_attrib_name = u_basic_breakup_string(new_name_value_pair, '=', 0);
1001 new_attrib_value = u_basic_breakup_string(new_name_value_pair, '=', 1);
1003 if (strlen(new_attrib_value) == 0) {
1004 g_free(new_attrib_value);
1005 new_attrib_value = NULL; /* s_misc_remaining_string doesn't return NULL for empty substring. */
1007 old_attrib_value = o_attrib_search_attached_attribs_by_name (o_pin, new_attrib_name, 0);
1009 /* ------- Four cases to consider: Case 1: old and new attribs exist ----- */
1010 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
1011 /* simply write new attrib into place of old one. */
1012 #if DEBUG
1013 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to replace old attrib with new one: name= %s, value= %s\n",
1014 new_attrib_name, new_attrib_value);
1015 #endif
1016 s_object_replace_attrib_in_object(o_pin,
1017 new_attrib_name,
1018 new_attrib_value,
1019 LEAVE_VISIBILITY_ALONE,
1020 LEAVE_NAME_VALUE_ALONE);
1023 /* ------- Four cases to consider: Case 2: old attrib exists, new one doesn't ----- */
1024 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
1025 /* remove attrib from pin */
1026 #if DEBUG
1027 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
1028 new_attrib_name, old_attrib_value);
1029 #endif
1030 s_object_remove_attrib_in_object(o_pin, new_attrib_name);
1033 /* ------- Four cases to consider: Case 3: No old attrib, new one exists. ----- */
1034 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
1035 /* add new attrib to pin. */
1037 #if DEBUG
1038 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
1039 new_attrib_name, new_attrib_value);
1040 #endif
1042 s_object_add_pin_attrib_to_object(o_pin, new_attrib_name, new_attrib_value);
1044 /* ------- Four cases to consider: Case 4 ----- */
1045 } else {
1046 /* Do nothing. */
1047 #if DEBUG
1048 printf("In s_toplevel_update_pin_attribs_in_toplevel, nothing needs to be done.\n");
1049 #endif
1052 /* free everything and iterate */
1053 g_free(new_name_value_pair);
1054 g_free(new_attrib_name);
1055 g_free(new_attrib_value);
1056 g_free(old_attrib_value);
1057 local_list = local_list->next;
1058 } /* while (local_list != NULL) */
1060 return;