Initial import of gattrib 20040806
[geda-gaf/whiteaudio.git] / gattrib / src / s_table.c
blob9076ac40194e71cb66ab548c7069544b7cca7ec6
1 /* gEDA - GPL Electronic Design Automation
2 * gattrib -- gEDA component and net attribute manipulation using spreadsheet.
3 * Copyright (C) 2003 -- 2004 Stuart D. Brorson.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 /*------------------------------------------------------------------
21 * This file holds fcns involved in manipulating the TABLE structure,
22 * which is subsidiary to SHEET_DATA. TABLE is a 2 dimensional array
23 * of structs; each struct corresponds to the data about an element
24 * in a single cell of the spreadsheet.
25 *------------------------------------------------------------------*/
27 #include <config.h>
29 #include <stdio.h>
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #endif
33 #include <math.h>
35 /*------------------------------------------------------------------
36 * Gattrib specific includes
37 *------------------------------------------------------------------*/
38 #include <libgeda/libgeda.h> /* geda library fcns */
39 #include "../include/struct.h" /* typdef and struct declarations */
40 #include "../include/prototype.h" /* function prototypes */
41 #include "../include/globals.h"
43 /* =================== Public Functions ====================== */
45 /*------------------------------------------------------------------
46 * This fcn is the table creator. It returns a pointer to
47 * an initialized TABLE struct. As calling args, it needs
48 * the number of rows and cols to allocate. The table is a
49 * dynamically allocated 2D array of structs. To access data in
50 * a cell in the table, you reference (for example):
51 * ((sheet_data->comp_table)[i][j]).attrib_value
52 * (Parens used only for clarity. It works without parens.)
53 *------------------------------------------------------------------*/
54 TABLE **s_table_new(int rows, int cols)
56 TABLE **new_table;
57 int i, j;
59 /* Here I am trying to create a 2 dimensional array of structs */
60 new_table = (TABLE **) malloc(rows*sizeof(TABLE *));
61 for (i = 0; i < rows; i++) {
62 new_table[i] = (TABLE *) malloc(cols * sizeof(TABLE));
63 /* Note that I should put some checks in here to verify that
64 * malloc worked correctly. */
67 /* Now pre-load the table with NULLs */
68 for (i = 0; i < rows; i++) {
69 for (j = 0; j < cols; j++) {
70 (new_table[i][j]).attrib_value = NULL;
71 (new_table[i][j]).row_name = NULL;
72 (new_table[i][j]).col_name = NULL;
73 (new_table[i][j]).row = i;
74 (new_table[i][j]).col = j;
75 (new_table[i][j]).visibility = 3; /* both name & value visible */
79 return (new_table);
84 /*------------------------------------------------------------------
85 * This fcn destroys the old table. Use it after reading in a new
86 * page to get rid of the old table before building a new one.
87 *------------------------------------------------------------------*/
88 void s_table_destroy(TABLE **table, int row_count, int col_count)
90 int i, j;
91 for (i = 0; i < row_count; i++) {
92 for (j = 0; j < row_count; j++) {
93 free( (table[i][j]).attrib_value );
97 return;
102 /*------------------------------------------------------------------
103 * This fcn returns the index number when given a STRING_LIST and a
104 * string to match. It finds the index
105 * number by iterating through the master list.
106 *------------------------------------------------------------------*/
107 int s_table_get_index(STRING_LIST *local_list, char *local_string) {
108 int count = 0;
109 STRING_LIST *list_element;
111 #ifdef DEBUG
112 printf("In s_table_get_index, examining %s to see if it is in the list.\n", local_string);
113 #endif
116 list_element = local_list;
117 while (list_element != NULL) {
118 if (strcmp(list_element->data, local_string) == 0) {
119 return count;
121 count++;
122 list_element = list_element->next;
124 /* If we are here, it is by mistake */
125 fprintf(stderr, "s_table_get_index passed a string not in master list!.\n");
126 exit(-1);
130 /*------------------------------------------------------------------
131 * This fcn iterates over adds all objects found on this page looking
132 * for components. When it finds a component, it finds all component
133 * attribs and sticks them in the TABLE.
134 *------------------------------------------------------------------*/
135 void s_table_add_toplevel_comp_items_to_comp_table(OBJECT *start_obj) {
136 OBJECT *o_current;
137 gchar *temp;
138 gchar *temp_uref;
139 int row, col;
140 gchar *attrib_text;
141 gchar *attrib_name;
142 gchar *attrib_value;
143 ATTRIB *a_current;
145 if (verbose_mode) {
146 printf("- Starting internal component TABLE creation\n");
149 #ifdef DEBUG
150 fflush(stderr);
151 fflush(stdout);
152 printf("=========== Just entered s_table_add_toplevel_comp_items_to_comp_table! ==============\n");
153 #endif
155 /* ----- Iterate through all objects found on page ----- */
156 o_current = start_obj;
157 while (o_current != NULL) {
159 #ifdef DEBUG
160 printf(" ---> In s_table_add_toplevel_comp_items_to_comp_table, examining o_current->name = %s\n", o_current->name);
161 #endif
163 /* ----- Now process objects found on page ----- */
164 if ( (o_current->type == OBJ_COMPLEX) &&
165 o_current->attribs &&
166 !o_attrib_search_component(o_current, "graphical") ) {
168 /* ---- Don't process part if it lacks a refdes ----- */
169 temp_uref = o_attrib_search_name_single(o_current, "refdes", NULL);
170 if (temp_uref) {
172 #if DEBUG
173 printf(" In s_table_add_toplevel_comp_items_to_comp_table, found component on page. Refdes = %s\n", temp_uref);
174 #endif
175 verbose_print(" C");
177 /* Having found a component, we loop over all attribs in this
178 * component, and stick them
179 * into cells in the table. */
180 a_current = o_current->attribs;
181 while (a_current != NULL) {
182 if (a_current->object->type == OBJ_TEXT
183 && a_current->object->text != NULL) { /* found an attribute */
184 /* may need to check more thoroughly here. . . . */
185 attrib_text = u_basic_strdup(a_current->object->text->string);
186 attrib_name = u_basic_breakup_string(attrib_text, '=', 0);
187 attrib_value = u_basic_breakup_string(attrib_text, '=', 1);
188 if (strcmp(attrib_name, "refdes") != 0) {
189 /* Don't include "refdes" */
191 /* Get row and col where to put this attrib */
192 row = s_table_get_index(sheet_head->master_comp_list_head, temp_uref);
193 col = s_table_get_index(sheet_head->master_comp_attrib_list_head, attrib_name);
194 #if DEBUG
195 printf(" In s_table_add_toplevel_comp_items_to_comp_table, about to add row %d, col %d, attrib_value = %s\n",
196 row, col, attrib_value);
197 printf(" . . . current address of attrib_value cell is [%p]\n", &((sheet_head->component_table)[row][col]).attrib_value);
198 #endif
199 /* Is there a compelling reason for me to put this into a separate fcn? */
200 ((sheet_head->component_table)[row][col]).row = row;
201 ((sheet_head->component_table)[row][col]).col = col;
202 ((sheet_head->component_table)[row][col]).row_name = u_basic_strdup(temp_uref);
203 ((sheet_head->component_table)[row][col]).col_name = u_basic_strdup(attrib_name);
204 ((sheet_head->component_table)[row][col]).attrib_value = u_basic_strdup(attrib_value);
206 free(attrib_name);
207 free(attrib_text);
208 free(attrib_value);
210 a_current = a_current->next;
212 } /* while (a_current != NULL) */
213 free(temp_uref);
214 } /* if (temp_uref) */
215 } /* if (o_current->type == OBJ_COMPLEX) */
217 o_current = o_current->next; /* iterate to next object on page */
219 } /* while o_current != NULL */
221 verbose_done();
226 /*------------------------------------------------------------------
227 * This fcn iterates over adds all items found on this page looking
228 * for nets and adds them individually to the net table. Looping over
229 * objects occurs here.
230 *------------------------------------------------------------------*/
231 void s_table_add_toplevel_net_items_to_net_table(OBJECT *start_obj) {
232 OBJECT *o_current;
233 char *temp_netname;
234 int row, col;
235 char *attrib_text;
236 char *attrib_name;
237 char *attrib_value;
238 ATTRIB *a_current;
240 /* ----- Iterate through all objects found on page ----- */
241 o_current = start_obj;
242 while (o_current != NULL) {
244 /* ----- Now process objects found on page ----- */
245 if (o_current->type == OBJ_NET) {
246 #if DEBUG
247 fflush(stderr);
248 fflush(stdout);
249 printf("In s_table_add_toplevel_net_items_to_net_table, Found net on page\n");
250 #endif
251 verbose_print(" N");
253 /* Having found a net, we stick it into the table. */
254 a_current = o_current->attribs;
255 while (a_current != NULL) {
256 if (a_current->object->type == OBJ_TEXT
257 && a_current->object->text != NULL) { /* found an attribute */
258 /* may need to check more thoroughly here. . . . */
259 attrib_text = u_basic_strdup(a_current->object->text->string);
260 attrib_name = u_basic_breakup_string(attrib_text, '=', 0);
261 attrib_value = u_basic_breakup_string(attrib_text, '=', 1);
262 if (strcmp(attrib_name, "netname") != 0) {
263 /* Don't include "netname" */
265 /* Get row and col where to put this attrib */
266 row = s_table_get_index(sheet_head->master_net_list_head, temp_netname);
267 col = s_table_get_index(sheet_head->master_net_attrib_list_head, attrib_name);
268 #if DEBUG
269 fflush(stderr);
270 fflush(stdout);
271 printf("In s_table_add_toplevel_net_items_to_net_table, about to add row %d, col %d, attrib_value = %s\n",
272 row, col, attrib_value);
273 printf(" . . . current address of attrib_value cell is [%p]\n", &((sheet_head->net_table)[row][col]).attrib_value);
274 #endif
275 /* Is there a compelling reason for me to put this into a separate fcn? */
276 ((sheet_head->net_table)[row][col]).row = row;
277 ((sheet_head->net_table)[row][col]).col = col;
278 ((sheet_head->net_table)[row][col]).row_name = u_basic_strdup(temp_netname);
279 ((sheet_head->net_table)[row][col]).col_name = u_basic_strdup(attrib_name);
280 ((sheet_head->net_table)[row][col]).attrib_value = u_basic_strdup(attrib_value);
282 free(attrib_name);
283 free(attrib_text);
284 free(attrib_value);
286 a_current = a_current->next;
288 } /* while (a_current != NULL) */
289 free(temp_netname);
291 } /*--- if (o_current->type == OBJ_NET) ---*/
294 o_current = o_current->next; /* iterate to next object on page */
295 } /* while o_current != NULL */
297 verbose_done();
299 #if DEBUG
300 fflush(stderr);
301 fflush(stdout);
302 printf("In s_table_add_toplevel_net_items_to_net_table -- we are about to return\n");
303 #endif
309 /*------------------------------------------------------------------
310 * This fcn iterates over adds all items found on this page
311 * looking for pins. WHen it finds a pin, it gathers all
312 * pin attribs and sticks them into the pin table.
313 *------------------------------------------------------------------*/
314 void s_table_add_toplevel_pin_items_to_pin_table(OBJECT *start_obj) {
315 OBJECT *o_current;
316 OBJECT *o_lower_current;;
317 gchar *temp;
318 gchar *temp_uref;
319 gchar *pinnumber;
320 gchar *row_label;
321 int row, col;
322 gchar *attrib_text;
323 gchar *attrib_name;
324 gchar *attrib_value;
325 ATTRIB *pin_attrib;
327 if (verbose_mode) {
328 printf("- Starting internal pin TABLE creation\n");
331 #ifdef DEBUG
332 printf("=========== Just entered s_table_add_toplevel_pin_items_to_pin_table! ==============\n");
333 #endif
335 /* ----- Iterate through all objects found on page ----- */
336 o_current = start_obj;
337 while (o_current != NULL) {
339 #ifdef DEBUG
340 printf(" ---> In s_table_add_toplevel_pin_items_to_pin_table, examining o_current->name = %s\n", o_current->name);
341 #endif
343 /* ----- Now process objects found on page ----- */
344 if ( (o_current->type == OBJ_COMPLEX) &&
345 o_current->attribs &&
346 !o_attrib_search_component(o_current, "graphical") ) {
348 /* ---- Don't process part if it lacks a refdes ----- */
349 temp_uref = o_attrib_search_name_single(o_current, "refdes", NULL);
350 if (temp_uref) {
352 /* ----- Now iterate through lower level objects looking for pins. ----- */
353 o_lower_current = o_current->complex->prim_objs;
354 while (o_lower_current != NULL) {
356 if (o_lower_current->type == OBJ_PIN) {
357 /* ----- Found a pin. First get its pinnumber. then get attrib head and loop on attribs. ----- */
358 pinnumber = o_attrib_search_name_single(o_lower_current, "pinnumber", NULL);
359 row_label = u_basic_strdup_multiple(temp_uref, ":", pinnumber, NULL);
361 #if DEBUG
362 printf(" In s_table_add_toplevel_pin_items_to_pin_table, examining pin %s\n", row_label);
363 #endif
365 pin_attrib = o_lower_current->attribs;
366 while (pin_attrib != NULL) {
367 if (pin_attrib->object->type == OBJ_TEXT
368 && pin_attrib->object->text != NULL) { /* found an attribute */
369 attrib_text = u_basic_strdup(pin_attrib->object->text->string);
370 attrib_name = u_basic_breakup_string(attrib_text, '=', 0);
371 attrib_value = u_basic_breakup_string(attrib_text, '=', 1);
373 if (strcmp(attrib_name, "pinnumber") != 0) {
374 /* Don't include "pinnumber" because it is already in other master list */
376 /* Get row and col where to put this attrib */
377 row = s_table_get_index(sheet_head->master_pin_list_head, row_label);
378 col = s_table_get_index(sheet_head->master_pin_attrib_list_head, attrib_name);
379 #if DEBUG
380 printf(" In s_table_add_toplevel_pin_items_to_pin_table, about to add row %d, col %d, attrib_value = %s\n",
381 row, col, attrib_value);
382 printf(" . . . current address of attrib_value cell is [%p]\n", &((sheet_head->component_table)[row][col]).attrib_value);
383 #endif
384 /* Is there a compelling reason for me to put this into a separate fcn? */
385 ((sheet_head->pin_table)[row][col]).row = row;
386 ((sheet_head->pin_table)[row][col]).col = col;
387 ((sheet_head->pin_table)[row][col]).row_name = u_basic_strdup(row_label);
388 ((sheet_head->pin_table)[row][col]).col_name = u_basic_strdup(attrib_name);
389 ((sheet_head->pin_table)[row][col]).attrib_value = u_basic_strdup(attrib_value);
391 free(attrib_name);
392 free(attrib_text);
393 free(attrib_value);
395 pin_attrib = pin_attrib->next;
397 } /* while (pin_attrib != NULL) */
398 free(pinnumber);
399 free(row_label);
402 o_lower_current = o_lower_current->next;
403 } /* while (o_lower_current != NULL) */
406 free(temp_uref);
409 o_current = o_current->next; /* iterate to next object on page */
411 } /* while o_current != NULL */
413 verbose_done();
417 /*------------------------------------------------------------------
418 * This fcn through the spreadsheet, extracts the attribs from
419 * the cells, and places them back into TABLE. This is the
420 * first step in saving out a project.
421 *------------------------------------------------------------------*/
422 int s_table_gtksheet_to_all_tables() {
424 int num_rows;
425 int num_cols;
426 STRING_LIST *master_row_list;
427 STRING_LIST *master_col_list;
428 TABLE **local_table;
429 GtkSheet *local_gtk_sheet;
431 /* First handle component sheet */
432 num_rows = sheet_head->comp_count;
433 num_cols = sheet_head->comp_attrib_count;
434 local_gtk_sheet = sheets[0];
435 master_row_list = sheet_head->master_comp_list_head;
436 master_col_list = sheet_head->master_comp_attrib_list_head;
437 local_table = sheet_head->component_table;
439 s_table_gtksheet_to_table(local_gtk_sheet, master_row_list,
440 master_col_list, local_table,
441 num_rows, num_cols);
443 #if 0
444 /* Next handle net sheet */
445 num_rows = sheet_head->net_count;
446 num_cols = sheet_head->net_attrib_count;
447 local_gtk_sheet = sheets[1];
448 master_row_list = sheet_head->master_net_list_head;
449 master_col_list = sheet_head->master_net_attrib_list_head;
450 local_table = sheet_head->net_table;
452 s_table_gtksheet_to_table(local_gtk_sheet, master_row_list,
453 master_col_list, local_table,
454 num_rows, num_cols);
455 #endif
457 /* Finally, handle component pin sheet */
458 num_rows = sheet_head->pin_count;
459 num_cols = sheet_head->pin_attrib_count;
460 local_gtk_sheet = sheets[2];
461 master_row_list = sheet_head->master_pin_list_head;
462 master_col_list = sheet_head->master_pin_attrib_list_head;
463 local_table = sheet_head->pin_table;
465 s_table_gtksheet_to_table(local_gtk_sheet, master_row_list,
466 master_col_list, local_table,
467 num_rows, num_cols);
469 return;
473 /* =================== Private Functions ====================== */
474 /*------------------------------------------------------------------
475 * This fcn does the actual heaving lifting of looping
476 * through the spreadsheet, extracting the attribs from
477 * the cells, and placing them back into TABLE. This is the
478 * first step in saving out a project.
479 *------------------------------------------------------------------*/
480 int s_table_gtksheet_to_table(GtkSheet *local_gtk_sheet, STRING_LIST *master_row_list,
481 STRING_LIST *master_col_list, TABLE **local_table,
482 int num_rows, int num_cols)
484 int row, col;
486 STRING_LIST *row_list_item;
487 gchar *row_title;
489 STRING_LIST *col_list_item;
490 gchar *col_title;
492 gchar *attrib_value;
494 row_list_item = master_row_list;
495 for (row = 0; row < num_rows; row++) {
496 row_title = (gchar *) u_basic_strdup(row_list_item->data);
498 col_list_item = master_col_list;
499 for (col = 0; col < num_cols; col++) {
500 col_title = (gchar *) u_basic_strdup(col_list_item->data);
502 /* get value of attrib in cell */
503 attrib_value = (gchar *) gtk_sheet_cell_get_text(GTK_SHEET(local_gtk_sheet), row, col);
505 #if 0
506 if (strlen(attrib_value) == 0) {
507 /* free(attrib_value); */ /* sometimes we have spurious, zero length strings creep */
508 attrib_value = NULL; /* into the GtkSheet */
510 #endif
513 #ifdef DEBUG
514 printf("In s_table_update_table, found attrib_value = %s in cell row=%d, col=%d\n",
515 attrib_value, row, col);
516 #endif
518 /* first handle attrib value in cell */
519 if ( local_table[row][col].attrib_value != NULL) {
520 free( local_table[row][col].attrib_value );
522 if (attrib_value != NULL) {
523 local_table[row][col].attrib_value = (gchar *) u_basic_strdup(attrib_value);
524 } else {
525 local_table[row][col].attrib_value = NULL;
528 /* next handle name of row (also held in TABLE cell) */
529 if ( local_table[row][col].row_name != NULL) {
530 free( local_table[row][col].row_name );
532 if (row_title != NULL) {
533 local_table[row][col].row_name = (gchar *) u_basic_strdup(row_title);
534 } else {
535 local_table[row][col].row_name = NULL;
538 /* finally handle name of col */
539 if ( local_table[row][col].col_name != NULL) {
540 free( local_table[row][col].col_name );
542 if (col_title != NULL) {
543 local_table[row][col].col_name = (gchar *) u_basic_strdup(col_title);
544 } else {
545 local_table[row][col].col_name = NULL;
548 /* get next col list item and then iterate. */
549 col_list_item = col_list_item->next;
552 row_list_item = row_list_item->next;
555 return;