Command built-in can parse output into list (no need to Match it now)
[k8jam.git] / lists.c
blob6114d8ad8ea668bc7b2f786907c95fdc10e98c0a
1 /*
2 * Copyright 1993, 1995 Christopher Seiwald.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
7 /*
8 * lists.c - maintain lists of strings
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.
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.
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
27 # include "jam.h"
28 # include "newstr.h"
29 # include "lists.h"
31 static LIST *freelist = 0; /* junkpile for list_free() */
35 * list_append() - append a list onto another one, returning total
37 LIST *list_append (LIST *l, LIST *nl) {
38 if (!nl) {
39 /* Just return l */
40 } else if (!l) {
41 l = nl;
42 } else {
43 /* Graft two non-empty lists. */
44 l->tail->next = nl;
45 l->tail = nl->tail;
47 return l;
52 * list_new() - tack a string onto the end of a list of strings
54 /* copy!=0: copystr; else newstr */
55 LIST *list_new (LIST *head, const char *string, int copy) {
56 LIST *l;
58 if (DEBUG_LISTS) printf("list > %s <\n", string);
60 /* Copy/newstr as needed */
61 string = copy?copystr(string):newstr(string);
63 /* Get list struct from freelist, if one available. */
64 /* Otherwise allocate. */
65 /* If from freelist, must free string first */
66 if (freelist) {
67 l = freelist;
68 freestr(l->string);
69 freelist = freelist->next;
70 } else l = (LIST *)malloc(sizeof(*l));
72 /* If first on chain, head points here. */
73 /* If adding to chain, tack us on. */
74 /* Tail must point to this new, last element. */
75 if (!head) head = l; else head->tail->next = l;
76 head->tail = l;
77 l->next = 0;
78 l->string = string;
79 return head;
84 * list_copy() - copy a whole list of strings (nl) onto end of another (l)
86 LIST *list_copy (LIST *l, LIST *nl) {
87 for (; nl; nl = list_next(nl)) l = list_new(l, nl->string, 1);
88 return l;
93 * list_sublist() - copy a subset of a list of strings
95 LIST *list_sublist (LIST *l, int start, int count) {
96 LIST *nl = 0;
98 for (; l && start--; l = list_next(l)) ;
99 for (; l && count--; l = list_next(l)) nl = list_new(nl, l->string, 1);
100 return nl;
104 /* backported from boost-jam; TEST IT!!! */
106 * list_sort() - sort list
108 LIST *list_sort (LIST *l) {
109 LIST *first = 0;
110 LIST *second = 0;
111 LIST *merged = l;
112 LIST *result;
114 if (!l) return L0;
115 for (;;) {
116 /* Split the list in two */
117 LIST **dst = &first;
118 LIST *src = merged;
119 for (;;) {
120 *dst = list_append(*dst, list_new(0, src->string, 1));
121 if (!src->next) break;
122 if (strcmp(src->string, src->next->string) > 0) dst = (dst==&first)?&second:&first;
123 src = src->next;
125 if (merged != l) list_free(merged);
126 merged = 0;
127 if (second == 0) { result = first; break; }
128 /* Merge lists 'first' and 'second' into 'merged' and free 'first'/'second'. */
130 LIST *f = first;
131 LIST *s = second;
132 while (f && s) {
133 if (strcmp(f->string, s->string) < 0) {
134 merged = list_append(merged, list_new(0, f->string, 1));
135 f = f->next;
136 } else {
137 merged = list_append(merged, list_new(0, s->string, 1));
138 s = s->next;
141 merged = list_copy(merged, f);
142 merged = list_copy(merged, s);
143 list_free(first);
144 list_free(second);
145 first = second = 0;
148 return result;
153 * list_free() - free a list of strings
155 void list_free (LIST *head) {
156 /* Just tack onto freelist. */
157 if (head) {
158 head->tail->next = freelist;
159 freelist = head;
165 * list_print() - print a list of strings to stdout
167 void list_print (LIST *l) {
168 for (; l; l = list_next(l)) printf("%s ", l->string);
172 /* FIXME! */
174 * list_printq() - print a list of safely quoted strings to a file
176 void list_printq (FILE *out, LIST *l) {
177 /* Dump each word, enclosed in "s */
178 /* Suitable for Jambase use. */
179 for (; l; l = list_next(l)) {
180 const char *p = l->string;
181 const char *ep = p+strlen(p);
182 const char *op = p;
184 fputc('\n', out);
185 fputc('\t', out);
186 fputc('"', out);
187 /* Any embedded "'s? Escape them */
188 while ((p = (char *)memchr(op, '"', ep-op))) {
189 fwrite(op, p-op, 1, out);
190 fputc('\\', out);
191 fputc('"', out);
192 op = p+1;
194 /* Write remainder */
195 fwrite(op, ep-op, 1, out);
196 fputc('"', out);
197 fputc(' ', out);
203 * list_length() - return the number of items in the list
205 int list_length (LIST *l) {
206 int n = 0;
208 for (; l; l = list_next(l), ++n) ;
209 return n;
214 * lol_init() - initialize a LOL (list of lists)
216 void lol_init (LOL *lol) {
217 lol->count = 0;
222 * lol_add() - append a LIST onto an LOL
224 void lol_add (LOL *lol, LIST *l) {
225 if (lol->count < LOL_MAX) lol->list[lol->count++] = l;
230 * lol_free() - free the LOL and its LISTs
232 void lol_free (LOL *lol) {
233 int i;
235 for (i = 0; i < lol->count; i++) list_free(lol->list[i]);
236 lol->count = 0;
241 * lol_get() - return one of the LISTs in the LOL
243 LIST *lol_get (LOL *lol, int i) {
244 return i<lol->count?lol->list[i]:0;
249 * lol_print() - debug print LISTS separated by ":"
251 void lol_print (LOL *lol) {
252 int i;
254 for (i = 0; i < lol->count; i++) {
255 if (i) printf(" : ");
256 list_print(lol->list[i]);