netlist: Apply title patch to Python netlist backend
[geda-gaf.git] / gattrib / src / s_toplevel.c
blob8c532cccfe17faeddaa472758a36e93577c50475
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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"
46 #include "../include/gettext.h"
49 /* =================== Public Functions ====================== */
52 /*! \brief Read a schematic page
54 * Reads in a schematic page & calls f_open, which fills out the
55 * toplevel structure.
57 * \param toplevel TOPLEVEL structure
58 * \param filename file to be opened
59 * \returns 1 on success, 0 on failure
61 int s_toplevel_read_page(TOPLEVEL *toplevel, char *filename)
63 int file_return_code;
64 GError *err = NULL;
66 /* Set the new filename */
67 toplevel->page_current->page_filename = g_strdup(filename);
69 /* read in and fill out toplevel using f_open and its callees */
70 file_return_code = f_open (toplevel, toplevel->page_current, filename, &err);
72 /* If an error occurred, print message */
73 if (err != NULL) {
74 g_warning ("%s", err->message);
75 g_error_free (err);
78 return file_return_code;
82 /*! \brief Verify the entire design
84 * This function loops through all components in the
85 * design looking for components which are placeholders.
87 * Placeholders are inserted into the object list when
88 * no symbol file is found. If this function finds a
89 * placeholder, it warns the user.
91 * \param toplevel pointer to the toplevel object to be verified
93 void s_toplevel_verify_design (TOPLEVEL *toplevel)
95 GList *p_iter;
96 const GList *o_iter;
98 int missing_sym_flag = 0;
100 for (p_iter = geda_list_get_glist (toplevel->pages);
101 p_iter != NULL;
102 p_iter = g_list_next (p_iter)) {
103 PAGE *p_current = p_iter->data;
105 for (o_iter = s_page_objects (p_current);
106 o_iter != NULL;
107 o_iter = g_list_next (o_iter)) {
108 OBJECT *o_current = o_iter->data;
110 /* --- look for object, and verify that it has a symbol file attached. ---- */
111 if (o_current->type == OBJ_PLACEHOLDER) {
112 missing_sym_flag = 1; /* flag to signal that problem exists. */
117 if (missing_sym_flag) {
118 x_dialog_missing_sym(); /* dialog gives user option to quit */
122 /*------------------------------------------------------------------*/
123 /*! \brief Copy data from gtksheet into TOPLEVEL struct
125 * Called when the user invokes "save". It first
126 * places all data from gtksheet into SHEET_DATA. Then it
127 * loops through all pages & calls s_toplevel_sheetdata_to_toplevel()
128 * to place all
129 * stuff in SHEET_DATA into the libgeda TOPLEVEL structure.
131 void
132 s_toplevel_gtksheet_to_toplevel(TOPLEVEL *toplevel)
134 GList *iter;
135 PAGE *p_current;
137 #if DEBUG
138 printf("--------------------- Entering s_toplevel_gtksheet_to_toplevel -------------------\n");
139 #endif
141 s_sheet_data_gtksheet_to_sheetdata(); /* read data from gtksheet into SHEET_DATA */
142 #if DEBUG
143 printf("In s_toplevel_gtksheet_to_toplevel -- done writing stuff from gtksheet into SHEET_DATA.\n");
144 #endif
146 /* must iterate over all pages in design */
147 for ( iter = geda_list_get_glist( toplevel->pages );
148 iter != NULL;
149 iter = g_list_next( iter ) ) {
151 p_current = (PAGE *)iter->data;
152 s_toplevel_set_page_current (toplevel, p_current);
153 /* only traverse pages which are toplevel */
154 if (p_current->page_control == 0) {
155 s_toplevel_sheetdata_to_toplevel (toplevel, p_current); /* adds all objects from page */
159 #if DEBUG
160 printf("In s_toplevel_gtksheet_to_toplevel -- done writing SHEEET_DATA text back into pr_currnet.\n");
161 #endif
163 return;
168 /*------------------------------------------------------------------*/
169 /*! \brief Add a new attribute to the top level
171 * This function gets called when the user has entered a new attrib name,
172 * and clicked the OK button. It does this:
173 * -# It figures out which attrib/sheet is being added to
174 * -# It destroys the old table in preparation for the new attrib.
175 * -# It adds the new attrib to the master lists.
176 * -# It creates a new table with the new attrib.
177 * -# It then adds the appropriate col to the gtksheet.
178 * \param new_attrib_name attribute to be added
180 void s_toplevel_add_new_attrib(gchar *new_attrib_name) {
181 gint cur_page; /* current page in notbook */
182 gint old_comp_attrib_count;
183 gint new_index;
185 if (strcmp(new_attrib_name, N_("_cancel")) == 0) {
186 return; /* user pressed cancel or closed window with no value in entry */
189 /* Next must figure out which sheet the attrib belongs to. */
190 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
191 #ifdef DEBUG
192 printf("In s_toplevel_add_new_attrib, adding new attrib to page %d.\n",
193 cur_page);
194 #endif
196 switch (cur_page) {
197 case 0: /* component attribute */
199 /* Eventually, I want to just resize the table to accomodate the
200 * new attrib. However, that is difficult. Therefore, I will just
201 * destroy the old table and recreate it for now. */
204 s_table_destroy(sheet_head->component_table,
205 sheet_head->comp_count, sheet_head->comp_attrib_count);
207 old_comp_attrib_count = sheet_head->comp_attrib_count;
208 #ifdef DEBUG
209 printf("In s_toplevel_add_new_attrib, before adding new comp attrib.\n");
210 printf(" comp_attrib_count = %d\n", old_comp_attrib_count);
211 #endif
213 s_string_list_add_item(sheet_head->master_comp_attrib_list_head,
214 &(sheet_head->comp_attrib_count),
215 new_attrib_name);
216 s_string_list_sort_master_comp_attrib_list();
218 /* Now, determine what index the new attrib ended up at
219 * This is necessary to tell gtk_sheet_insert_columns
220 * where the data should be shifted */
221 new_index = s_string_list_find_in_list(sheet_head->master_comp_attrib_list_head,
222 (char*)new_attrib_name);
224 #ifdef DEBUG
225 printf("In s_toplevel_add_new_attrib, just updated comp_attrib string list.\n");
226 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
227 #endif
229 /* Now create new table */
230 /* sheet_head->component_table = s_table_new(sheet_head->comp_count,
231 sheet_head->comp_attrib_count);
234 /* resize table to accomodate new attrib col */
235 sheet_head->component_table =
236 s_table_resize(sheet_head->component_table,
237 sheet_head->comp_count,
238 old_comp_attrib_count, sheet_head->comp_attrib_count);
240 #ifdef DEBUG
241 printf("In s_toplevel_add_new_attrib, just resized component table.\n");
242 #endif
244 /* Fill out new sheet with new stuff from gtksheet */
245 gtk_sheet_insert_columns(GTK_SHEET(sheets[0]), new_index, 1);
246 x_gtksheet_add_col_labels(GTK_SHEET(sheets[0]),
247 sheet_head->comp_attrib_count,
248 sheet_head->master_comp_attrib_list_head);
250 #ifdef DEBUG
251 printf("In s_toplevel_add_new_attrib, just updated gtksheet.\n");
252 #endif
254 break;
256 case 1: /* net attribute */
257 /* insert into net attribute list */
258 break;
260 case 2: /* pin attribute */
261 /* insert into pin attribute list */
262 break;
263 } /* switch */
265 return;
269 /*------------------------------------------------------------------*/
270 /*! \brief Delete an attribute column
272 * This function gets called when the user has selected a single attrib
273 * column, selected the edit->delete attrib item from the pull-down
274 * menu, and then said "yes" to the confirm dialog.
276 void s_toplevel_delete_attrib_col() {
277 gint cur_page; /* current page in notbook */
278 gint mincol, maxcol;
279 GtkSheet *sheet;
280 gchar *attrib_name;
282 /* Repeat previous checks */
283 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
284 sheet = GTK_SHEET(sheets[cur_page]);
285 if (sheet == NULL) {
286 return;
288 mincol = x_gtksheet_get_min_col(sheet);
289 maxcol = x_gtksheet_get_max_col(sheet);
290 if ( (mincol != maxcol) || (mincol == -1) || (maxcol == -1) ) {
291 return;
294 #ifdef DEBUG
295 printf("In s_toplevel_delete_attrib_col, checks were OK, now do real work\n");
296 #endif
298 /* Rebuild the gattrib-specific data structures */
299 switch (cur_page) {
301 case 0: /* component attribute */
303 /* Eventually, I want to just resize the table after deleting the
304 * attrib. However, that is difficult. Therefore, I will just
305 * destroy the old table and recreate it for now. */
307 s_table_destroy(sheet_head->component_table,
308 sheet_head->comp_count, sheet_head->comp_attrib_count);
310 /* Get name (label) of the col to delete from the gtk sheet */
311 attrib_name = g_strdup( gtk_sheet_column_button_get_label(sheet, mincol) );
313 if (attrib_name != NULL) {
314 #ifdef DEBUG
315 printf("In s_toplevel_delete_attrib_col, attrib to delete = %s\n", attrib_name);
316 #endif
317 } else {
318 fprintf(stderr, _("In s_toplevel_delete_attrib_col, can't get attrib name\n"));
319 return;
322 #ifdef DEBUG
323 printf("In s_toplevel_delete_attrib_col, before deleting comp attrib.\n");
324 printf(" comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
325 #endif
326 s_string_list_delete_item(&(sheet_head->master_comp_attrib_list_head),
327 &(sheet_head->comp_attrib_count),
328 attrib_name);
329 s_string_list_sort_master_comp_attrib_list(); /* this renumbers list also */
330 g_free(attrib_name);
332 #ifdef DEBUG
333 printf("In s_toplevel_delete_attrib_col, just updated comp_attrib string list.\n");
334 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
335 #endif
337 /* Now create new table with new attrib count*/
338 sheet_head->component_table = s_table_new(sheet_head->comp_count,
339 sheet_head->comp_attrib_count);
342 #ifdef DEBUG
343 printf("In s_toplevel_delete_attrib_col, just updated SHEET_DATA info.\n");
344 #endif
345 break;
347 case 1: /* net attribute */
348 /* insert into net attribute list */
349 break;
351 case 2: /* pin attribute */
352 /* insert into pin attribute list */
353 break;
354 } /* switch */
357 /* Delete col on gtksheet */
358 #ifdef DEBUG
359 printf("In s_toplevel_delete_attrib_col, about to delete col in gtksheet.\n");
360 #endif
361 gtk_sheet_delete_columns (sheet, mincol, 1);
362 #ifdef DEBUG
363 printf("In s_toplevel_delete_attrib_col, done deleting col in gtksheet.\n");
364 #endif
366 sheet_head->CHANGED = TRUE; /* Set changed flag so user is prompted when exiting */
368 return;
372 /* ======================= Private functions ====================== */
374 /*------------------------------------------------------------------*/
375 /*! \brief Copy SHEET_DATA content to TOP_LEVEL
377 * This function
378 * loops through all objects on (PAGE page)->(OBJECT *start_obj).
379 * It takes the updated SHEET_DATA->TABLE data and then updates the
380 * objects with the new attribs & attrib values.
381 * For each component, it updates the attached
382 * attrib values using the updated values held in the SHEET_DATA->TABLE
383 * structure. It does so in three steps:
384 * -# First find and update component attribs.
385 * -# Then find and update net attribs.
386 * -# Finally find and update pin attribs.
387 * \param toplevel TOPLEVEL structure
388 * \param page schematic page to copy
390 void
391 s_toplevel_sheetdata_to_toplevel (TOPLEVEL *toplevel, PAGE *page)
393 GList *copy_list;
394 GList *o_iter, *prim_iter;
395 char *temp_uref;
396 STRING_LIST *new_comp_attrib_pair_list;
397 STRING_LIST *new_pin_attrib_list;
399 /* ----- First deal with all components on the page. ----- */
400 #ifdef DEBUG
401 printf("----- In s_toplevel_sheetdata_to_toplevel, handling components\n");
402 #endif
404 /* Work from a copy list, as objects can be deleted
405 * from the list during iteration over the list.
407 /* NB: g_list_copy doesn't declare its input const, so we cast */
408 copy_list = g_list_copy ((GList *)s_page_objects (page));
410 /* Iterate backwards since attributes are attached after their
411 * parent objects in the list. Attributes can get deleted during
412 * the iteration.
414 for (o_iter = g_list_last (copy_list);
415 o_iter != NULL;
416 o_iter = g_list_previous (o_iter)) {
417 OBJECT *o_current = o_iter->data;
419 /* ------- Object is a component. Handle component attributes. ------- */
420 if (o_current->type == OBJ_COMPLEX) { /* Note that OBJ_COMPLEX = component + attribs */
422 #if 0
423 if (o_attrib_search_object_attribs_by_name (o_current, "graphical", 0)) {
424 break; /* Ignore graphical components */
426 #endif
428 temp_uref = s_attrib_get_refdes(o_current);
429 if (temp_uref != NULL) {
430 /* Must create a name=value pair list for each particular component
431 * which we can pass to function updating o_current. This function
432 * places all attribs
433 * found in the row into new_comp_attrib_pair_list. */
434 new_comp_attrib_pair_list = s_table_create_attrib_pair(temp_uref,
435 sheet_head->component_table,
436 sheet_head->master_comp_list_head,
437 sheet_head->comp_attrib_count);
440 /* Now update attribs in toplevel using this list. */
441 s_toplevel_update_component_attribs_in_toplevel(toplevel,
442 o_current,
443 new_comp_attrib_pair_list);
445 g_free(temp_uref);
446 } else {
447 #ifdef DEBUG
448 printf("In s_toplevel_sheetdata_to_toplevel, found complex with no refdes. name = %s\n",
449 o_current->name);
450 #endif
452 } /* if (o_current->type == OBJ_COMPLEX) */
456 g_list_free (copy_list);
458 #if 0
459 /* ----- Next deal with all nets on the page. ----- */
460 /* This is TBD */
462 #endif
465 /* ----- Finally deal with all pins on the page. ----- */
466 /* ----- Next deal with all nets on the page. ----- */
467 #ifdef DEBUG
468 printf("----- In s_toplevel_sheetdata_to_toplevel, handling pins\n");
469 #endif
471 /* Work from a copy list in case objects are
472 * deleted from the list during its iteration.
474 /* NB: g_list_copy doesn't declare its input const, so we cast */
475 copy_list = g_list_copy ((GList *)s_page_objects (page));
477 for (o_iter = g_list_last (copy_list);
478 o_iter != NULL;
479 o_iter = g_list_previous (o_iter)) {
480 OBJECT *o_current = o_iter->data;
482 /* ------- Object is a complex. Handle pins by looking ------ */
483 /* ------- for all pins attached to a component. ------ */
484 if (o_current->type == OBJ_COMPLEX) {
485 /* Upon finding a component, here's what to do:
486 * 0. Get refdes of component.
487 * 1. Loop over prim_objects, looking for pins.
488 * 2. When a pin is found, create refdes:pinnumber pair
489 * used in searching TABLE.
490 * 3. Search TABLE using refdes:pinnumber as key, and get list of
491 * attribs corresponding to this refdes:pinnumber
492 * 4. Stick the attribs into the TOPLEVEL data structure.
494 temp_uref = s_attrib_get_refdes(o_current);
495 if ( (temp_uref != NULL) && (o_current->complex->prim_objs) ) { /* make sure object complex has a refdes */
497 for (prim_iter = o_current->complex->prim_objs;
498 prim_iter != NULL;
499 prim_iter = g_list_next (prim_iter)) {
500 OBJECT *comp_prim_obj = prim_iter->data;
502 if (comp_prim_obj->type == OBJ_PIN) {
503 new_pin_attrib_list =
504 s_toplevel_get_pin_attribs_in_sheet (temp_uref, comp_prim_obj);
505 s_toplevel_update_pin_attribs_in_toplevel (toplevel,
506 temp_uref,
507 comp_prim_obj,
508 new_pin_attrib_list);
511 } /* if(temp_uref */
513 g_free(temp_uref);
517 g_list_free (copy_list);
519 return;
523 /*------------------------------------------------------------------*/
524 /*! \brief Get the component attributes from the top level
526 * This function returns a list of attributes attached to obj_name = comp
527 * refdes or netlist.
528 * \param refdes component refdes to return values from
529 * \returns a STRING_LIST where the data field holds a name=value string.
531 STRING_LIST *s_toplevel_get_component_attribs_in_sheet(char *refdes)
533 STRING_LIST *new_attrib_list;
534 STRING_LIST *local_attrib_list;
535 int i;
536 int row = -1;
537 int count = 0;
538 char *name_value_pair;
539 char *new_attrib_value;
540 char *new_attrib_name;
542 #if DEBUG
543 printf("----- Entering s_toplevel_get_component_attribs_in_sheet.\n");
544 #endif
547 /* First find pos of this refdes in the master list */
548 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
550 /* Sanity check */
551 if (row == -1) {
552 /* we didn't find the item in the list */
553 fprintf(stderr,
554 _("In s_toplevel_get_component_attribs_in_sheet, we didn't find the refdes in the master list!\n"));
555 return NULL;
558 /* Now get all attribs associated with this refdes (in TABLE, indexed
559 * by position), and insert them into new_attrib_list. */
560 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
562 i = 0;
563 local_attrib_list = sheet_head->master_comp_attrib_list_head;
564 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
565 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
567 if ( ((sheet_head->component_table)[row][i]).attrib_value ) {
568 new_attrib_value = g_strdup( ((sheet_head->component_table)[row][i]).attrib_value );
569 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
570 g_free(new_attrib_value);
571 } else {
572 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
574 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
575 g_free(new_attrib_name);
576 g_free(name_value_pair);
578 /* Sanity check */
579 if (count != i+1) {
580 /* for some reason, we have lost a name_value_pair somewhere . . . */
581 fprintf(stderr,
582 _("In s_toplevel_get_component_attribs_in_sheet, count != i! Exiting . . . .\n"));
583 exit(-1);
586 /* iterate */
587 i++;
588 local_attrib_list = local_attrib_list->next;
589 } /* while (local_attrib_list != NULL) */
591 return new_attrib_list;
596 /*------------------------------------------------------------------*/
597 /*! \brief Update component attributes in TOP_LEVEL
599 * For each attrib string attached to the component, update it using the value
600 * held in new_comp_attrib_list. Algorithm:
601 * -# Form list of all component attribs held on both the component
602 * (o_current), as well as in the attrib list (SHEET_DATA).
603 * -# Loop over name=value pairs held in complete_comp_attrib_list.
604 * -# For each name=value pair, look for corresponding attrib on o_current.
605 * -# For each name=value pair, look for the corresponding attrib in
606 * new_comp_attrib_list.
607 * -# If the attrib exists on o_current and in new_comp_attrib_list, write the
608 * new value (from new_comp_attrib_list) into o_current.
609 * -# If the attrib exists on o_current, but is null in name=value pair,
610 * delete the attrib from o_current.
611 * -# If the attribs doesn't exist on o_current, but is non-null in
612 * the name=value pair, create an attrib object and add it to the part
613 * on o_current.
614 * \param toplevel TOPLEVEL structure
615 * \param o_current Component (complex) to be updated.
616 * \param new_comp_attrib_list list of name=value attribute pairs
617 * from SHEET_DATA.
619 void
620 s_toplevel_update_component_attribs_in_toplevel (
621 TOPLEVEL *toplevel,
622 OBJECT *o_current,
623 STRING_LIST *new_comp_attrib_list)
625 STRING_LIST *local_list;
626 STRING_LIST *complete_comp_attrib_list;
627 char *old_name_value_pair;
628 char *new_attrib_name;
629 char *new_attrib_value;
630 char *old_attrib_name;
631 char *old_attrib_value;
632 gchar *refdes;
633 GList *a_iter;
634 OBJECT *a_current;
635 int count = 0; /* This is to fake out a function called later */
636 gint row, col;
637 gint visibility = 0;
638 gint show_name_value = 0;
640 #if DEBUG
641 printf("----- Entering s_toplevel_update_component_attribs_in_toplevel.\n");
642 #endif
645 * To remove dead attribs from o_current, we need to form a complete list of unique
646 * attribs by taking the union of the new attribs from the SHEET_DATA, and
647 * the old attribs living on o_current. That's what we're doing here.
648 * Later, we can delete those attribs in o_current which don't apear in
649 * new_comp_attrib_list.
651 /* First duplicate new_comp_attrib_list */
652 complete_comp_attrib_list = s_string_list_duplicate_string_list(new_comp_attrib_list);
654 /* Now create a complete list of unique attribute names. This will be used in
655 * the loop below when updating attributes. */
656 a_iter = o_current->attribs;
657 while (a_iter != NULL) {
658 a_current = a_iter->data;
659 if (a_current->type == OBJ_TEXT
660 && a_current->text != NULL) { /* found a name=value attribute pair. */
661 /* may need to check more thoroughly here. . . . */
662 old_name_value_pair = g_strdup(a_current->text->string);
664 /* Else clause is suggestion from Ales */
665 #if 1
666 old_attrib_name = u_basic_breakup_string(old_name_value_pair, '=', 0);
667 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
668 (strcmp(old_attrib_name, "net") != 0) &&
669 (strcmp(old_attrib_name, "slot") != 0) &&
670 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
671 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
673 #else
674 /* might now compile now, but this #if'd out branch isn't being built */
675 gint status;
676 status = o_attrib_get_name_value (a_current, &old_attrib_name, &old_attrib_value);
677 if (status == 0) {
678 /* Don't put "refdes" or "slot" into list. Don't put old name=value pair into list if a new
679 * one is already in there. */
680 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
681 (strcmp(old_attrib_name, "net") != 0) &&
682 (strcmp(old_attrib_name, "slot") != 0) &&
683 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
684 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
686 g_free (old_attrib_name);
687 g_free (old_attrib_value);
689 #endif
690 g_free(old_name_value_pair);
691 g_free(old_attrib_name);
693 a_iter = g_list_next (a_iter);
694 } /* while (a_current != NULL) */
698 *Now the main business of this function: updating the attribs attached to this o_current.
699 * Loop on name=value pairs held in complete_comp_attrib_list , and then use this to get the
700 * name=value pairs out of new_comp_attrib_list and from o_current.
703 /* First handle a special case: the component has no attribs (beside refdes). */
704 if (complete_comp_attrib_list->data == NULL)
705 return;
707 /* Now the normal case. . . . */
708 local_list = complete_comp_attrib_list;
709 while (local_list != NULL) {
711 #if DEBUG
712 printf("\n\n");
713 printf(" In s_toplevel_update_component_attribs_in_toplevel, handling entry in complete list %s .\n",
714 local_list->data);
715 #endif
717 /* Now get the old attrib name & value from complete_comp_attrib_list
718 * and value from o_current */
719 old_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
720 old_attrib_value = o_attrib_search_attached_attribs_by_name (o_current, old_attrib_name, 0);
722 #if DEBUG
723 printf(" In s_toplevel_update_component_attribs_in_toplevel, old name = \"%s\" .\n",
724 old_attrib_name);
725 printf(" In s_toplevel_update_component_attribs_in_toplevel, old value = \"%s\" .\n",
726 old_attrib_value);
727 #endif
729 /* Next try to get this attrib from new_comp_attrib_list */
730 new_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
731 if (s_string_list_in_list(new_comp_attrib_list, local_list->data)) {
732 new_attrib_value = s_misc_remaining_string(local_list->data, '=', 1);
733 } else {
734 new_attrib_value = NULL;
736 #if DEBUG
737 printf(" In s_toplevel_update_component_attribs_in_toplevel, new name = \"%s\" .\n",
738 new_attrib_name);
739 printf(" In s_toplevel_update_component_attribs_in_toplevel, new value = \"%s\" .\n",
740 new_attrib_value);
741 #endif
743 /* Now get row and col where this new attrib lives. Then get
744 * visibility of the new attrib stored in the component table */
745 /* We'll need this later */
746 refdes = g_strdup(s_attrib_get_refdes(o_current));
747 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
748 col = s_table_get_index(sheet_head->master_comp_attrib_list_head, new_attrib_name);
749 /* if attribute has been deleted from the sheet, here is where we detect that */
750 if ( (row == -1) || (col == -1) ) {
751 new_attrib_value = NULL; /* attrib will be deleted below */
752 } else { /* we need a better place to get this info since the TABLE can be out of date */
753 visibility = sheet_head->component_table[row][col].visibility;
754 show_name_value = sheet_head->component_table[row][col].show_name_value;
756 g_free(refdes);
759 /* ------- Four cases to consider: Case 1 ----- */
760 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
761 /* simply write new attrib into place of old one. */
762 #if DEBUG
763 printf(" -- In s_toplevel_update_component_attribs_in_toplevel,\n");
764 printf(" about to replace old attrib with name= %s, value= %s\n",
765 new_attrib_name, new_attrib_value);
766 printf(" visibility = %d, show_name_value = %d.\n",
767 visibility, show_name_value);
768 #endif
769 s_object_replace_attrib_in_object(toplevel,
770 o_current,
771 new_attrib_name,
772 new_attrib_value,
773 visibility,
774 show_name_value);
777 /* ------- Four cases to consider: Case 2 ----- */
778 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
779 /* remove attrib from component*/
780 #if DEBUG
781 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
782 old_attrib_name, old_attrib_value);
783 #endif
784 s_object_remove_attrib_in_object (toplevel, o_current, old_attrib_name);
787 /* ------- Four cases to consider: Case 3 ----- */
788 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
789 /* add new attrib to component. */
791 #if DEBUG
792 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
793 new_attrib_name, new_attrib_value);
794 #endif
796 s_object_add_comp_attrib_to_object (toplevel,
797 o_current,
798 new_attrib_name,
799 new_attrib_value,
800 visibility,
801 show_name_value);
803 /* ------- Four cases to consider: Case 4 ----- */
804 } else {
805 /* Do nothing. */
806 #if DEBUG
807 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, nothing needs to be done.\n");
808 #endif
811 /* Toggle attribute visibility and name/value setting */
814 /* free everything and iterate */
815 g_free(new_attrib_name);
816 g_free(new_attrib_value);
817 g_free(old_attrib_name);
818 g_free(old_attrib_value);
819 local_list = local_list->next;
820 } /* while (local_list != NULL) */
821 return;
825 /*------------------------------------------------------------------*/
827 * \todo Function doesn't do anything - candidate for removal?
829 STRING_LIST *s_toplevel_get_net_attribs_in_sheet(char *netname)
831 /* must be filled in */
832 return NULL;
836 /*------------------------------------------------------------------*/
838 * \todo Function doesn't do anything - candidate for removal?
840 void s_toplevel_update_net_attribs_in_toplevel(OBJECT *o_current,
841 STRING_LIST *new_net_attrib_list)
843 /* must be filled in */
844 return;
848 /*------------------------------------------------------------------*/
849 /*! \brief Get pin attributes
851 * This function takes a pointer to the OBJECT pin, and returns a list
852 * of attribs found attached to the pin. The returned list is a
853 * STRING_LIST where the ->data holds a name=value string.
854 * The algorithm is as follows:
855 * -# Form refdes:pinnumber label for this pin.
856 * -# Get row number of this refdes:pinnumber
857 * -# Create a list of name=value pairs from entries in the pin_table
858 * on this row.
859 * -# Return list of name=value pairs found.
861 * \param refdes Ref des string
862 * \param pin Pin object
863 * \returns name=value pair as a STRING_LIST
865 STRING_LIST *s_toplevel_get_pin_attribs_in_sheet(char *refdes, OBJECT *pin)
867 STRING_LIST *new_attrib_list;
868 STRING_LIST *local_attrib_list;
869 int i;
870 int row = -1;
871 int count = 0;
872 char *pinnumber;
873 char *row_label;
874 char *name_value_pair;
875 char *new_attrib_value;
876 char *new_attrib_name;
878 #if DEBUG
879 printf("----- Entering s_toplevel_get_pin_attribs_in_sheet.\n");
880 #endif
882 /* First find pos of this pin in the master pin list */
883 /* first convert refdes, pin to refdes:pinno text string. Then call table_get_index. */
885 pinnumber = o_attrib_search_object_attribs_by_name (pin, "pinnumber", 0);
887 if ( (refdes != NULL) && (pinnumber != NULL) ) {
888 row_label = g_strconcat(refdes, ":", pinnumber, NULL);
889 } else {
890 fprintf(stderr,
891 _("In s_toplevel_get_pin_attribs_in_sheet, either refdes or pinnumber of object missing!\n"));
892 return NULL;
894 row = s_table_get_index(sheet_head->master_pin_list_head, row_label);
896 /* Sanity check */
897 if (row == -1) {
898 /* we didn't find the item in the list */
899 fprintf(stderr,
900 _("In s_toplevel_get_pin_attribs_in_sheet, we didn't find the refdes:pin in the master list!\n"));
901 return NULL;
904 /* Now get all attribs associated with this refdes (in TABLE, indexed
905 * by position), and insert them into new_attrib_list. */
906 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
908 i = 0;
909 local_attrib_list = sheet_head->master_pin_attrib_list_head;
910 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
911 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
913 if ( ((sheet_head->pin_table)[row][i]).attrib_value ) {
914 new_attrib_value = g_strdup( ((sheet_head->pin_table)[row][i]).attrib_value );
915 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
916 g_free(new_attrib_value);
917 } else {
918 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
920 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
921 g_free(new_attrib_name);
922 g_free(name_value_pair);
924 /* Sanity check */
925 if (count != i+1) {
926 /* for some reason, we have lost a name_value_pair somewhere . . . */
927 fprintf(stderr,
928 _("In s_toplevel_get_pin_attribs_in_sheet, count != i! Exiting . . . .\n"));
929 exit(-1);
932 /* iterate */
933 i++;
934 local_attrib_list = local_attrib_list->next;
935 } /* while (local_attrib_list != NULL) */
937 return new_attrib_list;
942 /*------------------------------------------------------------------*/
943 /*! \brief Update pin attributes in toplevel
945 * For each attrib string attached to the pin, update it using the value
946 * held in new_pin_attrib_list. Algorithm:
947 * -# Loop over name=value pairs held in new_pin_attrib_list.
948 * -# For each name=value pair, look for corresponding attrib on pin.
949 * -# If the attrib exists on pin and in name=value pair, write the
950 * new value in.
951 * -# If the attrib exists on pin, but is null in name=value pair,
952 * delete the attrib.
953 * -# If the attribs doesn't exist on pin, but is non-null in
954 * the name=value pair, create an attrib object and add it to the pin.
955 * \param toplevel TOPLEVEL structure
956 * \param refdes Unused - needs refactored out
957 * \param [in,out] o_pin pin to update
958 * \param [in] new_pin_attrib_list New pin attribute list to apply
960 void
961 s_toplevel_update_pin_attribs_in_toplevel (TOPLEVEL *toplevel,
962 char *refdes,
963 OBJECT *o_pin,
964 STRING_LIST *new_pin_attrib_list)
966 STRING_LIST *local_list;
967 char *new_name_value_pair;
968 char *new_attrib_name;
969 char *new_attrib_value;
970 char *old_attrib_value;
972 #if DEBUG
973 printf("----- Entering s_toplevel_update_pin_attribs_in_toplevel.\n");
974 #endif
976 /* loop on name=value pairs held in new_pin_attrib_list */
977 local_list = new_pin_attrib_list;
978 while (local_list != NULL) {
979 new_name_value_pair = g_strdup(local_list->data);
980 #if DEBUG
981 printf(" In s_toplevel_update_pin_attribs_in_toplevel, handling entry in master list %s .\n", new_name_value_pair);
982 #endif
984 new_attrib_name = u_basic_breakup_string(new_name_value_pair, '=', 0);
985 new_attrib_value = u_basic_breakup_string(new_name_value_pair, '=', 1);
987 if (strlen(new_attrib_value) == 0) {
988 g_free(new_attrib_value);
989 new_attrib_value = NULL; /* s_misc_remaining_string doesn't return NULL for empty substring. */
991 old_attrib_value = o_attrib_search_attached_attribs_by_name (o_pin, new_attrib_name, 0);
993 /* ------- Four cases to consider: Case 1: old and new attribs exist ----- */
994 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
995 /* simply write new attrib into place of old one. */
996 #if DEBUG
997 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to replace old attrib with new one: name= %s, value= %s\n",
998 new_attrib_name, new_attrib_value);
999 #endif
1000 s_object_replace_attrib_in_object(toplevel,
1001 o_pin,
1002 new_attrib_name,
1003 new_attrib_value,
1004 LEAVE_VISIBILITY_ALONE,
1005 LEAVE_NAME_VALUE_ALONE);
1008 /* ------- Four cases to consider: Case 2: old attrib exists, new one doesn't ----- */
1009 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
1010 /* remove attrib from pin */
1011 #if DEBUG
1012 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
1013 new_attrib_name, old_attrib_value);
1014 #endif
1015 s_object_remove_attrib_in_object (toplevel, o_pin, new_attrib_name);
1018 /* ------- Four cases to consider: Case 3: No old attrib, new one exists. ----- */
1019 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
1020 /* add new attrib to pin. */
1022 #if DEBUG
1023 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
1024 new_attrib_name, new_attrib_value);
1025 #endif
1027 s_object_add_pin_attrib_to_object (toplevel,
1028 o_pin,
1029 new_attrib_name,
1030 new_attrib_value);
1032 /* ------- Four cases to consider: Case 4 ----- */
1033 } else {
1034 /* Do nothing. */
1035 #if DEBUG
1036 printf("In s_toplevel_update_pin_attribs_in_toplevel, nothing needs to be done.\n");
1037 #endif
1040 /* free everything and iterate */
1041 g_free(new_name_value_pair);
1042 g_free(new_attrib_name);
1043 g_free(new_attrib_value);
1044 g_free(old_attrib_value);
1045 local_list = local_list->next;
1046 } /* while (local_list != NULL) */
1048 return;