summaryrefslogtreecommitdiff
path: root/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'search.c')
-rw-r--r--search.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/search.c b/search.c
new file mode 100644
index 0000000..6c23d97
--- /dev/null
+++ b/search.c
@@ -0,0 +1,223 @@
+/*
+ * 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 http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#include "jam.h"
+#include "lists.h"
+#include "search.h"
+#include "timestamp.h"
+#include "pathsys.h"
+#include "variable.h"
+#include "newstr.h"
+#include "compile.h"
+#include "strings.h"
+#include "hash.h"
+#include "filesys.h"
+#include <string.h>
+
+
+typedef struct _binding
+{
+ char * binding;
+ char * target;
+} BINDING;
+
+static struct hash *explicit_bindings = 0;
+
+
+void call_bind_rule
+(
+ char * target_,
+ char * boundname_
+)
+{
+ LIST * bind_rule = var_get( "BINDRULE" );
+ if ( bind_rule )
+ {
+ /* No guarantee that the target is an allocated string, so be on the
+ * safe side.
+ */
+ char * target = copystr( target_ );
+
+ /* Likewise, do not rely on implementation details of newstr.c: allocate
+ * a copy of boundname.
+ */
+ char * boundname = copystr( 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( L0, target ) );
+
+ lol_add( frame->args, list_new( L0, boundname ) );
+ if ( lol_get( frame->args, 1 ) )
+ evaluate_rule( bind_rule->string, frame );
+
+ /* Clean up */
+ frame_free( frame );
+ }
+ else
+ {
+ if ( boundname )
+ freestr( boundname );
+ if ( target )
+ freestr( target );
+ }
+ }
+}
+
+/*
+ * 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 on that location.
+ *
+ * Second, examine all directories in SEARCH. If there's file already
+ * or there's another target with the same name which was placed
+ * to this location via LOCATE setting, stop and return the location.
+ * In case of previous target, return it's name via the third argument.
+ *
+ * This bevahiour allow to handle dependency on generated files. If
+ * caller does not expect that target is generated, 0 can be passed as
+ * the third argument.
+ */
+
+char *
+search(
+ char *target,
+ time_t *time,
+ char **another_target,
+ int file
+)
+{
+ PATHNAME f[1];
+ LIST *varlist;
+ string buf[1];
+ int found = 0;
+ /* Will be set to 1 if target location is specified via LOCATE. */
+ int explicitly_located = 0;
+ char *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( target, f );
+
+ f->f_grist.ptr = 0;
+ f->f_grist.len = 0;
+
+ if ( ( varlist = var_get( "LOCATE" ) ) )
+ {
+ f->f_root.ptr = varlist->string;
+ f->f_root.len = strlen( varlist->string );
+
+ path_build( f, buf, 1 );
+
+ if ( DEBUG_SEARCH )
+ printf( "locate %s: %s\n", target, buf->value );
+
+ explicitly_located = 1;
+
+ timestamp( buf->value, time );
+ found = 1;
+ }
+ else if ( ( varlist = var_get( "SEARCH" ) ) )
+ {
+ while ( varlist )
+ {
+ BINDING b, *ba = &b;
+ file_info_t *ff;
+
+ f->f_root.ptr = varlist->string;
+ f->f_root.len = strlen( varlist->string );
+
+ string_truncate( buf, 0 );
+ path_build( f, buf, 1 );
+
+ if ( DEBUG_SEARCH )
+ printf( "search %s: %s\n", target, buf->value );
+
+ ff = file_query(buf->value);
+ timestamp( buf->value, time );
+
+ b.binding = buf->value;
+
+ if ( hashcheck( explicit_bindings, (HASHDATA**)&ba ) )
+ {
+ if ( DEBUG_SEARCH )
+ printf(" search %s: found explicitly located target %s\n",
+ target, ba->target);
+ if ( another_target )
+ *another_target = ba->target;
+ found = 1;
+ break;
+ }
+ else if ( ff && ff->time )
+ {
+ if ( !file || ff->is_file )
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ varlist = list_next( varlist );
+ }
+ }
+
+ if ( !found )
+ {
+ /* Look for the obvious */
+ /* This is a questionable move. Should we look in the */
+ /* obvious place if SEARCH is set? */
+
+ f->f_root.ptr = 0;
+ f->f_root.len = 0;
+
+ string_truncate( buf, 0 );
+ path_build( f, buf, 1 );
+
+ if ( DEBUG_SEARCH )
+ printf( "search %s: %s\n", target, buf->value );
+
+ timestamp( buf->value, time );
+ }
+
+ boundname = newstr( buf->value );
+ string_free( buf );
+
+ if ( explicitly_located )
+ {
+ BINDING b;
+ BINDING * ba = &b;
+ b.binding = boundname;
+ b.target = target;
+ /* CONSIDER: we probably should issue a warning is another file
+ is explicitly bound to the same location. This might break
+ compatibility, though. */
+ hashenter( explicit_bindings, (HASHDATA * *)&ba );
+ }
+
+ /* prepare a call to BINDRULE if the variable is set */
+ call_bind_rule( target, boundname );
+
+ return boundname;
+}