1 /* *** This file was borrowed from jam 2.5. The copyright statement from
2  * *** jam.c appears below.
3  */
4 /*
5  * /+\
6  * +\	Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
7  * \+/
8  *
9  * This file is part of jam.
10  *
11  * License is hereby granted to use this software and distribute it
12  * freely, as long as this copyright notice is retained and modifications
13  * are clearly marked.
14  *
15  * ALL WARRANTIES ARE HEREBY DISCLAIMED.
16  */
17 
18 /*
19  * Copyright 1993, 1995 Christopher Seiwald.
20  *
21  * This file is part of Jam - see jam.c for Copyright information.
22  */
23 
24 /*
25  * lists.c - maintain lists of strings
26  *
27  * This implementation essentially uses a singly linked list, but
28  * guarantees that the head element of every list has a valid pointer
29  * to the tail of the list, so the new elements can efficiently and
30  * properly be appended to the end of a list.
31  *
32  * To avoid massive allocation, list_free() just tacks the whole freed
33  * chain onto freelist and list_new() looks on freelist first for an
34  * available list struct.  list_free() does not free the strings in the
35  * chain: it lazily lets list_new() do so.
36  *
37  * 08/23/94 (seiwald) - new list_append()
38  * 09/07/00 (seiwald) - documented lol_*() functions
39  * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
40  * 11/04/02 (seiwald) - const-ing for string literals
41  * 12/09/02 (seiwald) - new list_printq() for writing lists to Jambase
42  */
43 
44 # include "jam.h"
45 # include "newstr.h"
46 # include "lists.h"
47 
48 #if 1 /* TNB */
49 #include "alloc.h"
50 static ALLOC *listalloc = 0;
51 #endif
52 
53 static LIST *freelist = 0;	/* junkpile for list_free() */
54 
55 /*
56  * list_append() - append a list onto another one, returning total
57  */
58 
59 LIST *
list_append(LIST * l,LIST * nl)60 list_append(
61 	LIST	*l,
62 	LIST	*nl )
63 {
64 	if( !nl )
65 	{
66 	    /* Just return l */
67 	}
68 	else if( !l )
69 	{
70 	    l = nl;
71 	}
72 	else
73 	{
74 	    /* Graft two non-empty lists. */
75 	    l->tail->next = nl;
76 	    l->tail = nl->tail;
77 	}
78 
79 	return l;
80 }
81 
82 /*
83  * list_new() - tack a string onto the end of a list of strings
84  */
85 
86 LIST *
list_new(LIST * head,const char * string,int copy)87 list_new(
88 	LIST	*head,
89 	const char *string,
90 	int	copy )
91 {
92 	LIST *l;
93 
94 	if( DEBUG_LISTS )
95 	    printf( "list > %s <\n", string );
96 
97 	/* Copy/newstr as needed */
98 
99 	string = copy ? copystr( string ) : newstr( string );
100 
101 	/* Get list struct from freelist, if one available.  */
102 	/* Otherwise allocate. */
103 	/* If from freelist, must free string first */
104 
105 	if( freelist )
106 	{
107 	    l = freelist;
108 	    freestr( l->string );
109 	    freelist = freelist->next;
110 	}
111 	else
112 	{
113 #if 1 /* TNB */
114 		if (!listalloc)
115 			listalloc = alloc_init(sizeof(LIST), 64);
116 		l = (LIST *) alloc_enter(listalloc);
117 #else
118 	    l = (LIST *)malloc( sizeof( *l ) );
119 #endif
120 	}
121 
122 	/* If first on chain, head points here. */
123 	/* If adding to chain, tack us on. */
124 	/* Tail must point to this new, last element. */
125 
126 	if( !head ) head = l;
127 	else head->tail->next = l;
128 	head->tail = l;
129 	l->next = 0;
130 
131 	l->string = string;
132 
133 	return head;
134 }
135 
136 /*
137  * list_copy() - copy a whole list of strings (nl) onto end of another (l)
138  */
139 
140 LIST *
list_copy(LIST * l,LIST * nl)141 list_copy(
142 	LIST	*l,
143 	LIST 	*nl )
144 {
145 	for( ; nl; nl = list_next( nl ) )
146 	    l = list_new( l, nl->string, 1 );
147 
148 	return l;
149 }
150 
151 /*
152  * list_sublist() - copy a subset of a list of strings
153  */
154 
155 LIST *
list_sublist(LIST * l,int start,int count)156 list_sublist(
157 	LIST	*l,
158 	int	start,
159 	int	count )
160 {
161 	LIST	*nl = 0;
162 
163 	for( ; l && start--; l = list_next( l ) )
164 	    ;
165 
166 	for( ; l && count--; l = list_next( l ) )
167 	    nl = list_new( nl, l->string, 1 );
168 
169 	return nl;
170 }
171 
172 /*
173  * list_free() - free a list of strings
174  */
175 
176 void
list_free(LIST * head)177 list_free( LIST	*head )
178 {
179 	/* Just tack onto freelist. */
180 
181 	if( head )
182 	{
183 	    head->tail->next = freelist;
184 	    freelist = head;
185 	}
186 }
187 
188 /*
189  * list_print() - print a list of strings to stdout
190  */
191 
192 void
list_print(LIST * l)193 list_print( LIST *l )
194 {
195 	for( ; l; l = list_next( l ) )
196 	    printf( "%s ", l->string );
197 }
198 
199 /*
200  * list_printq() - print a list of safely quoted strings to a file
201  */
202 
203 void
list_printq(FILE * out,LIST * l)204 list_printq( FILE *out, LIST *l )
205 {
206 	/* Dump each word, enclosed in "s */
207 	/* Suitable for Jambase use. */
208 
209 	for( ; l; l = list_next( l ) )
210 	{
211 	    const char *p = l->string;
212 	    const char *ep = p + strlen( p );
213 	    const char *op = p;
214 
215 	    fputc( '\n', out );
216 	    fputc( '\t', out );
217 	    fputc( '"', out );
218 
219 	    /* Any embedded "'s?  Escape them */
220 
221 	    while( ( p = (char *)memchr( op, '"',  ep - op ) ) ) /* TNB */
222 	    {
223 		fwrite( op, p - op, 1, out );
224 		fputc( '\\', out );
225 		fputc( '"', out );
226 		op = p + 1;
227 	    }
228 
229 	    /* Write remainder */
230 
231 	    fwrite( op, ep - op, 1, out );
232 	    fputc( '"', out );
233 	    fputc( ' ', out );
234 	}
235 }
236 
237 /*
238  * list_length() - return the number of items in the list
239  */
240 
241 int
list_length(LIST * l)242 list_length( LIST *l )
243 {
244 	int n = 0;
245 
246 	for( ; l; l = list_next( l ), ++n )
247 	    ;
248 
249 	return n;
250 }
251 
252 /*
253  * lol_init() - initialize a LOL (list of lists)
254  */
255 
256 void
lol_init(LOL * lol)257 lol_init( LOL *lol )
258 {
259 	lol->count = 0;
260 }
261 
262 /*
263  * lol_add() - append a LIST onto an LOL
264  */
265 
266 void
lol_add(LOL * lol,LIST * l)267 lol_add(
268 	LOL	*lol,
269 	LIST	*l )
270 {
271 	if( lol->count < LOL_MAX )
272 	    lol->list[ lol->count++ ] = l;
273 }
274 
275 /*
276  * lol_free() - free the LOL and its LISTs
277  */
278 
279 void
lol_free(LOL * lol)280 lol_free( LOL *lol )
281 {
282 	int i;
283 
284 	for( i = 0; i < lol->count; i++ )
285 	    list_free( lol->list[i] );
286 
287 	lol->count = 0;
288 }
289 
290 /*
291  * lol_get() - return one of the LISTs in the LOL
292  */
293 
294 LIST *
lol_get(LOL * lol,int i)295 lol_get(
296 	LOL	*lol,
297 	int	i )
298 {
299 	return i < lol->count ? lol->list[i] : 0;
300 }
301 
302 /*
303  * lol_print() - debug print LISTS separated by ":"
304  */
305 
306 void
lol_print(LOL * lol)307 lol_print( LOL *lol )
308 {
309 	int i;
310 
311 	for( i = 0; i < lol->count; i++ )
312 	{
313 	    if( i )
314 		printf( " : " );
315 	    list_print( lol->list[i] );
316 	}
317 }
318 
donelist(void)319 void donelist(void) /* TNB */
320 {
321 	freelist = 0;
322 	alloc_free(listalloc);
323 	listalloc = 0;
324 }
325