gsch2pcb: Make --m4-file and -m4-pcbdir arguments work again.
[geda-gaf/peter-b.git] / gattrib / src / s_string_list.c
blob2ba4ee2fa7f162bc90887e822827fca4bc6834b3
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 involved in manipulating the STRING_LIST
23 * structure.
25 * This file holds functions involved in manipulating the STRING_LIST
26 * structure. STRING_LIST is basically a linked list of strings
27 * (text).
29 * \todo This could be implemented using an underlying GList
30 * structure. The count parameter could also be eliminated -
31 * either store it in the struct or preferably, calculate it
32 * when needed - I don't think the speed penalty of traversing
33 * the list is significant at all. GDE
36 #include <config.h>
38 #include <stdio.h>
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #include <math.h>
44 /*------------------------------------------------------------------
45 * Gattrib specific includes
46 *------------------------------------------------------------------*/
47 #include <libgeda/libgeda.h> /* geda library fcns */
48 #include "../include/struct.h" /* typdef and struct declarations */
49 #include "../include/prototype.h" /* function prototypes */
50 #include "../include/globals.h"
52 #ifdef HAVE_LIBDMALLOC
53 #include <dmalloc.h>
54 #endif
58 /*------------------------------------------------------------------*/
59 /*! \brief Return a pointer to a new STRING_LIST
61 * Returns a pointer to a new STRING_LIST struct. This list is empty.
62 * \returns pointer to the new STRING_LIST struct.
64 STRING_LIST *s_string_list_new() {
65 STRING_LIST *local_string_list;
67 local_string_list = g_malloc(sizeof(STRING_LIST));
68 local_string_list->data = NULL;
69 local_string_list->next = NULL;
70 local_string_list->prev = NULL;
71 local_string_list->pos = -1; /* can look for this later . . . */
73 return local_string_list;
77 /*------------------------------------------------------------------*/
78 /*! \brief Duplicate a STRING_LIST
80 * Given a STRING_LIST, duplicate it and returns a pointer
81 * to the new, duplicate list.
82 * \param old_string_list pointer to the STRING_LIST to be duplicated
83 * \returns a pointer to the duplicate STRING_LIST
85 STRING_LIST *s_string_list_duplicate_string_list(STRING_LIST *old_string_list) {
86 STRING_LIST *new_string_list;
87 STRING_LIST *local_string_list;
88 char *data;
89 gint count;
91 new_string_list = s_string_list_new();
93 if (old_string_list->data == NULL)
94 /* This is an empty string list */
95 return new_string_list;
97 local_string_list = old_string_list;
98 while (local_string_list != NULL) {
99 data = g_strdup(local_string_list->data);
100 s_string_list_add_item(new_string_list, &count, data);
101 g_free(data);
102 local_string_list = local_string_list->next;
105 return new_string_list;
109 /*------------------------------------------------------------------*/
110 /*! \brief Add an item to a STRING_LIST
112 * Inserts the item into a STRING_LIST.
113 * It first passes through the
114 * list to make sure that there are no duplications.
115 * \param list pointer to STRING_LIST to be added to.
116 * \param count FIXME Don't know what this does - input or output? both?
117 * \param item pointer to string to be added
119 void s_string_list_add_item(STRING_LIST *list, int *count, char *item) {
121 gchar *trial_item = NULL;
122 STRING_LIST *prev;
123 STRING_LIST *local_list;
125 if (list == NULL) {
126 fprintf(stderr, "In s_string_list_add_item, tried to add to a NULL list.\n");
127 return;
130 /* First check to see if list is empty. Handle insertion of first item
131 into empty list separately. (Is this necessary?) */
132 if (list->data == NULL) {
133 #ifdef DEBUG
134 printf("In s_string_list_add_item, about to place first item in list.\n");
135 #endif
136 list->data = (gchar *) g_strdup(item);
137 list->next = NULL;
138 list->prev = NULL; /* this may have already been initialized. . . . */
139 list->pos = *count; /* This enumerates the pos on the list. Value is reset later by sorting. */
140 (*count)++; /* increment count to 1 */
141 return;
144 /* Otherwise, loop through list looking for duplicates */
145 prev = list;
146 while (list != NULL) {
147 trial_item = (gchar *) g_strdup(list->data);
148 if (strcmp(trial_item, item) == 0) {
149 /* Found item already in list. Just return. */
150 g_free(trial_item);
151 return;
153 g_free(trial_item);
154 prev = list;
155 list = list->next;
158 /* If we are here, it's 'cause we didn't find the item pre-existing in the list. */
159 /* In this case, we insert it. */
161 local_list = (STRING_LIST *) g_malloc(sizeof(STRING_LIST)); /* allocate space for this list entry */
162 local_list->data = (gchar *) g_strdup(item); /* copy data into list */
163 local_list->next = NULL;
164 local_list->prev = prev; /* point this item to last entry in old list */
165 prev->next = local_list; /* make last item in old list point to this one. */
166 local_list->pos = *count; /* This enumerates the pos on the list. Value is reset later by sorting. */
167 (*count)++; /* increment count */
168 /* list = local_list; */
169 return;
174 /*------------------------------------------------------------------*/
175 /*! \brief Delete an item from a STRING_LIST
177 * Deletes an item in a STRING_LIST.
178 * \param list pointer to STRING_LIST
179 * \param count pointer to count of items in list
180 * \param item item to remove from list
182 void s_string_list_delete_item(STRING_LIST **list, int *count, gchar *item) {
184 gchar *trial_item = NULL;
185 STRING_LIST *list_item;
186 STRING_LIST *next_item = NULL;
187 STRING_LIST *prev_item = NULL;
189 /* First check to see if list is empty. If empty, spew error and return */
190 if ( (*list)->data == NULL) {
191 fprintf(stderr, "In s_string_list_delete_item, tried to remove item from empty list\n");
192 return;
195 #ifdef DEBUG
196 printf("In s_string_list_delete_item, about to delete item %s from list.\n", item);
197 #endif
199 /* Now loop through list looking for item */
200 list_item = (*list);
201 while (list_item != NULL) {
202 trial_item = (gchar *) g_strdup(list_item->data);
203 #ifdef DEBUG
204 printf("In s_string_list_delete_item, matching item against trial item = %s from list.\n", trial_item);
205 #endif
206 if (strcmp(trial_item, item) == 0) {
207 /* found item, now delete it. */
208 #ifdef DEBUG
209 printf("In s_string_list_delete_item, found match . . . . . \n");
210 #endif
211 prev_item = list_item->prev;
212 next_item = list_item->next;
214 /* Check position in list */
215 if (next_item == NULL && prev_item == NULL) {
216 /* pathological case of one item list. */
217 (*list) = NULL;
218 } else if (next_item == NULL && prev_item != NULL) {
219 /* at list's end */
220 prev_item->next = NULL;
221 } else if (next_item != NULL && prev_item == NULL) {
222 /* at list's beginning */
223 next_item->prev = NULL;
224 (*list) = next_item; /* also need to fix pointer to list head */
225 /* g_free(list); */
226 } else {
227 /* normal case of element in middle of list */
228 prev_item->next = next_item;
229 next_item->prev = prev_item;
232 #ifdef DEBUG
233 printf("In s_string_list_delete_item, now free list_item\n");
234 #endif
235 g_free(list_item); /* free current list item */
236 (*count)--; /* decrement count */
237 /* Do we need to re-number the list? */
239 #ifdef DEBUG
240 printf("In s_string_list_delete_item, now free trial_item\n");
241 #endif
242 g_free(trial_item); /* free trial item before returning */
243 #ifdef DEBUG
244 printf("In s_string_list_delete_item, returning . . . .\n");
245 #endif
246 return;
248 g_free(trial_item);
249 list_item = list_item->next;
252 /* If we are here, it's 'cause we didn't find the item.
253 * Spew error and return.
255 fprintf(stderr, "In s_string_list_delete_item, couldn't delete item %s\n", item);
256 return;
260 /*------------------------------------------------------------------*/
261 /*! \brief Detect item in list
263 * Look for item in the list.
265 * \param list pointer to the STRING_LIST struct
266 * \param item string to search for
267 * \returns 0 if absent, 1 if present
269 int s_string_list_in_list(STRING_LIST *list, char *item) {
271 gchar *trial_item = NULL;
273 /* First check to see if list is empty. If empty, return
274 * 0 automatically. (I probably don't need to handle this
275 * separately.) */
276 if (list->data == NULL) {
277 return 0;
280 /* Otherwise, loop through list looking for duplicates */
281 while (list != NULL) {
282 trial_item = (gchar *) g_strdup(list->data);
283 if (strcmp(trial_item, item) == 0) {
284 /* Found item already in list. return 1. */
285 g_free(trial_item);
286 return 1;
288 g_free(trial_item);
289 list = list->next;
292 /* If we are here, it's 'cause we didn't find the item
293 * pre-existing in the list. In this case, return 0 */
294 return 0;
299 /*------------------------------------------------------------------*/
300 /*! \brief Get an item from a STRING_LIST by index
302 * Returns the index'th item in the string list.
303 * \param list pointer to STRING_LIST to get from
304 * \param index index of item to return
305 * \returns NULL if there is a problem otherwise a pointer to
306 * the string.
308 gchar *s_string_list_get_data_at_index(STRING_LIST *list, gint index)
310 gint i;
311 STRING_LIST *local_item;
313 /* First check to see if list is empty. If empty, return
314 * NULL automatically. */
315 if (list->data == NULL) {
316 return NULL;
319 local_item = list;
320 for (i = 0 ; i < index ; i++) {
321 if (local_item == NULL) {
322 return NULL;
323 } else {
324 local_item = local_item->next;
327 return local_item->data;
331 /*------------------------------------------------------------------*/
332 /*! \brief Sort the master component list
334 * Takes the master comp list
335 * sheet_head->master_comp_list_head
336 * and sorts it in this order:
337 * <all refdeses in alphabetical order>
338 * Right now it does nothing other than fill in the "position"
339 * and "length" variables.
341 void s_string_list_sort_master_comp_list() {
342 int i = 0;
343 STRING_LIST *local_list, *p;
345 /* Here's where we do the sort. The sort is done using a fcn found on the web. */
346 local_list = sheet_head->master_comp_list_head;
347 for (p=local_list; p; p=p->next)
348 p->pos = 0;
349 local_list = listsort(local_list, 0, 1);
351 /* Do this after sorting is done. This resets the order of the individual items
352 * in the list. */
353 while (local_list != NULL) { /* make sure item is not null */
354 local_list->pos = i;
355 if (local_list->next != NULL) {
356 i++;
357 local_list = local_list->next;
358 } else {
359 break; /* leave loop *before* iterating to NULL EOL marker */
363 /* Now go to first item in local list and reassign list head to new first element */
364 while (local_list->prev != NULL) {
365 local_list = local_list->prev;
368 sheet_head->master_comp_list_head = local_list;
370 return;
374 /* This list overrides the alphanumeric sort. Attribs not found in
375 this list are sorted as if they had a value of DEFAULT_ATTRIB_POS
376 within this list, but alphanumerically relative to each other. */
377 static struct {
378 const char *attrib;
379 int pos;
380 } certain_attribs[] = {
381 {"device", 1},
382 {"footprint", 2},
383 {"value", 3},
384 {"symversion", 200}
386 #define NUM_CERTAINS (sizeof(certain_attribs)/sizeof(certain_attribs[0]))
387 #define DEFAULT_ATTRIB_POS 100
389 /*------------------------------------------------------------------*/
390 /*! \brief Sort the master component attribute list
392 * Take the master comp attrib list
393 * sheet_head->master_comp_attrib_list_head
394 * and sort it in this order:
395 * <all refdeses in alphabetical order>
396 * Right now it does nothing other than fill in the "position"
397 * and "length" variables.
399 void s_string_list_sort_master_comp_attrib_list() {
400 int i = 0;
401 STRING_LIST *local_list, *p;
403 /* Here's where we do the sort */
404 local_list = sheet_head->master_comp_attrib_list_head;
407 * Note that this sort is TBD -- it is more than just an alphabetic sort 'cause we want
408 * certain attribs to go first.
410 for (p=local_list; p; p=p->next) {
411 int i;
412 p->pos = DEFAULT_ATTRIB_POS;
413 for (i=0; i<NUM_CERTAINS; i++)
414 if (p->data != NULL) {
415 if (strcmp (certain_attribs[i].attrib, p->data) == 0)
417 p->pos = certain_attribs[i].pos;
418 break;
423 local_list = listsort(local_list, 0, 1);
424 sheet_head->master_comp_attrib_list_head = local_list;
426 /* Do this after sorting is done. This resets the order of the individual items
427 * in the list. */
428 while (local_list != NULL) {
429 local_list->pos = i;
430 i++;
431 local_list = local_list->next;
434 return;
437 /*------------------------------------------------------------------*/
438 /*! \brief Sort the master netlist
440 * This fcn takes the master net list
441 * sheet_head->master_net_list_head
442 * and sorts it in this order:
443 * <all nets in alphabetical order>
445 void s_string_list_sort_master_net_list() {
446 int i = 0;
447 STRING_LIST *local_list;
450 /* Do this after sorting is done. This resets the order of the individual items
451 * in the list. */
452 local_list = sheet_head->master_net_list_head;
453 while (local_list != NULL) {
454 local_list->pos = i;
455 i++;
456 local_list = local_list->next;
459 return;
462 /*------------------------------------------------------------------*/
463 /*! \brief Sort the master net attribute list
465 * Take the master net attribute list
466 * sheet_head->master_net_attrib_list_head
467 * and sort it in this order:
468 * value, footprint, model-name, file,
469 * <all other attributes in alphabetical order>
471 /*------------------------------------------------------------------*/
472 void s_string_list_sort_master_net_attrib_list() {
473 int i = 0;
474 STRING_LIST *local_list;
477 /* Do this after sorting is done. This resets the order of the individual items
478 * in the list. */
479 local_list = sheet_head->master_net_attrib_list_head;
480 while (local_list != NULL) {
481 local_list->pos = i;
482 i++;
483 local_list = local_list->next;
486 return;
490 /*------------------------------------------------------------------*/
491 /*! \brief Sort the master pin list
493 * Take the master pin list
494 * sheet_head->master_pin_list_head
495 * and sorts it in this order:
496 * <all refdeses in alphabetical order>
497 * Right now it does nothing other than fill in the "position"
498 * and "length" variables.
500 /*------------------------------------------------------------------*/
501 void s_string_list_sort_master_pin_list() {
502 int i = 0;
503 STRING_LIST *local_list, *p;
505 /* Here's where we do the sort. The sort is done using a fcn found on the web. */
506 local_list = sheet_head->master_pin_list_head;
507 for (p=local_list; p; p=p->next)
508 p->pos = 0;
509 local_list = listsort(local_list, 0, 1);
511 /* Do this after sorting is done. This resets the order of the individual items
512 * in the list. */
513 while (local_list != NULL) { /* make sure item is not null */
514 local_list->pos = i;
515 if (local_list->next != NULL) {
516 i++;
517 local_list = local_list->next;
518 } else {
519 break; /* leave loop *before* iterating to NULL EOL marker */
523 /* Now go to first item in local list and reassign list head to new first element */
524 while (local_list->prev != NULL) {
525 local_list = local_list->prev;
528 sheet_head->master_pin_list_head = local_list;
530 return;
533 /*------------------------------------------------------------------*/
534 /*! \brief Sort the master pin attribute list
536 * Takes the master pin attrib list
537 * sheet_head->master_pin_attrib_list_head
538 * and sorts it in this order:
539 * <all pin attribs in alphabetical order>
540 * Right now it does nothing other than fill in the "position"
541 * and "length" variables.
543 /*------------------------------------------------------------------*/
544 void s_string_list_sort_master_pin_attrib_list() {
545 int i = 0;
546 STRING_LIST *local_list;
548 /* Here's where we do the sort */
551 * Note that this sort is TBD -- it is more than just an alphabetic sort 'cause we want
552 * certain attribs to go first.
556 /* Do this after sorting is done. This resets the order of the individual items
557 * in the list. */
558 local_list = sheet_head->master_pin_attrib_list_head;
559 while (local_list != NULL) {
560 local_list->pos = i;
561 i++;
562 local_list = local_list->next;
565 return;