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