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