1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
4 **********/
5 
6 /* Wordlist manipulation stuff.  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "ngspice/bool.h"
12 #include "ngspice/memory.h"
13 #include "ngspice/ngspice.h"
14 #include "ngspice/wordlist.h"
15 
16 
17 /* Determine the length of a word list. */
18 int
wl_length(const wordlist * wl)19 wl_length(const wordlist *wl)
20 {
21     int i = 0;
22 
23     for (; wl; wl = wl->wl_next)
24         i++;
25 
26     return (i);
27 }
28 
29 
30 /* Free the storage used by a word list. */
31 void
wl_free(wordlist * wl)32 wl_free(wordlist *wl)
33 {
34     while (wl) {
35         wordlist *next = wl->wl_next;
36         tfree(wl->wl_word);
37         tfree(wl);
38         wl = next;
39     }
40 }
41 
42 
43 /* Copy a wordlist and the words. */
44 wordlist *
wl_copy(const wordlist * wl)45 wl_copy(const wordlist *wl)
46 {
47     wordlist *first = NULL, *last = NULL;
48 
49     for (; wl; wl = wl->wl_next)
50         wl_append_word(&first, &last, copy(wl->wl_word));
51 
52     return (first);
53 }
54 
55 
56 /* Substitute a wordlist for one element of a wordlist, and return a
57  * pointer to the last element of the inserted list.  */
58 wordlist *
wl_splice(wordlist * elt,wordlist * list)59 wl_splice(wordlist *elt, wordlist *list)
60 {
61 
62     if (list)
63         list->wl_prev = elt->wl_prev;
64     if (elt->wl_prev)
65         elt->wl_prev->wl_next = list;
66     if (list) {
67         while (list->wl_next)
68             list = list->wl_next;
69         list->wl_next = elt->wl_next;
70     }
71     if (elt->wl_next)
72         elt->wl_next->wl_prev = list;
73     tfree(elt->wl_word);
74     tfree(elt);
75     return (list);
76 }
77 
78 
79 
80 static void
printword(const char * string,FILE * fp)81 printword(const char *string, FILE *fp)
82 {
83     if (string) {
84         while (*string) {
85             putc((*string++), fp);
86         }
87     }
88 }
89 
90 
91 /* Print a word list. (No \n at the end...) */
92 void
wl_print(const wordlist * wl,FILE * fp)93 wl_print(const wordlist *wl, FILE *fp)
94 {
95     for (; wl; wl = wl->wl_next) {
96         printword(wl->wl_word, fp);
97         if (wl->wl_next)
98             putc(' ', fp);
99     }
100 }
101 
102 
103 /* Turn an array of char *'s into a wordlist. */
104 wordlist *
wl_build(const char * const * v)105 wl_build(const char * const *v)
106 {
107     wordlist *first = NULL;
108     wordlist *last = NULL;
109 
110     while (*v)
111         wl_append_word(&first, &last, copy(*v++));
112 
113     return first;
114 }
115 
116 
117 
118 /* Convert a single string into a wordlist. */
119 wordlist *
wl_from_string(const char * sz)120 wl_from_string(const char *sz)
121 {
122     const char * list_of_1_word[2];
123     list_of_1_word[0] = sz;
124     list_of_1_word[1] = (char *) NULL;
125     return wl_build(list_of_1_word);
126 } /* end of function wl_from_string */
127 
128 
129 
130 char **
wl_mkvec(const wordlist * wl)131 wl_mkvec(const wordlist *wl)
132 {
133     int  len = wl_length(wl);
134     char **vec = TMALLOC(char *, (size_t) len + 1);
135 
136     int i;
137 
138     for (i = 0; i < len; i++) {
139         vec[i] = copy(wl->wl_word);
140         wl = wl->wl_next;
141     }
142     vec[i] = NULL;
143 
144     return (vec);
145 }
146 
147 
148 
149 /* Nconc two wordlists together. */
150 wordlist *
wl_append(wordlist * wlist,wordlist * nwl)151 wl_append(wordlist *wlist, wordlist *nwl)
152 {
153     wordlist *wl;
154     if (wlist == NULL)
155         return (nwl);
156     if (nwl == NULL)
157         return (wlist);
158     for (wl = wlist; wl->wl_next; wl = wl->wl_next)
159         ;
160     wl->wl_next = nwl;
161     nwl->wl_prev = wl;
162     return (wlist);
163 }
164 
165 
166 /* Reverse a word list. */
167 wordlist *
wl_reverse(wordlist * wl)168 wl_reverse(wordlist *wl)
169 {
170     if (!wl)
171         return (wl);
172 
173     for (;;) {
174         SWAP(wordlist *, wl->wl_next, wl->wl_prev);
175         if (!wl->wl_prev)
176             return (wl);
177         wl = wl->wl_prev;
178     }
179 }
180 
181 
182 /* This function converts a wordlist into a string, adding a blank space
183  * between each word and a null termination. The wordlist may be NULL, in
184  * which case "" is returned.
185  *
186  * The returned string is allocated and must be freed by the caller. */
187 char *
wl_flatten(const wordlist * wlist)188 wl_flatten(const wordlist *wlist)
189 {
190     char *buf;
191     const wordlist *wl;
192 
193     /* Handle case of an empty list */
194     if (wlist == (wordlist *) NULL) {
195         buf = TMALLOC(char, 1);
196         *buf = '\0';
197         return buf;
198     }
199 
200     /* List has at least one word */
201 
202     /* Find size needed for buffer
203      * +1 for interword blanks and null at end */
204     size_t len = 0;
205     for (wl = wlist; wl; wl = wl->wl_next)
206         len += strlen(wl->wl_word) + 1;
207 
208     /* Allocate to min required size */
209     buf = TMALLOC(char, len);
210 
211     /* Step through the list again, building the output string */
212     char *p_dst = buf;
213     for (wl = wlist; ; ) { /* for each word */
214         /* Add all source chars until end of word */
215         const char *p_src = wl->wl_word;
216         for ( ; ; p_src++) { /* for each char */
217             const char ch_src = *p_src;
218             if (ch_src == '\0') { /* exit when null found */
219                 break;
220             }
221             *p_dst++ = ch_src;
222         } /* end of loop over chars in source string */
223 
224         /* Move to next word, exiting if none left */
225         if ((wl = wl->wl_next) == (wordlist *) NULL) {
226             *p_dst = '\0'; /* null-terminate string */
227             return buf; /* normal function exit */
228         }
229         *p_dst++ = ' '; /* add space between words */
230     } /* end of loop over words in word list */
231 } /* end of function wl_flatten */
232 
233 
234 
235 /* Return the nth element of a wordlist, or the last one if n is too
236  * big.  Numbering starts at 0...  */
237 wordlist *
wl_nthelem(int i,wordlist * wl)238 wl_nthelem(int i, wordlist *wl)
239 {
240     while ((i-- > 0) && wl->wl_next)
241         wl = wl->wl_next;
242 
243     return (wl);
244 }
245 
246 
247 
248 /* Compare function for the array of word pointers */
249 static int
wlcomp(const char * const * s,const char * const * t)250 wlcomp(const char * const *s, const char * const *t)
251 {
252     return strcmp(*s, *t);
253 }
254 
255 
256 
257 /* Sort a word list in order of strcmp ascending */
258 void
wl_sort(wordlist * wl)259 wl_sort(wordlist *wl)
260 {
261     size_t i = 0;
262     wordlist *ww = wl;
263     char **stuff;
264 
265     /* Find number of words in the list */
266     for (i = 0; ww; i++) {
267         ww = ww->wl_next;
268     }
269 
270     /* If empty list or only one word, no sort is required */
271     if (i <= 1) {
272         return;
273     }
274 
275     stuff = TMALLOC(char *, i); /* allocate buffer for words */
276 
277     /* Add pointers to the words to the buffer */
278     for (i = 0, ww = wl; ww; i++, ww = ww->wl_next) {
279         stuff[i] = ww->wl_word;
280     }
281 
282     /* Sort the words */
283     qsort(stuff, i, sizeof (char *),
284             (int (*)(const void *, const void *)) &wlcomp);
285 
286     /* Put the words back into the word list in sorted order */
287     for (i = 0, ww = wl; ww; i++, ww = ww->wl_next) {
288         ww->wl_word = stuff[i];
289     }
290 
291     tfree(stuff); /* free buffer of word pointers */
292 } /* end of function wl_sort */
293 
294 
295 
296 /* Return a range of wordlist elements... */
297 wordlist *
wl_range(wordlist * wl,int low,int up)298 wl_range(wordlist *wl, int low, int up)
299 {
300     wordlist *tt;
301     bool rev = FALSE;
302 
303     if (low > up) {
304         SWAP(int, up, low);
305         rev = TRUE;
306     }
307     up -= low;
308     while (wl && (low > 0)) {
309         tt = wl->wl_next;
310         tfree(wl->wl_word);
311         tfree(wl);
312         wl = tt;
313         if (wl)
314             wl->wl_prev = NULL;
315         low--;
316     }
317     tt = wl;
318     while (tt && (up > 0)) {
319         tt = tt->wl_next;
320         up--;
321     }
322     if (tt && tt->wl_next) {
323         wl_free(tt->wl_next);
324         tt->wl_next = NULL;
325     }
326     if (rev)
327         wl = wl_reverse(wl);
328     return (wl);
329 }
330 
331 
332 /*
333  *  prepend a new `word'
334  *     to the front of the given `wlist' wordlist
335  *  and return this new list
336  */
337 
338 wordlist *
wl_cons(char * word,wordlist * wlist)339 wl_cons(char *word, wordlist *wlist)
340 {
341     wordlist *w = TMALLOC(wordlist, 1);
342     w->wl_next = wlist;
343     w->wl_prev = NULL;
344     w->wl_word = word;
345 
346     if (wlist)
347         wlist->wl_prev = w;
348 
349     return (w);
350 }
351 
352 
353 /*
354  * given a wordlist
355  *   described by a `first' and `last' wordlist element
356  * append a new `word'
357  *   and update the given `first' and `last' pointers accordingly
358  *
359  * Remarks
360  * Onwership of the buffer containing the word is given to the
361  * word list. That is, the word is not copied.
362  */
363 
364 void
wl_append_word(wordlist ** first,wordlist ** last,char * word)365 wl_append_word(wordlist **first, wordlist **last, char *word)
366 {
367     wordlist *w = TMALLOC(wordlist, 1);
368     w->wl_next = NULL;
369     w->wl_prev = (*last);
370     w->wl_word = word;
371 
372     if (*last)
373         (*last)->wl_next = w;
374     else
375         (*first) = w;
376 
377     (*last) = w;
378 }
379 
380 
381 /*
382  * given a pointer `wl' into a wordlist, cut off this list from its
383  * preceding elements and return itself. Thus, the function creates two
384  * valid word lists: the one before this word and the one starting with
385  * this word and continuing to the end of the original word list.
386  */
387 wordlist *
wl_chop(wordlist * wl)388 wl_chop(wordlist *wl)
389 {
390     if (wl && wl->wl_prev) {
391         wl->wl_prev->wl_next = NULL;
392         wl->wl_prev = NULL;
393     }
394     return (wl);
395 }
396 
397 
398 /*
399  * given a pointer `wl' into a wordlist
400  *   cut off the rest of the list
401  *   and return this rest
402  */
403 wordlist *
wl_chop_rest(wordlist * wl)404 wl_chop_rest(wordlist *wl)
405 {
406     wordlist *rest = wl->wl_next;
407     wl->wl_next = NULL;
408     if(rest)
409         rest->wl_prev = NULL;
410     return (rest);
411 }
412 
413 
414 /*
415  * search for a string in a wordlist
416  */
417 wordlist *
wl_find(const char * string,const wordlist * wl)418 wl_find(const char *string, const wordlist *wl)
419 {
420     if (!string)
421         return NULL;
422 
423     for (; wl; wl = wl->wl_next)
424         if (eq(string, wl->wl_word))
425             break;
426     return ((wordlist *) wl);
427 } /* end of function wl_find */
428 
429 
430 
431 /*
432  * delete elements from a wordlist
433  *   starting at `from'
434  *   up to but exclusive of `to'.
435  *   `to' may be NULL to delete from `from' to the end of the list
436  *
437  * Allocations for the deleted slice are freed.
438  *
439  * Note that the function does not check if `from' and `to' are in
440  * the same word list initially or that the former precedes the latter.
441  */
442 void
wl_delete_slice(wordlist * from,wordlist * to)443 wl_delete_slice(wordlist *from, wordlist *to)
444 {
445 
446     if (from == to) { /* nothing to delete */
447         return;
448     }
449 
450     wordlist *prev = from->wl_prev;
451 
452     if (prev) {
453         prev->wl_next = to;
454     }
455 
456     if (to) {
457         to->wl_prev->wl_next = NULL;
458         to->wl_prev = prev;
459     }
460 
461     wl_free(from);
462 } /* end of function wl_delete_slice */
463 
464 
465 
466