gsch2pcb: Make --m4-file and -m4-pcbdir arguments work again.
[geda-gaf/peter-b.git] / gattrib / src / s_toplevel.c
blob68a122169fd63e1e0bc191a00306636053c71b14
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"
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 * toplevel structure.
60 * \param toplevel TOPLEVEL structure
61 * \param filename file to be opened
62 * \returns 1 on success, 0 on failure
64 int s_toplevel_read_page(TOPLEVEL *toplevel, char *filename)
66 int file_return_code;
67 GError *err = NULL;
69 /* Set the new filename */
70 toplevel->page_current->page_filename = g_strdup(filename);
72 /* read in and fill out toplevel using f_open and its callees */
73 file_return_code = f_open (toplevel, toplevel->page_current, filename, &err);
75 /* If an error occurred, print message */
76 if (err != NULL) {
77 g_warning ("%s", err->message);
78 g_error_free (err);
81 return file_return_code;
85 /*! \brief Verify the entire design
87 * This function loops through all components in the
88 * design looking for components which are placeholders.
90 * Placeholders are inserted into the object list when
91 * no symbol file is found. If this function finds a
92 * placeholder, it warns the user.
94 * \param toplevel pointer to the toplevel object to be verified
96 void s_toplevel_verify_design (TOPLEVEL *toplevel)
98 GList *p_iter;
99 const GList *o_iter;
101 int missing_sym_flag = 0;
103 for (p_iter = geda_list_get_glist (toplevel->pages);
104 p_iter != NULL;
105 p_iter = g_list_next (p_iter)) {
106 PAGE *p_current = p_iter->data;
108 for (o_iter = s_page_objects (p_current);
109 o_iter != NULL;
110 o_iter = g_list_next (o_iter)) {
111 OBJECT *o_current = o_iter->data;
113 /* --- look for object, and verify that it has a symbol file attached. ---- */
114 if (o_current->type == OBJ_PLACEHOLDER) {
115 missing_sym_flag = 1; /* flag to signal that problem exists. */
120 if (missing_sym_flag) {
121 x_dialog_missing_sym(); /* dialog gives user option to quit */
125 /*------------------------------------------------------------------*/
126 /*! \brief Copy data from gtksheet into TOPLEVEL struct
128 * Called when the user invokes "save". It first
129 * places all data from gtksheet into SHEET_DATA. Then it
130 * loops through all pages & calls s_toplevel_sheetdata_to_toplevel()
131 * to place all
132 * stuff in SHEET_DATA into the libgeda TOPLEVEL structure.
134 void
135 s_toplevel_gtksheet_to_toplevel(TOPLEVEL *toplevel)
137 GList *iter;
138 PAGE *p_current;
140 #if DEBUG
141 printf("--------------------- Entering s_toplevel_gtksheet_to_toplevel -------------------\n");
142 #endif
144 s_sheet_data_gtksheet_to_sheetdata(); /* read data from gtksheet into SHEET_DATA */
145 #if DEBUG
146 printf("In s_toplevel_gtksheet_to_toplevel -- done writing stuff from gtksheet into SHEET_DATA.\n");
147 #endif
149 /* must iterate over all pages in design */
150 for ( iter = geda_list_get_glist( toplevel->pages );
151 iter != NULL;
152 iter = g_list_next( iter ) ) {
154 p_current = (PAGE *)iter->data;
155 toplevel->page_current = p_current;
156 /* only traverse pages which are toplevel */
157 if (p_current->page_control == 0) {
158 s_toplevel_sheetdata_to_toplevel (toplevel, p_current); /* adds all objects from page */
162 #if DEBUG
163 printf("In s_toplevel_gtksheet_to_toplevel -- done writing SHEEET_DATA text back into pr_currnet.\n");
164 #endif
166 return;
171 /*------------------------------------------------------------------*/
172 /*! \brief Add a new attribute to the top level
174 * This function gets called when the user has entered a new attrib name,
175 * and clicked the OK button. It does this:
176 * -# It figures out which attrib/sheet is being added to
177 * -# It destroys the old table in preparation for the new attrib.
178 * -# It adds the new attrib to the master lists.
179 * -# It creates a new table with the new attrib.
180 * -# It then adds the appropriate col to the gtksheet.
181 * \param new_attrib_name attribute to be added
183 void s_toplevel_add_new_attrib(gchar *new_attrib_name) {
184 gint cur_page; /* current page in notbook */
185 gint old_comp_attrib_count;
187 if (strcmp(new_attrib_name, "_cancel") == 0) {
188 return; /* user pressed cancel or closed window with no value in entry */
191 /* Next must figure out which sheet the attrib belongs to. */
192 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
193 #ifdef DEBUG
194 printf("In s_toplevel_add_new_attrib, adding new attrib to page %d.\n",
195 cur_page);
196 #endif
198 switch (cur_page) {
199 case 0: /* component attribute */
201 /* Eventually, I want to just resize the table to accomodate the
202 * new attrib. However, that is difficult. Therefore, I will just
203 * destroy the old table and recreate it for now. */
206 s_table_destroy(sheet_head->component_table,
207 sheet_head->comp_count, sheet_head->comp_attrib_count);
209 old_comp_attrib_count = sheet_head->comp_attrib_count;
210 #ifdef DEBUG
211 printf("In s_toplevel_add_new_attrib, before adding new comp attrib.\n");
212 printf(" comp_attrib_count = %d\n", old_comp_attrib_count);
213 #endif
215 s_string_list_add_item(sheet_head->master_comp_attrib_list_head,
216 &(sheet_head->comp_attrib_count),
217 new_attrib_name);
218 s_string_list_sort_master_comp_attrib_list();
220 #ifdef DEBUG
221 printf("In s_toplevel_add_new_attrib, just updated comp_attrib string list.\n");
222 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
223 #endif
225 /* Now create new table */
226 /* sheet_head->component_table = s_table_new(sheet_head->comp_count,
227 sheet_head->comp_attrib_count);
230 /* resize table to accomodate new attrib col */
231 sheet_head->component_table =
232 s_table_resize(sheet_head->component_table,
233 sheet_head->comp_count,
234 old_comp_attrib_count, sheet_head->comp_attrib_count);
236 #ifdef DEBUG
237 printf("In s_toplevel_add_new_attrib, just resized component table.\n");
238 #endif
240 /* Fill out new sheet with new stuff from gtksheet */
241 gtk_sheet_insert_columns(GTK_SHEET(sheets[0]), sheet_head->comp_attrib_count, 1);
242 x_gtksheet_add_col_labels(GTK_SHEET(sheets[0]),
243 sheet_head->comp_attrib_count,
244 sheet_head->master_comp_attrib_list_head);
246 #ifdef DEBUG
247 printf("In s_toplevel_add_new_attrib, just updated gtksheet.\n");
248 #endif
250 break;
252 case 1: /* net attribute */
253 /* insert into net attribute list */
254 break;
256 case 2: /* pin attribute */
257 /* insert into pin attribute list */
258 break;
259 } /* switch */
261 return;
265 /*------------------------------------------------------------------*/
266 /*! \brief Delete an attribute column
268 * This function gets called when the user has selected a single attrib
269 * column, selected the edit->delete attrib item from the pull-down
270 * menu, and then said "yes" to the confirm dialog.
272 void s_toplevel_delete_attrib_col() {
273 gint cur_page; /* current page in notbook */
274 gint mincol, maxcol;
275 GtkSheet *sheet;
276 gchar *attrib_name;
278 /* Repeat previous checks */
279 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
280 sheet = GTK_SHEET(sheets[cur_page]);
281 if (sheet == NULL) {
282 return;
284 mincol = x_gtksheet_get_min_col(sheet);
285 maxcol = x_gtksheet_get_max_col(sheet);
286 if ( (mincol != maxcol) || (mincol == -1) || (maxcol == -1) ) {
287 return;
290 #ifdef DEBUG
291 printf("In s_toplevel_delete_attrib_col, checks were OK, now do real work\n");
292 #endif
294 /* Rebuild the gattrib-specific data structures */
295 switch (cur_page) {
297 case 0: /* component attribute */
299 /* Eventually, I want to just resize the table after deleting the
300 * attrib. However, that is difficult. Therefore, I will just
301 * destroy the old table and recreate it for now. */
303 s_table_destroy(sheet_head->component_table,
304 sheet_head->comp_count, sheet_head->comp_attrib_count);
306 /* Get name (label) of the col to delete from the gtk sheet */
307 attrib_name = g_strdup( gtk_sheet_column_button_get_label(sheet, mincol) );
309 if (attrib_name != NULL) {
310 #ifdef DEBUG
311 printf("In s_toplevel_delete_attrib_col, attrib to delete = %s\n", attrib_name);
312 #endif
313 } else {
314 fprintf(stderr, "In s_toplevel_delete_attrib_col, can't get attrib name\n");
315 return;
318 #ifdef DEBUG
319 printf("In s_toplevel_delete_attrib_col, before deleting comp attrib.\n");
320 printf(" comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
321 #endif
322 s_string_list_delete_item(&(sheet_head->master_comp_attrib_list_head),
323 &(sheet_head->comp_attrib_count),
324 attrib_name);
325 s_string_list_sort_master_comp_attrib_list(); /* this renumbers list also */
326 g_free(attrib_name);
328 #ifdef DEBUG
329 printf("In s_toplevel_delete_attrib_col, just updated comp_attrib string list.\n");
330 printf(" new comp_attrib_count = %d\n", sheet_head->comp_attrib_count);
331 #endif
333 /* Now create new table with new attrib count*/
334 sheet_head->component_table = s_table_new(sheet_head->comp_count,
335 sheet_head->comp_attrib_count);
338 #ifdef DEBUG
339 printf("In s_toplevel_delete_attrib_col, just updated SHEET_DATA info.\n");
340 #endif
341 break;
343 case 1: /* net attribute */
344 /* insert into net attribute list */
345 break;
347 case 2: /* pin attribute */
348 /* insert into pin attribute list */
349 break;
350 } /* switch */
353 /* Delete col on gtksheet */
354 #ifdef DEBUG
355 printf("In s_toplevel_delete_attrib_col, about to delete col in gtksheet.\n");
356 #endif
357 gtk_sheet_delete_columns (sheet, mincol, 1);
358 #ifdef DEBUG
359 printf("In s_toplevel_delete_attrib_col, done deleting col in gtksheet.\n");
360 #endif
362 sheet_head->CHANGED = TRUE; /* Set changed flag so user is prompted when exiting */
364 return;
368 /* ======================= Private functions ====================== */
370 /*------------------------------------------------------------------*/
371 /*! \brief Copy SHEET_DATA content to TOP_LEVEL
373 * This function
374 * loops through all objects on (PAGE page)->(OBJECT *start_obj).
375 * It takes the updated SHEET_DATA->TABLE data and then updates the
376 * objects with the new attribs & attrib values.
377 * For each component, it updates the attached
378 * attrib values using the updated values held in the SHEET_DATA->TABLE
379 * structure. It does so in three steps:
380 * -# First find and update component attribs.
381 * -# Then find and update net attribs.
382 * -# Finally find and update pin attribs.
383 * \param toplevel TOPLEVEL structure
384 * \param page schematic page to copy
386 void
387 s_toplevel_sheetdata_to_toplevel (TOPLEVEL *toplevel, PAGE *page)
389 GList *copy_list;
390 GList *o_iter, *prim_iter;
391 char *temp_uref;
392 STRING_LIST *new_comp_attrib_pair_list;
393 STRING_LIST *new_pin_attrib_list;
395 /* ----- First deal with all components on the page. ----- */
396 #ifdef DEBUG
397 printf("----- In s_toplevel_sheetdata_to_toplevel, handling components\n");
398 #endif
400 /* Work from a copy list, as objects can be deleted
401 * from the list during iteration over the list.
403 /* NB: g_list_copy doesn't declare its input const, so we cast */
404 copy_list = g_list_copy ((GList *)s_page_objects (page));
406 /* Iterate backwards since attributes are attached after their
407 * parent objects in the list. Attributes can get deleted during
408 * the iteration.
410 for (o_iter = g_list_last (copy_list);
411 o_iter != NULL;
412 o_iter = g_list_previous (o_iter)) {
413 OBJECT *o_current = o_iter->data;
415 /* ------- Object is a component. Handle component attributes. ------- */
416 if (o_current->type == OBJ_COMPLEX) { /* Note that OBJ_COMPLEX = component + attribs */
418 #if 0
419 if (o_attrib_search_object_attribs_by_name (o_current, "graphical", 0)) {
420 break; /* Ignore graphical components */
422 #endif
424 temp_uref = s_attrib_get_refdes(o_current);
425 if (temp_uref != NULL) {
426 /* Must create a name=value pair list for each particular component
427 * which we can pass to function updating o_current. This function
428 * places all attribs
429 * found in the row into new_comp_attrib_pair_list. */
430 new_comp_attrib_pair_list = s_table_create_attrib_pair(temp_uref,
431 sheet_head->component_table,
432 sheet_head->master_comp_list_head,
433 sheet_head->comp_attrib_count);
436 /* Now update attribs in toplevel using this list. */
437 s_toplevel_update_component_attribs_in_toplevel(toplevel,
438 o_current,
439 new_comp_attrib_pair_list);
441 g_free(temp_uref);
442 } else {
443 #ifdef DEBUG
444 printf("In s_toplevel_sheetdata_to_toplevel, found complex with no refdes. name = %s\n",
445 o_current->name);
446 #endif
448 } /* if (o_current->type == OBJ_COMPLEX) */
452 g_list_free (copy_list);
454 #if 0
455 /* ----- Next deal with all nets on the page. ----- */
456 /* This is TBD */
458 #endif
461 /* ----- Finally deal with all pins on the page. ----- */
462 /* ----- Next deal with all nets on the page. ----- */
463 #ifdef DEBUG
464 printf("----- In s_toplevel_sheetdata_to_toplevel, handling pins\n");
465 #endif
467 /* Work from a copy list in case objects are
468 * deleted from the list during its iteration.
470 /* NB: g_list_copy doesn't declare its input const, so we cast */
471 copy_list = g_list_copy ((GList *)s_page_objects (page));
473 for (o_iter = g_list_last (copy_list);
474 o_iter != NULL;
475 o_iter = g_list_previous (o_iter)) {
476 OBJECT *o_current = o_iter->data;
478 /* ------- Object is a complex. Handle pins by looking ------ */
479 /* ------- for all pins attached to a component. ------ */
480 if (o_current->type == OBJ_COMPLEX) {
481 /* Upon finding a component, here's what to do:
482 * 0. Get refdes of component.
483 * 1. Loop over prim_objects, looking for pins.
484 * 2. When a pin is found, create refdes:pinnumber pair
485 * used in searching TABLE.
486 * 3. Search TABLE using refdes:pinnumber as key, and get list of
487 * attribs corresponding to this refdes:pinnumber
488 * 4. Stick the attribs into the TOPLEVEL data structure.
490 temp_uref = s_attrib_get_refdes(o_current);
491 if ( (temp_uref != NULL) && (o_current->complex->prim_objs) ) { /* make sure object complex has a refdes */
493 for (prim_iter = o_current->complex->prim_objs;
494 prim_iter != NULL;
495 prim_iter = g_list_next (prim_iter)) {
496 OBJECT *comp_prim_obj = prim_iter->data;
498 if (comp_prim_obj->type == OBJ_PIN) {
499 new_pin_attrib_list =
500 s_toplevel_get_pin_attribs_in_sheet (temp_uref, comp_prim_obj);
501 s_toplevel_update_pin_attribs_in_toplevel (toplevel,
502 temp_uref,
503 comp_prim_obj,
504 new_pin_attrib_list);
507 } /* if(temp_uref */
509 g_free(temp_uref);
513 g_list_free (copy_list);
515 return;
519 /*------------------------------------------------------------------*/
520 /*! \brief Get the component attributes from the top level
522 * This function returns a list of attributes attached to obj_name = comp
523 * refdes or netlist.
524 * \param refdes component refdes to return values from
525 * \returns a STRING_LIST where the data field holds a name=value string.
527 STRING_LIST *s_toplevel_get_component_attribs_in_sheet(char *refdes)
529 STRING_LIST *new_attrib_list;
530 STRING_LIST *local_attrib_list;
531 int i;
532 int row = -1;
533 int count = 0;
534 char *name_value_pair;
535 char *new_attrib_value;
536 char *new_attrib_name;
538 #if DEBUG
539 printf("----- Entering s_toplevel_get_component_attribs_in_sheet.\n");
540 #endif
543 /* First find pos of this refdes in the master list */
544 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
546 /* Sanity check */
547 if (row == -1) {
548 /* we didn't find the item in the list */
549 fprintf(stderr,
550 "In s_toplevel_get_component_attribs_in_sheet, we didn't find the refdes in the master list!\n");
551 return NULL;
554 /* Now get all attribs associated with this refdes (in TABLE, indexed
555 * by position), and insert them into new_attrib_list. */
556 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
558 i = 0;
559 local_attrib_list = sheet_head->master_comp_attrib_list_head;
560 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
561 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
563 if ( ((sheet_head->component_table)[row][i]).attrib_value ) {
564 new_attrib_value = g_strdup( ((sheet_head->component_table)[row][i]).attrib_value );
565 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
566 g_free(new_attrib_value);
567 } else {
568 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
570 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
571 g_free(new_attrib_name);
572 g_free(name_value_pair);
574 /* Sanity check */
575 if (count != i+1) {
576 /* for some reason, we have lost a name_value_pair somewhere . . . */
577 fprintf(stderr,
578 "In s_toplevel_get_component_attribs_in_sheet, count != i! Exiting . . . .\n");
579 exit(-1);
582 /* iterate */
583 i++;
584 local_attrib_list = local_attrib_list->next;
585 } /* while (local_attrib_list != NULL) */
587 return new_attrib_list;
592 /*------------------------------------------------------------------*/
593 /*! \brief Update component attributes in TOP_LEVEL
595 * For each attrib string attached to the component, update it using the value
596 * held in new_comp_attrib_list. Algorithm:
597 * -# Form list of all component attribs held on both the component
598 * (o_current), as well as in the attrib list (SHEET_DATA).
599 * -# Loop over name=value pairs held in complete_comp_attrib_list.
600 * -# For each name=value pair, look for corresponding attrib on o_current.
601 * -# For each name=value pair, look for the corresponding attrib in
602 * new_comp_attrib_list.
603 * -# If the attrib exists on o_current and in new_comp_attrib_list, write the
604 * new value (from new_comp_attrib_list) into o_current.
605 * -# If the attrib exists on o_current, but is null in name=value pair,
606 * delete the attrib from o_current.
607 * -# If the attribs doesn't exist on o_current, but is non-null in
608 * the name=value pair, create an attrib object and add it to the part
609 * on o_current.
610 * \param toplevel TOPLEVEL structure
611 * \param o_current Component (complex) to be updated.
612 * \param new_comp_attrib_list list of name=value attribute pairs
613 * from SHEET_DATA.
615 void
616 s_toplevel_update_component_attribs_in_toplevel (
617 TOPLEVEL *toplevel,
618 OBJECT *o_current,
619 STRING_LIST *new_comp_attrib_list)
621 STRING_LIST *local_list;
622 STRING_LIST *complete_comp_attrib_list;
623 char *old_name_value_pair;
624 char *new_attrib_name;
625 char *new_attrib_value;
626 char *old_attrib_name;
627 char *old_attrib_value;
628 gchar *refdes;
629 GList *a_iter;
630 OBJECT *a_current;
631 int count = 0; /* This is to fake out a function called later */
632 gint row, col;
633 gint visibility = 0;
634 gint show_name_value = 0;
636 #if DEBUG
637 printf("----- Entering s_toplevel_update_component_attribs_in_toplevel.\n");
638 #endif
641 * To remove dead attribs from o_current, we need to form a complete list of unique
642 * attribs by taking the union of the new attribs from the SHEET_DATA, and
643 * the old attribs living on o_current. That's what we're doing here.
644 * Later, we can delete those attribs in o_current which don't apear in
645 * new_comp_attrib_list.
647 /* First duplicate new_comp_attrib_list */
648 complete_comp_attrib_list = s_string_list_duplicate_string_list(new_comp_attrib_list);
650 /* Now create a complete list of unique attribute names. This will be used in
651 * the loop below when updating attributes. */
652 a_iter = o_current->attribs;
653 while (a_iter != NULL) {
654 a_current = a_iter->data;
655 if (a_current->type == OBJ_TEXT
656 && a_current->text != NULL) { /* found a name=value attribute pair. */
657 /* may need to check more thoroughly here. . . . */
658 old_name_value_pair = g_strdup(a_current->text->string);
660 /* Else clause is suggestion from Ales */
661 #if 1
662 old_attrib_name = u_basic_breakup_string(old_name_value_pair, '=', 0);
663 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
664 (strcmp(old_attrib_name, "net") != 0) &&
665 (strcmp(old_attrib_name, "slot") != 0) &&
666 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
667 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
669 #else
670 /* might now compile now, but this #if'd out branch isn't being built */
671 gint status;
672 status = o_attrib_get_name_value (a_current, &old_attrib_name, &old_attrib_value);
673 if (status == 0) {
674 /* Don't put "refdes" or "slot" into list. Don't put old name=value pair into list if a new
675 * one is already in there. */
676 if ( (strcmp(old_attrib_name, "refdes") != 0) &&
677 (strcmp(old_attrib_name, "net") != 0) &&
678 (strcmp(old_attrib_name, "slot") != 0) &&
679 (s_attrib_name_in_list(new_comp_attrib_list, old_attrib_name) == FALSE) ) {
680 s_string_list_add_item(complete_comp_attrib_list, &count, old_name_value_pair);
682 g_free (old_attrib_name);
683 g_free (old_attrib_value);
685 #endif
686 g_free(old_name_value_pair);
687 g_free(old_attrib_name);
689 a_iter = g_list_next (a_iter);
690 } /* while (a_current != NULL) */
694 *Now the main business of this function: updating the attribs attached to this o_current.
695 * Loop on name=value pairs held in complete_comp_attrib_list , and then use this to get the
696 * name=value pairs out of new_comp_attrib_list and from o_current.
699 /* First handle a special case: the component has no attribs (beside refdes). */
700 if (complete_comp_attrib_list->data == NULL)
701 return;
703 /* Now the normal case. . . . */
704 local_list = complete_comp_attrib_list;
705 while (local_list != NULL) {
707 #if DEBUG
708 printf("\n\n");
709 printf(" In s_toplevel_update_component_attribs_in_toplevel, handling entry in complete list %s .\n",
710 local_list->data);
711 #endif
713 /* Now get the old attrib name & value from complete_comp_attrib_list
714 * and value from o_current */
715 old_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
716 old_attrib_value = o_attrib_search_attached_attribs_by_name (o_current, old_attrib_name, 0);
718 #if DEBUG
719 printf(" In s_toplevel_update_component_attribs_in_toplevel, old name = \"%s\" .\n",
720 old_attrib_name);
721 printf(" In s_toplevel_update_component_attribs_in_toplevel, old value = \"%s\" .\n",
722 old_attrib_value);
723 #endif
725 /* Next try to get this attrib from new_comp_attrib_list */
726 new_attrib_name = u_basic_breakup_string(local_list->data, '=', 0);
727 if (s_string_list_in_list(new_comp_attrib_list, local_list->data)) {
728 new_attrib_value = s_misc_remaining_string(local_list->data, '=', 1);
729 } else {
730 new_attrib_value = NULL;
732 #if DEBUG
733 printf(" In s_toplevel_update_component_attribs_in_toplevel, new name = \"%s\" .\n",
734 new_attrib_name);
735 printf(" In s_toplevel_update_component_attribs_in_toplevel, new value = \"%s\" .\n",
736 new_attrib_value);
737 #endif
739 /* Now get row and col where this new attrib lives. Then get
740 * visibility of the new attrib stored in the component table */
741 /* We'll need this later */
742 refdes = g_strdup(s_attrib_get_refdes(o_current));
743 row = s_table_get_index(sheet_head->master_comp_list_head, refdes);
744 col = s_table_get_index(sheet_head->master_comp_attrib_list_head, new_attrib_name);
745 /* if attribute has been deleted from the sheet, here is where we detect that */
746 if ( (row == -1) || (col == -1) ) {
747 new_attrib_value = NULL; /* attrib will be deleted below */
748 } else { /* we need a better place to get this info since the TABLE can be out of date */
749 visibility = sheet_head->component_table[row][col].visibility;
750 show_name_value = sheet_head->component_table[row][col].show_name_value;
752 g_free(refdes);
755 /* ------- Four cases to consider: Case 1 ----- */
756 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
757 /* simply write new attrib into place of old one. */
758 #if DEBUG
759 printf(" -- In s_toplevel_update_component_attribs_in_toplevel,\n");
760 printf(" about to replace old attrib with name= %s, value= %s\n",
761 new_attrib_name, new_attrib_value);
762 printf(" visibility = %d, show_name_value = %d.\n",
763 visibility, show_name_value);
764 #endif
765 s_object_replace_attrib_in_object(toplevel,
766 o_current,
767 new_attrib_name,
768 new_attrib_value,
769 visibility,
770 show_name_value);
773 /* ------- Four cases to consider: Case 2 ----- */
774 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
775 /* remove attrib from component*/
776 #if DEBUG
777 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
778 old_attrib_name, old_attrib_value);
779 #endif
780 s_object_remove_attrib_in_object (toplevel, o_current, old_attrib_name);
783 /* ------- Four cases to consider: Case 3 ----- */
784 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
785 /* add new attrib to component. */
787 #if DEBUG
788 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
789 new_attrib_name, new_attrib_value);
790 #endif
792 s_object_add_comp_attrib_to_object (toplevel,
793 o_current,
794 new_attrib_name,
795 new_attrib_value,
796 visibility,
797 show_name_value);
799 /* ------- Four cases to consider: Case 4 ----- */
800 } else {
801 /* Do nothing. */
802 #if DEBUG
803 printf(" -- In s_toplevel_update_component_attribs_in_toplevel, nothing needs to be done.\n");
804 #endif
807 /* Toggle attribute visibility and name/value setting */
810 /* free everything and iterate */
811 g_free(new_attrib_name);
812 g_free(new_attrib_value);
813 g_free(old_attrib_name);
814 g_free(old_attrib_value);
815 local_list = local_list->next;
816 } /* while (local_list != NULL) */
817 return;
821 /*------------------------------------------------------------------*/
823 * \todo Function doesn't do anything - candidate for removal?
825 STRING_LIST *s_toplevel_get_net_attribs_in_sheet(char *netname)
827 /* must be filled in */
828 return NULL;
832 /*------------------------------------------------------------------*/
834 * \todo Function doesn't do anything - candidate for removal?
836 void s_toplevel_update_net_attribs_in_toplevel(OBJECT *o_current,
837 STRING_LIST *new_net_attrib_list)
839 /* must be filled in */
840 return;
844 /*------------------------------------------------------------------*/
845 /*! \brief Get pin attributes
847 * This function takes a pointer to the OBJECT pin, and returns a list
848 * of attribs found attached to the pin. The returned list is a
849 * STRING_LIST where the ->data holds a name=value string.
850 * The algorithm is as follows:
851 * -# Form refdes:pinnumber label for this pin.
852 * -# Get row number of this refdes:pinnumber
853 * -# Create a list of name=value pairs from entries in the pin_table
854 * on this row.
855 * -# Return list of name=value pairs found.
857 * \param refdes Ref des string
858 * \param pin Pin object
859 * \returns name=value pair as a STRING_LIST
861 STRING_LIST *s_toplevel_get_pin_attribs_in_sheet(char *refdes, OBJECT *pin)
863 STRING_LIST *new_attrib_list;
864 STRING_LIST *local_attrib_list;
865 int i;
866 int row = -1;
867 int count = 0;
868 char *pinnumber;
869 char *row_label;
870 char *name_value_pair;
871 char *new_attrib_value;
872 char *new_attrib_name;
874 #if DEBUG
875 printf("----- Entering s_toplevel_get_pin_attribs_in_sheet.\n");
876 #endif
878 /* First find pos of this pin in the master pin list */
879 /* first convert refdes, pin to refdes:pinno text string. Then call table_get_index. */
881 pinnumber = o_attrib_search_object_attribs_by_name (pin, "pinnumber", 0);
883 if ( (refdes != NULL) && (pinnumber != NULL) ) {
884 row_label = g_strconcat(refdes, ":", pinnumber, NULL);
885 } else {
886 fprintf(stderr,
887 "In s_toplevel_get_pin_attribs_in_sheet, either refdes or pinnumber of object missing!\n");
888 return NULL;
890 row = s_table_get_index(sheet_head->master_pin_list_head, row_label);
892 /* Sanity check */
893 if (row == -1) {
894 /* we didn't find the item in the list */
895 fprintf(stderr,
896 "In s_toplevel_get_pin_attribs_in_sheet, we didn't find the refdes:pin in the master list!\n");
897 return NULL;
900 /* Now get all attribs associated with this refdes (in TABLE, indexed
901 * by position), and insert them into new_attrib_list. */
902 new_attrib_list = s_string_list_new(); /* init new_attrib_list */
904 i = 0;
905 local_attrib_list = sheet_head->master_pin_attrib_list_head;
906 while (local_attrib_list != NULL) { /* iterate over all possible attribs */
907 new_attrib_name = g_strdup(local_attrib_list->data); /* take attrib name from column headings */
909 if ( ((sheet_head->pin_table)[row][i]).attrib_value ) {
910 new_attrib_value = g_strdup( ((sheet_head->pin_table)[row][i]).attrib_value );
911 name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
912 g_free(new_attrib_value);
913 } else {
914 name_value_pair = g_strconcat(new_attrib_name, "=", NULL); /* empty attrib */
916 s_string_list_add_item(new_attrib_list, &count, name_value_pair); /* add name=value to new list */
917 g_free(new_attrib_name);
918 g_free(name_value_pair);
920 /* Sanity check */
921 if (count != i+1) {
922 /* for some reason, we have lost a name_value_pair somewhere . . . */
923 fprintf(stderr,
924 "In s_toplevel_get_pin_attribs_in_sheet, count != i! Exiting . . . .\n");
925 exit(-1);
928 /* iterate */
929 i++;
930 local_attrib_list = local_attrib_list->next;
931 } /* while (local_attrib_list != NULL) */
933 return new_attrib_list;
938 /*------------------------------------------------------------------*/
939 /*! \brief Update pin attributes in toplevel
941 * For each attrib string attached to the pin, update it using the value
942 * held in new_pin_attrib_list. Algorithm:
943 * -# Loop over name=value pairs held in new_pin_attrib_list.
944 * -# For each name=value pair, look for corresponding attrib on pin.
945 * -# If the attrib exists on pin and in name=value pair, write the
946 * new value in.
947 * -# If the attrib exists on pin, but is null in name=value pair,
948 * delete the attrib.
949 * -# If the attribs doesn't exist on pin, but is non-null in
950 * the name=value pair, create an attrib object and add it to the pin.
951 * \param toplevel TOPLEVEL structure
952 * \param refdes Unused - needs refactored out
953 * \param [in,out] o_pin pin to update
954 * \param [in] new_pin_attrib_list New pin attribute list to apply
956 void
957 s_toplevel_update_pin_attribs_in_toplevel (TOPLEVEL *toplevel,
958 char *refdes,
959 OBJECT *o_pin,
960 STRING_LIST *new_pin_attrib_list)
962 STRING_LIST *local_list;
963 char *new_name_value_pair;
964 char *new_attrib_name;
965 char *new_attrib_value;
966 char *old_attrib_value;
968 #if DEBUG
969 printf("----- Entering s_toplevel_update_pin_attribs_in_toplevel.\n");
970 #endif
972 /* loop on name=value pairs held in new_pin_attrib_list */
973 local_list = new_pin_attrib_list;
974 while (local_list != NULL) {
975 new_name_value_pair = g_strdup(local_list->data);
976 #if DEBUG
977 printf(" In s_toplevel_update_pin_attribs_in_toplevel, handling entry in master list %s .\n", new_name_value_pair);
978 #endif
980 new_attrib_name = u_basic_breakup_string(new_name_value_pair, '=', 0);
981 new_attrib_value = u_basic_breakup_string(new_name_value_pair, '=', 1);
983 if (strlen(new_attrib_value) == 0) {
984 g_free(new_attrib_value);
985 new_attrib_value = NULL; /* s_misc_remaining_string doesn't return NULL for empty substring. */
987 old_attrib_value = o_attrib_search_attached_attribs_by_name (o_pin, new_attrib_name, 0);
989 /* ------- Four cases to consider: Case 1: old and new attribs exist ----- */
990 if ( (old_attrib_value != NULL) && (new_attrib_value != NULL) && (strlen(new_attrib_value) != 0) ) {
991 /* simply write new attrib into place of old one. */
992 #if DEBUG
993 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to replace old attrib with new one: name= %s, value= %s\n",
994 new_attrib_name, new_attrib_value);
995 #endif
996 s_object_replace_attrib_in_object(toplevel,
997 o_pin,
998 new_attrib_name,
999 new_attrib_value,
1000 LEAVE_VISIBILITY_ALONE,
1001 LEAVE_NAME_VALUE_ALONE);
1004 /* ------- Four cases to consider: Case 2: old attrib exists, new one doesn't ----- */
1005 else if ( (old_attrib_value != NULL) && (new_attrib_value == NULL) ) {
1006 /* remove attrib from pin */
1007 #if DEBUG
1008 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to remove old attrib with name= %s, value= %s\n",
1009 new_attrib_name, old_attrib_value);
1010 #endif
1011 s_object_remove_attrib_in_object (toplevel, o_pin, new_attrib_name);
1014 /* ------- Four cases to consider: Case 3: No old attrib, new one exists. ----- */
1015 else if ( (old_attrib_value == NULL) && (new_attrib_value != NULL) ) {
1016 /* add new attrib to pin. */
1018 #if DEBUG
1019 printf("In s_toplevel_update_pin_attribs_in_toplevel, about to add new attrib with name= %s, value= %s\n",
1020 new_attrib_name, new_attrib_value);
1021 #endif
1023 s_object_add_pin_attrib_to_object (toplevel,
1024 o_pin,
1025 new_attrib_name,
1026 new_attrib_value);
1028 /* ------- Four cases to consider: Case 4 ----- */
1029 } else {
1030 /* Do nothing. */
1031 #if DEBUG
1032 printf("In s_toplevel_update_pin_attribs_in_toplevel, nothing needs to be done.\n");
1033 #endif
1036 /* free everything and iterate */
1037 g_free(new_name_value_pair);
1038 g_free(new_attrib_name);
1039 g_free(new_attrib_value);
1040 g_free(old_attrib_value);
1041 local_list = local_list->next;
1042 } /* while (local_list != NULL) */
1044 return;