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