2 * Copyright 1993, 1995 Christopher Seiwald.
3 * This file is part of Jam - see jam.c for Copyright information.
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 3 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, see <http://www.gnu.org/licenses/>.
19 * lists.c - maintain lists of strings
21 * This implementation essentially uses a singly linked list, but
22 * guarantees that the head element of every list has a valid pointer
23 * to the tail of the list, so the new elements can efficiently and
24 * properly be appended to the end of a list.
26 * To avoid massive allocation, list_free() just tacks the whole freed
27 * chain onto freelist and list_new() looks on freelist first for an
28 * available list struct. list_free() does not free the strings in the
29 * chain: it lazily lets list_new() do so.
36 static LIST
*freelist
= NULL
; /* junkpile for list_free() */
40 * list_append() - append a list onto another one, returning total
42 LIST
*list_append (LIST
*l
, LIST
*nl
) {
48 /* graft two non-empty lists */
56 static JAMFA_PURE
int contains (LIST
*l
, const char *str
) {
57 for (; l
!= NULL
; l
= l
->next
) if (strcmp(l
->string
, str
) == 0) return 1;
63 * list_removeall() - remove all occurences of `nl` items from `l`
65 LIST
*list_removeall (LIST
*l
, LIST
*nl
) {
67 LIST
*p
= NULL
, *h
= NULL
;
70 if (contains(nl
, l
->string
)) {
71 // remove (i.e. move node to freelist)
72 if (p
!= NULL
) p
->next
= n
;
73 if (n
== NULL
&& h
!= NULL
) h
->tail
= p
;
78 if (h
== NULL
) h
= l
; // save list head
80 if (n
== NULL
&& h
!= NULL
) h
->tail
= l
;
90 /* get list struct from freelist, if one available, otherwise allocate */
91 /* if from freelist, must free string first */
92 static inline LIST
*alloc_item (void) {
97 freelist
= freelist
->next
;
99 l
= malloc(sizeof(*l
));
106 * list_new() - tack a string onto the end of a list of strings
108 /* copy!=0: copystr; else newstr */
109 LIST
*list_new (LIST
*head
, const char *string
, int copy
) {
111 if (DEBUG_LISTS
) printf("list > %s <\n", string
);
112 /* copy/newstr as needed */
113 string
= (copy
? copystr(string
) : newstr(string
));
115 /* if first on chain, head points here */
116 /* if adding to chain, tack us on */
117 /* tail must point to this new, last element */
118 if (!head
) head
= l
; else head
->tail
->next
= l
;
127 * list_copy() - copy a whole list of strings (nl) onto end of another (l)
129 LIST
*list_copy (LIST
*l
, LIST
*nl
) {
130 for (; nl
; nl
= list_next(nl
)) l
= list_new(l
, nl
->string
, 1);
136 * list_sublist() - copy a subset of a list of strings
138 LIST
*list_sublist (LIST
*l
, int start
, int count
) {
140 for (; l
&& start
--; l
= list_next(l
)) ;
141 for (; l
&& count
--; l
= list_next(l
)) nl
= list_new(nl
, l
->string
, 1);
146 /* backported from boost-jam; TEST IT!!! */
148 * list_sort() - sort list
150 LIST
*list_sort (LIST
*l
) {
151 LIST
*first
= NULL
, *second
= NULL
, *merged
= l
, *result
;
154 /* split the list in two */
158 *dst
= list_append(*dst
, list_new(0, src
->string
, 1));
159 if (!src
->next
) break;
160 if (strcmp(src
->string
, src
->next
->string
) > 0) dst
= (dst
==&first
)?&second
:&first
;
163 if (merged
!= l
) list_free(merged
);
165 if (second
== 0) { result
= first
; break; }
166 /* merge lists 'first' and 'second' into 'merged' and free 'first'/'second' */
168 LIST
*f
= first
, *s
= second
;
170 if (strcmp(f
->string
, s
->string
) < 0) {
171 merged
= list_append(merged
, list_new(0, f
->string
, 1));
174 merged
= list_append(merged
, list_new(0, s
->string
, 1));
178 merged
= list_copy(merged
, f
);
179 merged
= list_copy(merged
, s
);
189 /* returns new list */
190 LIST
*list_reverse (const LIST
*l
) {
191 LIST
*res
= L0
, *last
= L0
;
193 res
= last
= alloc_item();
194 last
->string
= copystr(l
->string
);
199 for (; l
!= NULL
; l
= l
->next
) {
200 LIST
*i
= alloc_item();
201 i
->string
= copystr(l
->string
);
205 if (res
!= L0
) res
->tail
= last
;
212 * list_free() - free a list of strings
214 void list_free (LIST
*head
) {
215 /* Just tack onto freelist. */
217 head
->tail
->next
= freelist
;
224 * list_print() - print a list of strings to stdout
226 void list_print_ex (FILE *fo
, const LIST
*l
, int flags
) {
227 int spc
= (l
== NULL
);
228 for (; l
; l
= list_next(l
)) {
229 if (spc
&& (flags
&LPFLAG_NO_SPACES
) == 0) fputc(' ', fo
);
230 fputs(l
->string
, fo
);
233 if (spc
&& (flags
&LPFLAG_NO_TRSPACE
) == 0) fputc(' ', fo
);
240 * list_printq() - print a list of safely quoted strings to a file
242 void list_printq (FILE *out
, LIST
*l
) {
243 /* dump each word, enclosed in "s */
244 /* suitable for Jambase use. */
245 for (; l
; l
= list_next(l
)) {
246 const char *p
= l
->string
;
247 const char *ep
= p
+strlen(p
);
252 /* any embedded "'s? Escape them */
253 while ((p
= (char *)memchr(op
, '"', ep
-op
))) {
254 fwrite(op
, p
-op
, 1, out
);
259 /* Write remainder */
260 fwrite(op
, ep
-op
, 1, out
);
269 * list_length() - return the number of items in the list
271 JAMFA_PURE
int list_length (const LIST
*l
) {
273 for (n
= 0; l
; l
= list_next(l
), ++n
) ;
279 * lol_init() - initialize a LOL (list of lists)
281 void lol_init (LOL
*lol
) {
287 * lol_add() - append a LIST onto an LOL
289 void lol_add (LOL
*lol
, LIST
*l
) {
290 if (lol
->count
< LOL_MAX
) lol
->list
[lol
->count
++] = l
;
295 * lol_free() - free the LOL and its LISTs
297 void lol_free (LOL
*lol
) {
298 for (int i
= 0; i
< lol
->count
; ++i
) list_free(lol
->list
[i
]);
304 * lol_get() - return one of the LISTs in the LOL
306 JAMFA_PURE LIST
*lol_get (LOL
*lol
, int i
) {
307 return (i
>= 0 && i
< lol
->count
? lol
->list
[i
] : NULL
);
312 * lol_print() - debug print LISTS separated by ":"
314 void lol_print (const LOL
*lol
) {
315 for (int i
= 0; i
< lol
->count
; ++i
) {
317 list_print(lol
->list
[i
]);