diff options
Diffstat (limited to '')
-rw-r--r-- | src/boost/tools/build/src/engine/search.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/src/boost/tools/build/src/engine/search.cpp b/src/boost/tools/build/src/engine/search.cpp new file mode 100644 index 000000000..7529e02dc --- /dev/null +++ b/src/boost/tools/build/src/engine/search.cpp @@ -0,0 +1,275 @@ +/* + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. + * + * This file is part of Jam - see jam.c for Copyright information. + */ + +/* This file is ALSO: + * Copyright 2001-2004 David Abrahams. + * 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) + */ + +#include "jam.h" +#include "search.h" + +#include "compile.h" +#include "filesys.h" +#include "hash.h" +#include "lists.h" +#include "object.h" +#include "pathsys.h" +#include "jam_strings.h" +#include "timestamp.h" +#include "variable.h" +#include "output.h" + +#include <string.h> + + +typedef struct _binding +{ + OBJECT * binding; + OBJECT * target; +} BINDING; + +static struct hash * explicit_bindings = 0; + + +void call_bind_rule( OBJECT * target_, OBJECT * boundname_ ) +{ + LIST * const bind_rule = var_get( root_module(), constant_BINDRULE ); + if ( !list_empty( bind_rule ) ) + { + OBJECT * target = object_copy( target_ ); + OBJECT * boundname = object_copy( boundname_ ); + if ( boundname && target ) + { + /* Prepare the argument list. */ + FRAME frame[ 1 ]; + frame_init( frame ); + + /* First argument is the target name. */ + lol_add( frame->args, list_new( target ) ); + + lol_add( frame->args, list_new( boundname ) ); + if ( lol_get( frame->args, 1 ) ) + { + OBJECT * rulename = list_front( bind_rule ); + list_free( evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ) ); + } + + /* Clean up */ + frame_free( frame ); + } + else + { + if ( boundname ) + object_free( boundname ); + if ( target ) + object_free( target ); + } + } +} + +/* Records the binding of a target with an explicit LOCATE. */ +void set_explicit_binding( OBJECT * target, OBJECT * locate ) +{ + OBJECT * boundname; + OBJECT * key; + PATHNAME f[ 1 ]; + string buf[ 1 ]; + int found; + BINDING * ba; + + if ( !explicit_bindings ) + explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified " + "locations" ); + + string_new( buf ); + + /* Parse the filename. */ + path_parse( object_str( target ), f ); + + /* Ignore the grist. */ + f->f_grist.ptr = 0; + f->f_grist.len = 0; + + /* Root the target path at the given location. */ + f->f_root.ptr = object_str( locate ); + f->f_root.len = strlen( object_str( locate ) ); + + path_build( f, buf ); + boundname = object_new( buf->value ); + if ( DEBUG_SEARCH ) + out_printf( "explicit locate %s: %s\n", object_str( target ), buf->value ); + string_free( buf ); + key = path_as_key( boundname ); + object_free( boundname ); + + ba = (BINDING *)hash_insert( explicit_bindings, key, &found ); + if ( !found ) + { + ba->binding = key; + ba->target = target; + } + else + object_free( key ); +} + +/* + * search.c - find a target along $(SEARCH) or $(LOCATE). + * + * First, check if LOCATE is set. If so, use it to determine the location of + * target and return, regardless of whether anything exists at that location. + * + * Second, examine all directories in SEARCH. If the file exists there or there + * is another target with the same name already placed at this location via the + * LOCATE setting, stop and return the location. In case of a previous target, + * return its name via the 'another_target' argument. + * + * This behaviour allows handling dependencies on generated files. + * + * If caller does not expect that the target is generated, 0 can be passed as + * 'another_target'. + */ + +OBJECT * search( OBJECT * target, timestamp * const time, + OBJECT * * another_target, int const file ) +{ + PATHNAME f[ 1 ]; + LIST * varlist; + string buf[ 1 ]; + int found = 0; + OBJECT * boundname = 0; + + if ( another_target ) + *another_target = 0; + + if ( !explicit_bindings ) + explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified " + "locations" ); + + string_new( buf ); + + /* Parse the filename. */ + path_parse( object_str( target ), f ); + + f->f_grist.ptr = 0; + f->f_grist.len = 0; + + varlist = var_get( root_module(), constant_LOCATE ); + if ( !list_empty( varlist ) ) + { + OBJECT * key; + f->f_root.ptr = object_str( list_front( varlist ) ); + f->f_root.len = strlen( object_str( list_front( varlist ) ) ); + + path_build( f, buf ); + + if ( DEBUG_SEARCH ) + out_printf( "locate %s: %s\n", object_str( target ), buf->value ); + + key = object_new( buf->value ); + timestamp_from_path( time, key ); + object_free( key ); + found = 1; + } + else if ( varlist = var_get( root_module(), constant_SEARCH ), + !list_empty( varlist ) ) + { + LISTITER iter = list_begin( varlist ); + LISTITER const end = list_end( varlist ); + for ( ; iter != end; iter = list_next( iter ) ) + { + BINDING * ba; + file_info_t * ff; + OBJECT * key; + OBJECT * test_path; + + f->f_root.ptr = object_str( list_item( iter ) ); + f->f_root.len = strlen( object_str( list_item( iter ) ) ); + + string_truncate( buf, 0 ); + path_build( f, buf ); + + if ( DEBUG_SEARCH ) + out_printf( "search %s: %s\n", object_str( target ), buf->value ); + + test_path = object_new( buf->value ); + key = path_as_key( test_path ); + object_free( test_path ); + ff = file_query( key ); + timestamp_from_path( time, key ); + + if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) ) + { + if ( DEBUG_SEARCH ) + out_printf(" search %s: found explicitly located target %s\n", + object_str( target ), object_str( ba->target ) ); + if ( another_target ) + *another_target = ba->target; + found = 1; + object_free( key ); + break; + } + else if ( ff ) + { + if ( !file || ff->is_file ) + { + found = 1; + object_free( key ); + break; + } + } + object_free( key ); + } + } + + if ( !found ) + { + /* Look for the obvious. */ + /* This is a questionable move. Should we look in the obvious place if + * SEARCH is set? + */ + OBJECT * key; + + f->f_root.ptr = 0; + f->f_root.len = 0; + + string_truncate( buf, 0 ); + path_build( f, buf ); + + if ( DEBUG_SEARCH ) + out_printf( "search %s: %s\n", object_str( target ), buf->value ); + + key = object_new( buf->value ); + timestamp_from_path( time, key ); + object_free( key ); + } + + boundname = object_new( buf->value ); + string_free( buf ); + + /* Prepare a call to BINDRULE if the variable is set. */ + call_bind_rule( target, boundname ); + + return boundname; +} + + +static void free_binding( void * xbinding, void * data ) +{ + object_free( ( (BINDING *)xbinding )->binding ); +} + + +void search_done( void ) +{ + if ( explicit_bindings ) + { + hashenumerate( explicit_bindings, free_binding, 0 ); + hashdone( explicit_bindings ); + } +} |