1 /* Lepton EDA attribute editor
2  * Copyright (C) 2003-2010 Stuart D. Brorson.
3  * Copyright (C) 2003-2013 gEDA Contributors
4  * Copyright (C) 2017-2021 Lepton EDA Contributors
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*------------------------------------------------------------------*/
22 /*! \file
23  *  \brief Functions involved in manipulating the STRING_LIST
24  *         structure.
25  *
26  * This file holds functions involved in manipulating the STRING_LIST
27  * structure.  STRING_LIST is basically a linked list of strings
28  * (text).
29  *
30  * \todo This could be implemented using an underlying GList
31  *       structure.  The count parameter could also be eliminated -
32  *       either store it in the struct or preferably, calculate it
33  *       when needed - I don't think the speed penalty of traversing
34  *       the list is significant at all. GDE
35  */
36 
37 #include <config.h>
38 
39 #include <stdio.h>
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #include <math.h>
44 
45 /*------------------------------------------------------------------
46  * Gattrib specific includes
47  *------------------------------------------------------------------*/
48 #include <liblepton/liblepton.h>
49 #include "../include/struct.h"     /* typdef and struct declarations */
50 #include "../include/prototype.h"  /* function prototypes */
51 #include "../include/globals.h"
52 #include "../include/gettext.h"
53 
54 
55 
56 /*------------------------------------------------------------------*/
57 /*! \brief Return a pointer to a new STRING_LIST
58  *
59  * Returns a pointer to a new STRING_LIST struct. This list is empty.
60  * \returns pointer to the new STRING_LIST struct.
61  */
s_string_list_new()62 STRING_LIST *s_string_list_new() {
63   STRING_LIST *local_string_list;
64 
65   local_string_list = (STRING_LIST*) g_malloc (sizeof (STRING_LIST));
66   local_string_list->data = NULL;
67   local_string_list->next = NULL;
68   local_string_list->prev = NULL;
69   local_string_list->pos = -1;   /* can look for this later . . .  */
70 
71   return local_string_list;
72 }
73 
74 
75 /*------------------------------------------------------------------*/
76 /*! \brief Duplicate a STRING_LIST
77  *
78  * Given a STRING_LIST, duplicate it and returns a pointer
79  * to the new, duplicate list.
80  * \param old_string_list pointer to the STRING_LIST to be duplicated
81  * \returns a pointer to the duplicate STRING_LIST
82  */
s_string_list_duplicate_string_list(STRING_LIST * old_string_list)83 STRING_LIST *s_string_list_duplicate_string_list(STRING_LIST *old_string_list) {
84   STRING_LIST *new_string_list;
85   STRING_LIST *local_string_list;
86   char *data;
87   gint count;
88 
89   new_string_list = s_string_list_new();
90 
91   if (old_string_list->data == NULL)
92     /* This is an empty string list */
93     return new_string_list;
94 
95   local_string_list = old_string_list;
96   while (local_string_list != NULL) {
97     data = g_strdup(local_string_list->data);
98     s_string_list_add_item(new_string_list, &count, data);
99     g_free(data);
100     local_string_list = local_string_list->next;
101   }
102 
103   return new_string_list;
104 }
105 
106 
107 /*------------------------------------------------------------------*/
108 /*! \brief Add an item to a STRING_LIST
109  *
110  * Inserts the item into a STRING_LIST.
111  * It first passes through the
112  * list to make sure that there are no duplications.
113  * \param list pointer to STRING_LIST to be added to.
114  * \param count FIXME Don't know what this does - input or output? both?
115  * \param item pointer to string to be added
116  */
s_string_list_add_item(STRING_LIST * list,int * count,char * item)117 void s_string_list_add_item(STRING_LIST *list, int *count, char *item) {
118 
119   gchar *trial_item = NULL;
120   STRING_LIST *prev;
121   STRING_LIST *local_list;
122 
123   if (list == NULL) {
124     fprintf (stderr, "s_string_list_add_item: ");
125     fprintf (stderr, _("Tried to add to a NULL list.\n"));
126     return;
127   }
128 
129   /* First check to see if list is empty.  Handle insertion of first item
130      into empty list separately.  (Is this necessary?) */
131   if (list->data == NULL) {
132     g_debug ("s_string_list_add_item: "
133              "About to place first item in list.\n");
134     list->data = (gchar *) g_strdup(item);
135     list->next = NULL;
136     list->prev = NULL;  /* this may have already been initialized. . . . */
137     list->pos = *count; /* This enumerates the pos on the list.  Value is reset later by sorting. */
138     (*count)++;  /* increment count to 1 */
139     return;
140   }
141 
142   /* Otherwise, loop through list looking for duplicates */
143   prev = list;
144   while (list != NULL) {
145     trial_item = (gchar *) g_strdup(list->data);
146     if (strcmp(trial_item, item) == 0) {
147       /* Found item already in list.  Just return. */
148       g_free(trial_item);
149       return;
150     }
151     g_free(trial_item);
152     prev = list;
153     list = list->next;
154   }
155 
156   /* If we are here, it's 'cause we didn't find the item pre-existing in the list. */
157   /* In this case, we insert it. */
158 
159   local_list = (STRING_LIST *) g_malloc(sizeof(STRING_LIST));  /* allocate space for this list entry */
160   local_list->data = (gchar *) g_strdup(item);   /* copy data into list */
161   local_list->next = NULL;
162   local_list->prev = prev;  /* point this item to last entry in old list */
163   prev->next = local_list;  /* make last item in old list point to this one. */
164   local_list->pos = *count; /* This enumerates the pos on the list.  Value is reset later by sorting. */
165   (*count)++;  /* increment count */
166   /*   list = local_list;  */
167   return;
168 
169 }
170 
171 
172 /*------------------------------------------------------------------*/
173 /*! \brief Delete an item from a STRING_LIST
174  *
175  * Deletes an item in a STRING_LIST.
176  * \param list pointer to STRING_LIST
177  * \param count pointer to count of items in list
178  * \param item item to remove from list
179  */
s_string_list_delete_item(STRING_LIST ** list,int * count,gchar * item)180 void s_string_list_delete_item(STRING_LIST **list, int *count, gchar *item) {
181 
182   gchar *trial_item = NULL;
183   STRING_LIST *list_item;
184   STRING_LIST *next_item = NULL;
185   STRING_LIST *prev_item = NULL;
186 
187   /* First check to see if list is empty.  If empty, spew error and return */
188   if ( (*list)->data == NULL) {
189     fprintf (stderr, "s_string_list_delete_item: ");
190     fprintf (stderr, _("Tried to remove item from empty list.\n"));
191     return;
192   }
193 
194   g_debug ("s_string_list_delete_item: "
195            "About to delete item %s from list.\n",
196            item);
197 
198   /* Now loop through list looking for item */
199   list_item = (*list);
200   while (list_item != NULL) {
201     trial_item = (gchar *) g_strdup(list_item->data);
202     g_debug ("s_string_list_delete_item: "
203              "Matching item against trial item = %s from list.\n",
204              trial_item);
205     if (strcmp(trial_item, item) == 0) {
206       /* found item, now delete it. */
207       g_debug ("s_string_list_delete_item: "
208                "Match found.\n");
209       prev_item = list_item->prev;
210       next_item = list_item->next;
211 
212       /* Check position in list */
213       if (next_item == NULL && prev_item == NULL) {
214         /* pathological case of one item list. */
215         (*list) = NULL;
216       } else if (next_item == NULL && prev_item != NULL) {
217         /* at list's end */
218         prev_item->next = NULL;
219       } else if (next_item != NULL && prev_item == NULL) {
220         /* at list's beginning */
221         next_item->prev = NULL;
222         (*list) = next_item;         /* also need to fix pointer to list head */
223         /*  g_free(list);  */
224       } else {
225         /* normal case of element in middle of list */
226         prev_item->next = next_item;
227         next_item->prev = prev_item;
228       }
229 
230       g_debug ("s_string_list_delete_item: "
231                "Free list_item.\n");
232       g_free(list_item);  /* free current list item */
233       (*count)--;       /* decrement count */
234       /* Do we need to re-number the list? */
235 
236       g_debug ("s_string_list_delete_item: "
237                "Free trial_item.\n");
238       g_free(trial_item); /* free trial item before returning */
239       g_debug ("s_string_list_delete_item: "
240                "Return.\n");
241       return;
242     }
243     g_free(trial_item);
244     list_item = list_item->next;
245   }
246 
247   /* If we are here, it's 'cause we didn't find the item.
248    * Spew error and return.
249    */
250   fprintf (stderr, "s_string_list_delete_item:");
251   fprintf (stderr, _("Couldn't delete item %1$s\n"), item);
252   return;
253 
254 }
255 
256 /*------------------------------------------------------------------*/
257 /*! \brief Detect item in list
258  *
259  * Look for item in the list.
260  *
261  * \param list pointer to the STRING_LIST struct
262  * \param item string to search for
263  * \returns 0 if absent, 1 if present
264  */
s_string_list_in_list(STRING_LIST * list,char * item)265 int s_string_list_in_list(STRING_LIST *list, char *item) {
266 
267   gchar *trial_item = NULL;
268 
269   /* First check to see if list is empty.  If empty, return
270    * 0 automatically.  (I probably don't need to handle this
271    * separately.)  */
272   if (list->data == NULL) {
273     return 0;
274   }
275 
276   /* Otherwise, loop through list looking for duplicates */
277   while (list != NULL) {
278     trial_item = (gchar *) g_strdup(list->data);
279     if (strcmp(trial_item, item) == 0) {
280       /* Found item already in list.  return 1. */
281       g_free(trial_item);
282       return 1;
283     }
284     g_free(trial_item);
285     list = list->next;
286   }
287 
288   /* If we are here, it's 'cause we didn't find the item
289    * pre-existing in the list.  In this case, return 0 */
290   return 0;
291 
292 }
293 
294 
295 /*------------------------------------------------------------------*/
296 /*! \brief Detect item in list
297  *
298  * Look for item in the list, and return the index (-1 if absent).
299  * Intended to be a more useful variant of s_string_list_in_list.
300  *
301  * \param list pointer to the STRING_LIST struct
302  * \param item string to search for
303  * \returns -1 if absent, index number if present
304  */
s_string_list_find_in_list(STRING_LIST * list,char * item)305 gint s_string_list_find_in_list(STRING_LIST *list, char *item) {
306 
307   gint index = 0;
308   gchar *trial_item = NULL;
309 
310   /* First check to see if list is empty.  If empty, return -1. */
311   if (list->data == NULL) {
312     return -1;
313   }
314 
315   /* Otherwise, loop through list looking for the item */
316   while (list != NULL) {
317     trial_item = (gchar *) g_strdup(list->data);
318     if (strcmp(trial_item, item) == 0) {
319       /* Found item in list; return index. */
320       g_free(trial_item);
321       return index;
322     }
323     g_free(trial_item);
324     list = list->next;
325     index++;
326   }
327 
328   /* If we are here, it's 'cause we didn't find the item
329    * pre-existing in the list.  In this case, return -1 */
330   return -1;
331 
332 }
333 
334 
335 /*------------------------------------------------------------------*/
336 /*! \brief Get an item from a STRING_LIST by index
337  *
338  * Returns the index'th item in the string list.
339  * \param list pointer to STRING_LIST to get from
340  * \param index index of item to return
341  * \returns NULL if there is a problem otherwise a pointer to
342  *          the string.
343  */
s_string_list_get_data_at_index(STRING_LIST * list,gint index)344 gchar *s_string_list_get_data_at_index(STRING_LIST *list, gint index)
345 {
346   gint i;
347   STRING_LIST *local_item;
348 
349   /* First check to see if list is empty.  If empty, return
350    * NULL automatically.  */
351   if (list->data == NULL) {
352     return NULL;
353   }
354 
355   local_item = list;
356   for (i = 0 ; i < index ; i++) {
357     if (local_item == NULL) {
358       return NULL;
359     } else {
360       local_item = local_item->next;
361     }
362   }
363   return local_item->data;
364 }
365 
366 
367 /*------------------------------------------------------------------*/
368 /*! \brief Sort the master component list
369  *
370  * Takes the master comp list
371  * sheet_head->master_comp_list_head
372  * and sorts it in this order:
373  * <all refdeses in alphabetical order>
374  * Right now it does nothing other than fill in the "position"
375  * and "length" variables.
376  */
s_string_list_sort_master_comp_list()377 void s_string_list_sort_master_comp_list() {
378   int i = 0;
379   STRING_LIST *local_list, *p;
380 
381   /* Here's where we do the sort.  The sort is done using a fcn found on the web. */
382   local_list = sheet_head->master_comp_list_head;
383   for (p=local_list; p; p=p->next)
384     p->pos = 0;
385   local_list = listsort(local_list, 0, 1);
386 
387   /* Do this after sorting is done.  This resets the order of the individual items
388    * in the list.  */
389   while (local_list != NULL) {  /* make sure item is not null */
390     local_list->pos = i;
391     if (local_list->next != NULL) {
392       i++;
393       local_list = local_list->next;
394     } else {
395       break;                    /* leave loop *before* iterating to NULL EOL marker */
396     }
397   }
398 
399   /* Now go to first item in local list and reassign list head to new first element */
400   while (local_list->prev != NULL) {
401     local_list = local_list->prev;
402   }
403 
404   sheet_head->master_comp_list_head = local_list;
405 
406   return;
407 }
408 
409 
410 /* This list overrides the alphanumeric sort.  Attribs not found in
411    this list are sorted as if they had a value of DEFAULT_ATTRIB_POS
412    within this list, but alphanumerically relative to each other.  */
413 static struct {
414   const char *attrib;
415   int pos;
416 } certain_attribs[] = {
417   {"device", 1},
418   {"footprint", 2},
419   {"value", 3},
420   {"symversion", 200}
421 };
422 #define NUM_CERTAINS (sizeof(certain_attribs)/sizeof(certain_attribs[0]))
423 #define DEFAULT_ATTRIB_POS 100
424 
425 /*------------------------------------------------------------------*/
426 /*! \brief Sort the master component attribute list
427  *
428  * Take the master comp attrib list
429  * sheet_head->master_comp_attrib_list_head
430  * and sort it in this order:
431  * <all refdeses in alphabetical order>
432  * Right now it does nothing other than fill in the "position"
433  * and "length" variables.
434  */
s_string_list_sort_master_comp_attrib_list()435 void s_string_list_sort_master_comp_attrib_list() {
436   int i = 0;
437   STRING_LIST *local_list, *p;
438 
439   /* Here's where we do the sort */
440   local_list = sheet_head->master_comp_attrib_list_head;
441 
442   /*
443    * Note that this sort is TBD -- it is more than just an alphabetic sort 'cause we want
444    * certain attribs to go first.
445    */
446   for (p=local_list; p; p=p->next) {
447     int i;
448     p->pos = DEFAULT_ATTRIB_POS;
449     for (i=0; i < (gint) NUM_CERTAINS; i++) {
450       if (p->data != NULL
451           && (strcmp (certain_attribs[i].attrib, p->data) == 0)) {
452         p->pos = certain_attribs[i].pos;
453         break;
454       }
455     }
456   }
457 
458   local_list = listsort(local_list, 0, 1);
459   sheet_head->master_comp_attrib_list_head = local_list;
460 
461   /* Do this after sorting is done.  This resets the order of the individual items
462    * in the list.  */
463   while (local_list != NULL) {
464     local_list->pos = i;
465     i++;
466     local_list = local_list->next;
467   }
468 
469   return;
470 }
471 
472 /*------------------------------------------------------------------*/
473 /*! \brief Sort the master netlist
474  *
475  * This fcn takes the master net list
476  * sheet_head->master_net_list_head
477  * and sorts it in this order:
478  * <all nets in alphabetical order>
479  */
s_string_list_sort_master_net_list()480 void s_string_list_sort_master_net_list() {
481   int i = 0;
482   STRING_LIST *local_list;
483 
484 
485   /* Do this after sorting is done.  This resets the order of the individual items
486    * in the list.  */
487   local_list = sheet_head->master_net_list_head;
488   while (local_list != NULL) {
489     local_list->pos = i;
490     i++;
491     local_list = local_list->next;
492   }
493 
494   return;
495 }
496 
497 /*------------------------------------------------------------------*/
498 /*! \brief Sort the master net attribute list
499  *
500  * Take the master net attribute list
501  * sheet_head->master_net_attrib_list_head
502  * and sort it in this order:
503  * value, footprint, model-name, file,
504  * <all other attributes in alphabetical order>
505  */
506 /*------------------------------------------------------------------*/
s_string_list_sort_master_net_attrib_list()507 void s_string_list_sort_master_net_attrib_list() {
508   int i = 0;
509   STRING_LIST *local_list;
510 
511 
512   /* Do this after sorting is done.  This resets the order of the individual items
513    * in the list.  */
514   local_list = sheet_head->master_net_attrib_list_head;
515   while (local_list != NULL) {
516     local_list->pos = i;
517     i++;
518     local_list = local_list->next;
519   }
520 
521   return;
522 }
523 
524 
525 /*------------------------------------------------------------------*/
526 /*! \brief Sort the master pin list
527  *
528  * Take the master pin list
529  * sheet_head->master_pin_list_head
530  * and sorts it in this order:
531  * <all refdeses in alphabetical order>
532  * Right now it does nothing other than fill in the "position"
533  * and "length" variables.
534  */
535 /*------------------------------------------------------------------*/
s_string_list_sort_master_pin_list()536 void s_string_list_sort_master_pin_list() {
537   int i = 0;
538   STRING_LIST *local_list, *p;
539 
540   /* Here's where we do the sort.  The sort is done using a fcn found on the web. */
541   local_list = sheet_head->master_pin_list_head;
542   for (p=local_list; p; p=p->next)
543     p->pos = 0;
544   local_list = listsort(local_list, 0, 1);
545 
546   /* Do this after sorting is done.  This resets the order of the individual items
547    * in the list.  */
548   while (local_list != NULL) {  /* make sure item is not null */
549     local_list->pos = i;
550     if (local_list->next != NULL) {
551       i++;
552       local_list = local_list->next;
553     } else {
554       break;                    /* leave loop *before* iterating to NULL EOL marker */
555     }
556   }
557 
558   /* Now go to first item in local list and reassign list head to new first element */
559   while (local_list->prev != NULL) {
560     local_list = local_list->prev;
561   }
562 
563   sheet_head->master_pin_list_head = local_list;
564 
565   return;
566 }
567 
568 /*------------------------------------------------------------------*/
569 /*! \brief Sort the master pin attribute list
570  *
571  * Takes the master pin attrib list
572  * sheet_head->master_pin_attrib_list_head
573  * and sorts it in this order:
574  * <all pin attribs in alphabetical order>
575  * Right now it does nothing other than fill in the "position"
576  * and "length" variables.
577  */
578 /*------------------------------------------------------------------*/
s_string_list_sort_master_pin_attrib_list()579 void s_string_list_sort_master_pin_attrib_list() {
580   int i = 0;
581   STRING_LIST *local_list;
582 
583   /* Here's where we do the sort */
584 
585   /*
586    * Note that this sort is TBD -- it is more than just an alphabetic sort 'cause we want
587    * certain attribs to go first.
588    */
589 
590 
591   /* Do this after sorting is done.  This resets the order of the individual items
592    * in the list.  */
593   local_list = sheet_head->master_pin_attrib_list_head;
594   while (local_list != NULL) {
595     local_list->pos = i;
596     i++;
597     local_list = local_list->next;
598   }
599 
600   return;
601 }
602