]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 "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, 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 | ||
74 | void var_defines( struct module_t * module, char * const * e, int preprocess ) | |
75 | { | |
76 | string buf[ 1 ]; | |
77 | ||
78 | string_new( buf ); | |
79 | ||
80 | for ( ; *e; ++e ) | |
81 | { | |
82 | 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 | char * p; | |
106 | 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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
368 | static void var_dump( OBJECT * symbol, LIST * value, 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 | ||
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 | ||
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 | } |