1/* 2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. 3 * 4 * This file is part of Jam - see jam.c for Copyright information. 5 */ 6 7/* 8 * variable.c - handle jam multi-element variables 9 * 10 * External routines: 11 * 12 * var_defines() - load a bunch of variable=value settings 13 * var_string() - expand a string with variables in it 14 * var_get() - get value of a user defined symbol 15 * var_set() - set a variable in jam's user defined symbol table 16 * var_swap() - swap a variable's value with the given one 17 * var_done() - free variable tables 18 * 19 * Internal routines: 20 * 21 * var_enter() - make new var symbol table entry, returning var ptr 22 * var_dump() - dump a variable to stdout 23 * 24 * 04/13/94 (seiwald) - added shorthand L0 for null list pointer 25 * 08/23/94 (seiwald) - Support for '+=' (append to variable) 26 * 01/22/95 (seiwald) - split environment variables at blanks or :'s 27 * 05/10/95 (seiwald) - split path variables at SPLITPATH (not :) 28 * 09/11/00 (seiwald) - defunct var_list() removed 29 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr() 30 * 11/04/02 (seiwald) - const-ing for string literals 31 */ 32 33# include "jam.h" 34# include "lists.h" 35# include "parse.h" 36# include "variable.h" 37# include "expand.h" 38# include "hash.h" 39# include "newstr.h" 40 41static struct hash *varhash = 0; 42 43/* 44 * VARIABLE - a user defined multi-value variable 45 */ 46 47typedef struct _variable VARIABLE ; 48 49struct _variable { 50 const char *symbol; 51 LIST *value; 52} ; 53 54static VARIABLE *var_enter( const char *symbol ); 55static void var_dump( const char *symbol, LIST *value, const char *what ); 56 57 58 59/* 60 * var_defines() - load a bunch of variable=value settings 61 * 62 * If variable name ends in PATH, split value at :'s. 63 * Otherwise, split at blanks. 64 */ 65 66void 67var_defines( const char **e ) 68{ 69 for( ; *e; e++ ) 70 { 71 const char *val; 72 73 /* Just say "no": windows defines this in the env, */ 74 /* but we don't want it to override our notion of OS. */ 75 76 if( !strcmp( *e, "OS=Windows_NT" ) ) 77 continue; 78 79# ifdef OS_MAC 80 /* On the mac (MPW), the var=val is actually var\0val */ 81 /* Think different. */ 82 83 if( ( val = strchr( *e, '=' ) ) || ( val = *e + strlen( *e ) ) ) 84# else 85 if( val = strchr( *e, '=' ) ) 86# endif 87 { 88 LIST *l = L0; 89 const char *pp, *p; 90# ifdef OS_MAC 91 char split = ','; 92# else 93 char split = ' '; 94# endif 95 char buf[ MAXSYM ]; 96 97 /* Split *PATH at :'s, not spaces */ 98 99 if( val - 4 >= *e ) 100 { 101 if( !strncmp( val - 4, "PATH", 4 ) || 102 !strncmp( val - 4, "Path", 4 ) || 103 !strncmp( val - 4, "path", 4 ) ) 104 split = SPLITPATH; 105 } 106 107 /* Do the split */ 108 109 for( pp = val + 1; p = strchr( pp, split ); pp = p + 1 ) 110 { 111 strncpy( buf, pp, p - pp ); 112 buf[ p - pp ] = '\0'; 113 l = list_new( l, buf, 0 ); 114 } 115 116 l = list_new( l, pp, 0 ); 117 118 /* Get name */ 119 120 if (val - *e > MAXSYM) { 121 printf("MAXSYM is too low, need at least %d\n", val - *e); 122 exit(-1); 123 } 124 strncpy( buf, *e, val - *e ); 125 buf[ val - *e ] = '\0'; 126 127 var_set( buf, l, VAR_SET ); 128 } 129 } 130} 131 132/* 133 * var_string() - expand a string with variables in it 134 * 135 * Copies in to out; doesn't modify targets & sources. 136 */ 137 138int 139var_string( 140 const char *in, 141 char *out, 142 int outsize, 143 LOL *lol ) 144{ 145 char *out0 = out; 146 char *oute = out + outsize - 1; 147 148 while( *in ) 149 { 150 char *lastword; 151 int dollar = 0; 152 153 /* Copy white space */ 154 155 while( isspace( *in ) ) 156 { 157 if( out >= oute ) 158 return -1; 159 160 *out++ = *in++; 161 } 162 163 lastword = out; 164 165 /* Copy non-white space, watching for variables */ 166 167 while( *in && !isspace( *in ) ) 168 { 169 if( out >= oute ) 170 return -1; 171 172 if( in[0] == '$' && in[1] == '(' ) 173 dollar++; 174 175 *out++ = *in++; 176 } 177 178 /* If a variable encountered, expand it and and embed the */ 179 /* space-separated members of the list in the output. */ 180 181 if( dollar ) 182 { 183 LIST *l = var_expand( L0, lastword, out, lol, 0 ); 184 185 out = lastword; 186 187 while( l ) 188 { 189 int so = strlen( l->string ); 190 191 if( out + so >= oute ) 192 return -1; 193 194 strcpy( out, l->string ); 195 out += so; 196 197 /* Separate with space */ 198 199 if( l = list_next( l ) ) 200 *out++ = ' '; 201 } 202 203 list_free( l ); 204 } 205 } 206 207 if( out >= oute ) 208 return -1; 209 210 *out++ = '\0'; 211 212 return out - out0; 213} 214 215/* 216 * var_get() - get value of a user defined symbol 217 * 218 * Returns NULL if symbol unset. 219 */ 220 221LIST * 222var_get( const char *symbol ) 223{ 224 VARIABLE var, *v = &var; 225 226 v->symbol = symbol; 227 228 if( varhash && hashcheck( varhash, (HASHDATA **)&v ) ) 229 { 230 if( DEBUG_VARGET ) 231 var_dump( v->symbol, v->value, "get" ); 232 return v->value; 233 } 234 235 return 0; 236} 237 238/* 239 * var_set() - set a variable in jam's user defined symbol table 240 * 241 * 'flag' controls the relationship between new and old values of 242 * the variable: SET replaces the old with the new; APPEND appends 243 * the new to the old; DEFAULT only uses the new if the variable 244 * was previously unset. 245 * 246 * Copies symbol. Takes ownership of value. 247 */ 248 249void 250var_set( 251 const char *symbol, 252 LIST *value, 253 int flag ) 254{ 255 VARIABLE *v = var_enter( symbol ); 256 257 if( DEBUG_VARSET ) 258 var_dump( symbol, value, "set" ); 259 260 switch( flag ) 261 { 262 case VAR_SET: 263 /* Replace value */ 264 list_free( v->value ); 265 v->value = value; 266 break; 267 268 case VAR_APPEND: 269 /* Append value */ 270 v->value = list_append( v->value, value ); 271 break; 272 273 case VAR_DEFAULT: 274 /* Set only if unset */ 275 if( !v->value ) 276 v->value = value; 277 else 278 list_free( value ); 279 break; 280 } 281} 282 283/* 284 * var_swap() - swap a variable's value with the given one 285 */ 286 287LIST * 288var_swap( 289 const char *symbol, 290 LIST *value ) 291{ 292 VARIABLE *v = var_enter( symbol ); 293 LIST *oldvalue = v->value; 294 295 if( DEBUG_VARSET ) 296 var_dump( symbol, value, "set" ); 297 298 v->value = value; 299 300 return oldvalue; 301} 302 303 304 305/* 306 * var_enter() - make new var symbol table entry, returning var ptr 307 */ 308 309static VARIABLE * 310var_enter( const char *symbol ) 311{ 312 VARIABLE var, *v = &var; 313 314 if( !varhash ) 315 varhash = hashinit( sizeof( VARIABLE ), "variables" ); 316 317 v->symbol = symbol; 318 v->value = 0; 319 320 if( hashenter( varhash, (HASHDATA **)&v ) ) 321 v->symbol = newstr( symbol ); /* never freed */ 322 323 return v; 324} 325 326/* 327 * var_dump() - dump a variable to stdout 328 */ 329 330static void 331var_dump( 332 const char *symbol, 333 LIST *value, 334 const char *what ) 335{ 336 printf( "%s %s = ", what, symbol ); 337 list_print( value ); 338 printf( "\n" ); 339} 340 341/* 342 * var_done() - free variable tables 343 */ 344 345void 346var_done() 347{ 348 hashdone( varhash ); 349} 350