1 /*
2 * Copyright 1993, 2000 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7 /* This file is ALSO:
8 * Copyright 2001-2004 David Abrahams.
9 * Copyright 2005 Reece H. Dunn.
10 * Copyright 2005 Rene Rivera.
11 * Distributed under the Boost Software License, Version 1.0.
12 * (See accompanying file LICENSE_1_0.txt or copy at
13 * http://www.boost.org/LICENSE_1_0.txt)
14 */
15
16 /*
17 * variable.c - handle Jam multi-element variables.
18 *
19 * External routines:
20 *
21 * var_defines() - load a bunch of variable=value settings
22 * var_get() - get value of a user defined symbol
23 * var_set() - set a variable in jam's user defined symbol table.
24 * var_swap() - swap a variable's value with the given one
25 * var_done() - free variable tables
26 *
27 * Internal routines:
28 *
29 * var_enter() - make new var symbol table entry, returning var ptr
30 * var_dump() - dump a variable to stdout
31 */
32
33 #include "jam.h"
34 #include "variable.h"
35
36 #include "filesys.h"
37 #include "hash.h"
38 #include "modules.h"
39 #include "parse.h"
40 #include "pathsys.h"
41 #include "jam_strings.h"
42 #include "output.h"
43
44 #include <stdio.h>
45 #include <stdlib.h>
46
47
48 /*
49 * VARIABLE - a user defined multi-value variable
50 */
51
52 typedef struct _variable VARIABLE ;
53
54 struct _variable
55 {
56 OBJECT * symbol;
57 LIST * value;
58 };
59
60 static LIST * * var_enter( struct module_t *, OBJECT * symbol );
61 static void var_dump( OBJECT * symbol, LIST * value, const char * what );
62
63
64 /*
65 * var_defines() - load a bunch of variable=value settings
66 *
67 * If preprocess is false, take the value verbatim.
68 *
69 * Otherwise, if the variable value is enclosed in quotes, strip the quotes.
70 * Otherwise, if variable name ends in PATH, split value at :'s.
71 * Otherwise, split the value at blanks.
72 */
73
var_defines(struct module_t * module,const char * const * e,int preprocess)74 void var_defines( struct module_t * module, const char * const * e, int preprocess )
75 {
76 string buf[ 1 ];
77
78 string_new( buf );
79
80 for ( ; *e; ++e )
81 {
82 const char * val;
83
84 if ( ( val = strchr( *e, '=' ) )
85 #if defined( OS_MAC )
86 /* On the mac (MPW), the var=val is actually var\0val */
87 /* Think different. */
88 || ( val = *e + strlen( *e ) )
89 #endif
90 )
91 {
92 LIST * l = L0;
93 size_t const len = strlen( val + 1 );
94 int const quoted = ( val[ 1 ] == '"' ) && ( val[ len ] == '"' ) &&
95 ( len > 1 );
96
97 if ( quoted && preprocess )
98 {
99 string_append_range( buf, val + 2, val + len );
100 l = list_push_back( l, object_new( buf->value ) );
101 string_truncate( buf, 0 );
102 }
103 else
104 {
105 const char * p;
106 const char * pp;
107 char split =
108 #if defined( OPT_NO_EXTERNAL_VARIABLE_SPLIT )
109 '\0'
110 #elif defined( OS_MAC )
111 ','
112 #else
113 ' '
114 #endif
115 ;
116
117 /* Split *PATH at :'s, not spaces. */
118 if ( val - 4 >= *e )
119 {
120 if ( !strncmp( val - 4, "PATH", 4 ) ||
121 !strncmp( val - 4, "Path", 4 ) ||
122 !strncmp( val - 4, "path", 4 ) )
123 split = SPLITPATH;
124 }
125
126 /* Do the split. */
127 for
128 (
129 pp = val + 1;
130 preprocess && ( ( p = strchr( pp, split ) ) != 0 );
131 pp = p + 1
132 )
133 {
134 string_append_range( buf, pp, p );
135 l = list_push_back( l, object_new( buf->value ) );
136 string_truncate( buf, 0 );
137 }
138
139 l = list_push_back( l, object_new( pp ) );
140 }
141
142 /* Get name. */
143 string_append_range( buf, *e, val );
144 {
145 OBJECT * const varname = object_new( buf->value );
146 var_set( module, varname, l, VAR_SET );
147 object_free( varname );
148 }
149 string_truncate( buf, 0 );
150 }
151 }
152 string_free( buf );
153 }
154
155
156 /* Last returned variable value saved so we may clear it in var_done(). */
157 static LIST * saved_var = L0;
158
159
160 /*
161 * var_get() - get value of a user defined symbol
162 *
163 * Returns NULL if symbol unset.
164 */
165
var_get(struct module_t * module,OBJECT * symbol)166 LIST * var_get( struct module_t * module, OBJECT * symbol )
167 {
168 LIST * result = L0;
169 #ifdef OPT_AT_FILES
170 /* Some "fixed" variables... */
171 if ( object_equal( symbol, constant_TMPDIR ) )
172 {
173 list_free( saved_var );
174 result = saved_var = list_new( object_new( path_tmpdir()->value ) );
175 }
176 else if ( object_equal( symbol, constant_TMPNAME ) )
177 {
178 list_free( saved_var );
179 result = saved_var = list_new( path_tmpnam() );
180 }
181 else if ( object_equal( symbol, constant_TMPFILE ) )
182 {
183 list_free( saved_var );
184 result = saved_var = list_new( path_tmpfile() );
185 }
186 else if ( object_equal( symbol, constant_STDOUT ) )
187 {
188 list_free( saved_var );
189 result = saved_var = list_new( object_copy( constant_STDOUT ) );
190 }
191 else if ( object_equal( symbol, constant_STDERR ) )
192 {
193 list_free( saved_var );
194 result = saved_var = list_new( object_copy( constant_STDERR ) );
195 }
196 else
197 #endif
198 {
199 VARIABLE * v;
200 int n;
201
202 if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
203 {
204 if ( DEBUG_VARGET )
205 var_dump( symbol, module->fixed_variables[ n ], "get" );
206 result = module->fixed_variables[ n ];
207 }
208 else if ( module->variables && ( v = (VARIABLE *)hash_find(
209 module->variables, symbol ) ) )
210 {
211 if ( DEBUG_VARGET )
212 var_dump( v->symbol, v->value, "get" );
213 result = v->value;
214 }
215
216 #ifdef OS_VMS
217 else if ( ( module->name && object_equal( module->name, constant_ENVIRON ) )
218 || root_module() == module )
219 {
220 /* On VMS, when a variable from root or ENVIRON module is not found,
221 * explicitly request it from the process.
222 * By design, process variables (and logicals) are not made available
223 * to C main(), and thus will not get loaded in bulk to root/ENVRON.
224 * So we get around it by getting any such variable on first request.
225 */
226 const char * val = getenv( object_str( symbol ) );
227
228 if ( val )
229 {
230 struct module_t * environ_module = module;
231 char * environ[ 2 ] = { 0 }; /* NULL-terminated */
232 string buf[ 1 ];
233
234 if ( root_module() == module )
235 {
236 environ_module = bindmodule( constant_ENVIRON );
237 }
238
239 string_copy( buf, object_str( symbol ) );
240 string_append( buf, "=" );
241 string_append( buf, val );
242
243 environ[ 0 ] = buf->value;
244
245 /* Load variable to global module, with splitting, for backward
246 * compatibility. Then to .ENVIRON, without splitting.
247 */
248 var_defines( root_module(), environ, 1 );
249 var_defines( environ_module, environ, 0 );
250 string_free( buf );
251
252 if ( module->variables && ( v = (VARIABLE *)hash_find(
253 module->variables, symbol ) ) )
254 {
255 if ( DEBUG_VARGET )
256 var_dump( v->symbol, v->value, "get" );
257 result = v->value;
258 }
259 }
260 }
261 #endif
262 }
263 return result;
264 }
265
266
var_get_and_clear_raw(module_t * module,OBJECT * symbol)267 LIST * var_get_and_clear_raw( module_t * module, OBJECT * symbol )
268 {
269 LIST * result = L0;
270 VARIABLE * v;
271
272 if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables,
273 symbol ) ) )
274 {
275 result = v->value;
276 v->value = L0;
277 }
278
279 return result;
280 }
281
282
283 /*
284 * var_set() - set a variable in Jam's user defined symbol table
285 *
286 * 'flag' controls the relationship between new and old values of the variable:
287 * SET replaces the old with the new; APPEND appends the new to the old; DEFAULT
288 * only uses the new if the variable was previously unset.
289 *
290 * Copies symbol. Takes ownership of value.
291 */
292
var_set(struct module_t * module,OBJECT * symbol,LIST * value,int flag)293 void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag
294 )
295 {
296 LIST * * v = var_enter( module, symbol );
297
298 if ( DEBUG_VARSET )
299 var_dump( symbol, value, "set" );
300
301 switch ( flag )
302 {
303 case VAR_SET: /* Replace value */
304 list_free( *v );
305 *v = value;
306 break;
307
308 case VAR_APPEND: /* Append value */
309 *v = list_append( *v, value );
310 break;
311
312 case VAR_DEFAULT: /* Set only if unset */
313 if ( list_empty( *v ) )
314 *v = value;
315 else
316 list_free( value );
317 break;
318 }
319 }
320
321
322 /*
323 * var_swap() - swap a variable's value with the given one
324 */
325
var_swap(struct module_t * module,OBJECT * symbol,LIST * value)326 LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value )
327 {
328 LIST * * v = var_enter( module, symbol );
329 LIST * oldvalue = *v;
330 if ( DEBUG_VARSET )
331 var_dump( symbol, value, "set" );
332 *v = value;
333 return oldvalue;
334 }
335
336
337 /*
338 * var_enter() - make new var symbol table entry, returning var ptr
339 */
340
var_enter(struct module_t * module,OBJECT * symbol)341 static LIST * * var_enter( struct module_t * module, OBJECT * symbol )
342 {
343 int found;
344 VARIABLE * v;
345 int n;
346
347 if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
348 return &module->fixed_variables[ n ];
349
350 if ( !module->variables )
351 module->variables = hashinit( sizeof( VARIABLE ), "variables" );
352
353 v = (VARIABLE *)hash_insert( module->variables, symbol, &found );
354 if ( !found )
355 {
356 v->symbol = object_copy( symbol );
357 v->value = L0;
358 }
359
360 return &v->value;
361 }
362
363
364 /*
365 * var_dump() - dump a variable to stdout
366 */
367
var_dump(OBJECT * symbol,LIST * value,const char * what)368 static void var_dump( OBJECT * symbol, LIST * value, const char * what )
369 {
370 out_printf( "%s %s = ", what, object_str( symbol ) );
371 list_print( value );
372 out_printf( "\n" );
373 }
374
375
376 /*
377 * var_done() - free variable tables
378 */
379
delete_var_(void * xvar,void * data)380 static void delete_var_( void * xvar, void * data )
381 {
382 VARIABLE * const v = (VARIABLE *)xvar;
383 object_free( v->symbol );
384 list_free( v->value );
385 }
386
var_done(struct module_t * module)387 void var_done( struct module_t * module )
388 {
389 list_free( saved_var );
390 saved_var = L0;
391 hashenumerate( module->variables, delete_var_, 0 );
392 hash_free( module->variables );
393 }
394