mirror of
https://github.com/boostorg/build.git
synced 2026-02-14 12:42:11 +00:00
Some system headers on POSIX systems indirectly include strings.h in extern "C" region. This sometimes results in Boost.Build's strings.h being included into such region, which marks all string_* functions as extern "C" and changes their name mangling rules accordingly, which causes linking errors. To resolve this header conflict, this commit renames strings.h to jam_strings.h. And strings.cpp to jam_strings.cpp for consistency. Fixes https://github.com/boostorg/build/issues/468.
394 lines
10 KiB
C++
394 lines
10 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_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.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 <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 )
|
|
{
|
|
string buf[ 1 ];
|
|
|
|
string_new( buf );
|
|
|
|
for ( ; *e; ++e )
|
|
{
|
|
const char * val;
|
|
|
|
if ( ( val = strchr( *e, '=' ) )
|
|
#if defined( OS_MAC )
|
|
/* On the mac (MPW), the var=val is actually var\0val */
|
|
/* Think different. */
|
|
|| ( val = *e + strlen( *e ) )
|
|
#endif
|
|
)
|
|
{
|
|
LIST * l = L0;
|
|
size_t const len = strlen( val + 1 );
|
|
int const quoted = ( val[ 1 ] == '"' ) && ( val[ len ] == '"' ) &&
|
|
( len > 1 );
|
|
|
|
if ( quoted && preprocess )
|
|
{
|
|
string_append_range( buf, val + 2, val + len );
|
|
l = list_push_back( l, object_new( buf->value ) );
|
|
string_truncate( buf, 0 );
|
|
}
|
|
else
|
|
{
|
|
const char * p;
|
|
const char * pp;
|
|
char split =
|
|
#if defined( OPT_NO_EXTERNAL_VARIABLE_SPLIT )
|
|
'\0'
|
|
#elif defined( OS_MAC )
|
|
','
|
|
#else
|
|
' '
|
|
#endif
|
|
;
|
|
|
|
/* Split *PATH at :'s, not spaces. */
|
|
if ( val - 4 >= *e )
|
|
{
|
|
if ( !strncmp( val - 4, "PATH", 4 ) ||
|
|
!strncmp( val - 4, "Path", 4 ) ||
|
|
!strncmp( val - 4, "path", 4 ) )
|
|
split = SPLITPATH;
|
|
}
|
|
|
|
/* Do the split. */
|
|
for
|
|
(
|
|
pp = val + 1;
|
|
preprocess && ( ( p = strchr( pp, split ) ) != 0 );
|
|
pp = p + 1
|
|
)
|
|
{
|
|
string_append_range( buf, pp, p );
|
|
l = list_push_back( l, object_new( buf->value ) );
|
|
string_truncate( buf, 0 );
|
|
}
|
|
|
|
l = list_push_back( l, object_new( pp ) );
|
|
}
|
|
|
|
/* Get name. */
|
|
string_append_range( buf, *e, val );
|
|
{
|
|
OBJECT * const varname = object_new( buf->value );
|
|
var_set( module, varname, l, VAR_SET );
|
|
object_free( varname );
|
|
}
|
|
string_truncate( buf, 0 );
|
|
}
|
|
}
|
|
string_free( buf );
|
|
}
|
|
|
|
|
|
/* 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 ( 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 ( 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 ( 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 ( 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 ( 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 );
|
|
}
|