mirror of
https://github.com/boostorg/build.git
synced 2026-01-19 04:02:14 +00:00
374 lines
9.5 KiB
C++
374 lines
9.5 KiB
C++
/*
|
|
* Copyright 1993, 2000 Christopher Seiwald.
|
|
*
|
|
* This file is part of Jam - see jam.c for Copyright information.
|
|
*/
|
|
|
|
/* This file is ALSO:
|
|
* Copyright 2001-2004 David Abrahams.
|
|
* Copyright 2005 Reece H. Dunn.
|
|
* Copyright 2005 Rene Rivera.
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE.txt or copy at
|
|
* https://www.bfgroup.xyz/b2/LICENSE.txt)
|
|
*/
|
|
|
|
/*
|
|
* variable.c - handle Jam multi-element variables.
|
|
*
|
|
* External routines:
|
|
*
|
|
* var_defines() - load a bunch of variable=value settings
|
|
* var_get() - get value of a user defined symbol
|
|
* var_set() - set a variable in jam's user defined symbol table.
|
|
* var_swap() - swap a variable's value with the given one
|
|
* var_done() - free variable tables
|
|
*
|
|
* Internal routines:
|
|
*
|
|
* var_enter() - make new var symbol table entry, returning var ptr
|
|
* var_dump() - dump a variable to stdout
|
|
*/
|
|
|
|
#include "jam.h"
|
|
#include "variable.h"
|
|
|
|
#include "filesys.h"
|
|
#include "hash.h"
|
|
#include "modules.h"
|
|
#include "parse.h"
|
|
#include "pathsys.h"
|
|
#include "jam_strings.h"
|
|
#include "output.h"
|
|
#include "strview.h"
|
|
#include "value.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
|
|
/*
|
|
* VARIABLE - a user defined multi-value variable
|
|
*/
|
|
|
|
typedef struct _variable VARIABLE ;
|
|
|
|
struct _variable
|
|
{
|
|
OBJECT * symbol;
|
|
LIST * value;
|
|
};
|
|
|
|
static LIST * * var_enter( struct module_t *, OBJECT * symbol );
|
|
static void var_dump( OBJECT * symbol, LIST * value, const char * what );
|
|
|
|
|
|
/*
|
|
* var_defines() - load a bunch of variable=value settings
|
|
*
|
|
* If preprocess is false, take the value verbatim.
|
|
*
|
|
* Otherwise, if the variable value is enclosed in quotes, strip the quotes.
|
|
* Otherwise, if variable name ends in PATH, split value at :'s.
|
|
* Otherwise, split the value at blanks.
|
|
*/
|
|
|
|
void var_defines(struct module_t * module, const char * const * e, int preprocess)
|
|
{
|
|
for (; *e; ++e)
|
|
{
|
|
::b2::string_view def(*e);
|
|
::b2::string_view var(def.begin(), def.find('='));
|
|
::b2::string_view val(def.begin() + var.size() + 1);
|
|
b2::jam::variable jam_var { module,
|
|
std::string { var.begin(), var.end() }.c_str() };
|
|
// std::printf(">> var_defines: *e = %s\n", *e);
|
|
// for (auto v : jam_var.get())
|
|
// {
|
|
// std::printf(" '%s'\n", v->str());
|
|
// }
|
|
|
|
// No value to set var with.
|
|
if (var.size() == def.size()) continue;
|
|
|
|
// Skip pre-processing, to just set the raw value.
|
|
if (preprocess == 0)
|
|
{
|
|
jam_var = ::b2::list_ref { ::b2::value_ref { val } };
|
|
continue;
|
|
}
|
|
|
|
// Quoted values do not get separator-split. But do get unquoted.
|
|
if (val.size() >= 2 && val.front() == '"' && val.back() == '"')
|
|
{
|
|
jam_var = ::b2::list_ref { ::b2::value_ref {
|
|
val.substr(1, val.size() - 2) } };
|
|
continue;
|
|
}
|
|
|
|
// Split on separator, either space or path.
|
|
jam_var = ::b2::list_cref {};
|
|
{
|
|
char split = ' ';
|
|
/* Split *PATH at :'s, not spaces. */
|
|
if (var.ends_with("PATH")
|
|
|| var.ends_with("Path" || var.ends_with("path")))
|
|
split = SPLITPATH;
|
|
/* Do the split. */
|
|
for (::b2::string_view::size_type p0 = 0; p0 < val.size();)
|
|
{
|
|
auto p1 = val.find(split, p0);
|
|
if (p1 == val.npos)
|
|
{
|
|
jam_var += ::b2::value_ref { val.substr(p0) };
|
|
p0 = val.npos;
|
|
}
|
|
else
|
|
{
|
|
jam_var += ::b2::value_ref { val.substr(p0, p1 - p0) };
|
|
p0 = p1 + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Last returned variable value saved so we may clear it in var_done(). */
|
|
static LIST * saved_var = L0;
|
|
|
|
|
|
/*
|
|
* var_get() - get value of a user defined symbol
|
|
*
|
|
* Returns NULL if symbol unset.
|
|
*/
|
|
|
|
LIST * var_get( struct module_t * module, OBJECT * symbol )
|
|
{
|
|
LIST * result = L0;
|
|
#ifdef OPT_AT_FILES
|
|
/* Some "fixed" variables... */
|
|
if ( object_equal( symbol, constant_TMPDIR ) )
|
|
{
|
|
list_free( saved_var );
|
|
result = saved_var = list_new( object_new( path_tmpdir()->value ) );
|
|
}
|
|
else if ( object_equal( symbol, constant_TMPNAME ) )
|
|
{
|
|
list_free( saved_var );
|
|
result = saved_var = list_new( path_tmpnam() );
|
|
}
|
|
else if ( object_equal( symbol, constant_TMPFILE ) )
|
|
{
|
|
list_free( saved_var );
|
|
result = saved_var = list_new( path_tmpfile() );
|
|
}
|
|
else if ( object_equal( symbol, constant_STDOUT ) )
|
|
{
|
|
list_free( saved_var );
|
|
result = saved_var = list_new( object_copy( constant_STDOUT ) );
|
|
}
|
|
else if ( object_equal( symbol, constant_STDERR ) )
|
|
{
|
|
list_free( saved_var );
|
|
result = saved_var = list_new( object_copy( constant_STDERR ) );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
VARIABLE * v;
|
|
int n;
|
|
|
|
if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
|
|
{
|
|
if ( is_debug_varget() )
|
|
var_dump( symbol, module->fixed_variables[ n ], "get" );
|
|
result = module->fixed_variables[ n ];
|
|
}
|
|
else if ( module->variables && ( v = (VARIABLE *)hash_find(
|
|
module->variables, symbol ) ) )
|
|
{
|
|
if ( is_debug_varget() )
|
|
var_dump( v->symbol, v->value, "get" );
|
|
result = v->value;
|
|
}
|
|
|
|
#ifdef OS_VMS
|
|
else if ( ( module->name && object_equal( module->name, constant_ENVIRON ) )
|
|
|| root_module() == module )
|
|
{
|
|
/* On VMS, when a variable from root or ENVIRON module is not found,
|
|
* explicitly request it from the process.
|
|
* By design, process variables (and logicals) are not made available
|
|
* to C main(), and thus will not get loaded in bulk to root/ENVRON.
|
|
* So we get around it by getting any such variable on first request.
|
|
*/
|
|
const char * val = getenv( object_str( symbol ) );
|
|
|
|
if ( val )
|
|
{
|
|
struct module_t * environ_module = module;
|
|
char * environ[ 2 ] = { 0 }; /* NULL-terminated */
|
|
string buf[ 1 ];
|
|
|
|
if ( root_module() == module )
|
|
{
|
|
environ_module = bindmodule( constant_ENVIRON );
|
|
}
|
|
|
|
string_copy( buf, object_str( symbol ) );
|
|
string_append( buf, "=" );
|
|
string_append( buf, val );
|
|
|
|
environ[ 0 ] = buf->value;
|
|
|
|
/* Load variable to global module, with splitting, for backward
|
|
* compatibility. Then to .ENVIRON, without splitting.
|
|
*/
|
|
var_defines( root_module(), environ, 1 );
|
|
var_defines( environ_module, environ, 0 );
|
|
string_free( buf );
|
|
|
|
if ( module->variables && ( v = (VARIABLE *)hash_find(
|
|
module->variables, symbol ) ) )
|
|
{
|
|
if ( is_debug_varget() )
|
|
var_dump( v->symbol, v->value, "get" );
|
|
result = v->value;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
LIST * var_get_and_clear_raw( module_t * module, OBJECT * symbol )
|
|
{
|
|
LIST * result = L0;
|
|
VARIABLE * v;
|
|
|
|
if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables,
|
|
symbol ) ) )
|
|
{
|
|
result = v->value;
|
|
v->value = L0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
* var_set() - set a variable in Jam's user defined symbol table
|
|
*
|
|
* 'flag' controls the relationship between new and old values of the variable:
|
|
* SET replaces the old with the new; APPEND appends the new to the old; DEFAULT
|
|
* only uses the new if the variable was previously unset.
|
|
*
|
|
* Copies symbol. Takes ownership of value.
|
|
*/
|
|
|
|
void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag
|
|
)
|
|
{
|
|
LIST * * v = var_enter( module, symbol );
|
|
|
|
if ( is_debug_varset() )
|
|
var_dump( symbol, value, "set" );
|
|
|
|
switch ( flag )
|
|
{
|
|
case VAR_SET: /* Replace value */
|
|
list_free( *v );
|
|
*v = value;
|
|
break;
|
|
|
|
case VAR_APPEND: /* Append value */
|
|
*v = list_append( *v, value );
|
|
break;
|
|
|
|
case VAR_DEFAULT: /* Set only if unset */
|
|
if ( list_empty( *v ) )
|
|
*v = value;
|
|
else
|
|
list_free( value );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* var_swap() - swap a variable's value with the given one
|
|
*/
|
|
|
|
LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value )
|
|
{
|
|
LIST * * v = var_enter( module, symbol );
|
|
LIST * oldvalue = *v;
|
|
if ( is_debug_varset() )
|
|
var_dump( symbol, value, "set" );
|
|
*v = value;
|
|
return oldvalue;
|
|
}
|
|
|
|
|
|
/*
|
|
* var_enter() - make new var symbol table entry, returning var ptr
|
|
*/
|
|
|
|
static LIST * * var_enter( struct module_t * module, OBJECT * symbol )
|
|
{
|
|
int found;
|
|
VARIABLE * v;
|
|
int n;
|
|
|
|
if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
|
|
return &module->fixed_variables[ n ];
|
|
|
|
if ( !module->variables )
|
|
module->variables = hashinit( sizeof( VARIABLE ), "variables" );
|
|
|
|
v = (VARIABLE *)hash_insert( module->variables, symbol, &found );
|
|
if ( !found )
|
|
{
|
|
v->symbol = object_copy( symbol );
|
|
v->value = L0;
|
|
}
|
|
|
|
return &v->value;
|
|
}
|
|
|
|
|
|
/*
|
|
* var_dump() - dump a variable to stdout
|
|
*/
|
|
|
|
static void var_dump( OBJECT * symbol, LIST * value, const char * what )
|
|
{
|
|
out_printf( "%s %s = ", what, object_str( symbol ) );
|
|
list_print( value );
|
|
out_printf( "\n" );
|
|
}
|
|
|
|
|
|
/*
|
|
* var_done() - free variable tables
|
|
*/
|
|
|
|
static void delete_var_( void * xvar, void * data )
|
|
{
|
|
VARIABLE * const v = (VARIABLE *)xvar;
|
|
object_free( v->symbol );
|
|
list_free( v->value );
|
|
}
|
|
|
|
void var_done( struct module_t * module )
|
|
{
|
|
list_free( saved_var );
|
|
saved_var = L0;
|
|
hashenumerate( module->variables, delete_var_, 0 );
|
|
hash_free( module->variables );
|
|
}
|