• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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