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