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