1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
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 * Distributed under the Boost Software License, Version 1.0.
10 * (See accompanying file LICENSE_1_0.txt or copy at
11 * http://www.boost.org/LICENSE_1_0.txt)
12 */
13
14 #include "jam.h"
15 #include "search.h"
16
17 #include "compile.h"
18 #include "filesys.h"
19 #include "hash.h"
20 #include "lists.h"
21 #include "object.h"
22 #include "pathsys.h"
23 #include "jam_strings.h"
24 #include "timestamp.h"
25 #include "variable.h"
26 #include "output.h"
27
28 #include <string.h>
29
30
31 typedef struct _binding
32 {
33 OBJECT * binding;
34 OBJECT * target;
35 } BINDING;
36
37 static struct hash * explicit_bindings = 0;
38
39
call_bind_rule(OBJECT * target_,OBJECT * boundname_)40 void call_bind_rule( OBJECT * target_, OBJECT * boundname_ )
41 {
42 LIST * const bind_rule = var_get( root_module(), constant_BINDRULE );
43 if ( !list_empty( bind_rule ) )
44 {
45 OBJECT * target = object_copy( target_ );
46 OBJECT * boundname = object_copy( boundname_ );
47 if ( boundname && target )
48 {
49 /* Prepare the argument list. */
50 FRAME frame[ 1 ];
51 frame_init( frame );
52
53 /* First argument is the target name. */
54 lol_add( frame->args, list_new( target ) );
55
56 lol_add( frame->args, list_new( boundname ) );
57 if ( lol_get( frame->args, 1 ) )
58 {
59 OBJECT * rulename = list_front( bind_rule );
60 list_free( evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ) );
61 }
62
63 /* Clean up */
64 frame_free( frame );
65 }
66 else
67 {
68 if ( boundname )
69 object_free( boundname );
70 if ( target )
71 object_free( target );
72 }
73 }
74 }
75
76 /* Records the binding of a target with an explicit LOCATE. */
set_explicit_binding(OBJECT * target,OBJECT * locate)77 void set_explicit_binding( OBJECT * target, OBJECT * locate )
78 {
79 OBJECT * boundname;
80 OBJECT * key;
81 PATHNAME f[ 1 ];
82 string buf[ 1 ];
83 int found;
84 BINDING * ba;
85
86 if ( !explicit_bindings )
87 explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified "
88 "locations" );
89
90 string_new( buf );
91
92 /* Parse the filename. */
93 path_parse( object_str( target ), f );
94
95 /* Ignore the grist. */
96 f->f_grist.ptr = 0;
97 f->f_grist.len = 0;
98
99 /* Root the target path at the given location. */
100 f->f_root.ptr = object_str( locate );
101 f->f_root.len = strlen( object_str( locate ) );
102
103 path_build( f, buf );
104 boundname = object_new( buf->value );
105 if ( DEBUG_SEARCH )
106 out_printf( "explicit locate %s: %s\n", object_str( target ), buf->value );
107 string_free( buf );
108 key = path_as_key( boundname );
109 object_free( boundname );
110
111 ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
112 if ( !found )
113 {
114 ba->binding = key;
115 ba->target = target;
116 }
117 else
118 object_free( key );
119 }
120
121 /*
122 * search.c - find a target along $(SEARCH) or $(LOCATE).
123 *
124 * First, check if LOCATE is set. If so, use it to determine the location of
125 * target and return, regardless of whether anything exists at that location.
126 *
127 * Second, examine all directories in SEARCH. If the file exists there or there
128 * is another target with the same name already placed at this location via the
129 * LOCATE setting, stop and return the location. In case of a previous target,
130 * return its name via the 'another_target' argument.
131 *
132 * This behaviour allows handling dependencies on generated files.
133 *
134 * If caller does not expect that the target is generated, 0 can be passed as
135 * 'another_target'.
136 */
137
search(OBJECT * target,timestamp * const time,OBJECT ** another_target,int const file)138 OBJECT * search( OBJECT * target, timestamp * const time,
139 OBJECT * * another_target, int const file )
140 {
141 PATHNAME f[ 1 ];
142 LIST * varlist;
143 string buf[ 1 ];
144 int found = 0;
145 OBJECT * boundname = 0;
146
147 if ( another_target )
148 *another_target = 0;
149
150 if ( !explicit_bindings )
151 explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified "
152 "locations" );
153
154 string_new( buf );
155
156 /* Parse the filename. */
157 path_parse( object_str( target ), f );
158
159 f->f_grist.ptr = 0;
160 f->f_grist.len = 0;
161
162 varlist = var_get( root_module(), constant_LOCATE );
163 if ( !list_empty( varlist ) )
164 {
165 OBJECT * key;
166 f->f_root.ptr = object_str( list_front( varlist ) );
167 f->f_root.len = strlen( object_str( list_front( varlist ) ) );
168
169 path_build( f, buf );
170
171 if ( DEBUG_SEARCH )
172 out_printf( "locate %s: %s\n", object_str( target ), buf->value );
173
174 key = object_new( buf->value );
175 timestamp_from_path( time, key );
176 object_free( key );
177 found = 1;
178 }
179 else if ( varlist = var_get( root_module(), constant_SEARCH ),
180 !list_empty( varlist ) )
181 {
182 LISTITER iter = list_begin( varlist );
183 LISTITER const end = list_end( varlist );
184 for ( ; iter != end; iter = list_next( iter ) )
185 {
186 BINDING * ba;
187 file_info_t * ff;
188 OBJECT * key;
189 OBJECT * test_path;
190
191 f->f_root.ptr = object_str( list_item( iter ) );
192 f->f_root.len = strlen( object_str( list_item( iter ) ) );
193
194 string_truncate( buf, 0 );
195 path_build( f, buf );
196
197 if ( DEBUG_SEARCH )
198 out_printf( "search %s: %s\n", object_str( target ), buf->value );
199
200 test_path = object_new( buf->value );
201 key = path_as_key( test_path );
202 object_free( test_path );
203 ff = file_query( key );
204 timestamp_from_path( time, key );
205
206 if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
207 {
208 if ( DEBUG_SEARCH )
209 out_printf(" search %s: found explicitly located target %s\n",
210 object_str( target ), object_str( ba->target ) );
211 if ( another_target )
212 *another_target = ba->target;
213 found = 1;
214 object_free( key );
215 break;
216 }
217 else if ( ff )
218 {
219 if ( !file || ff->is_file )
220 {
221 found = 1;
222 object_free( key );
223 break;
224 }
225 }
226 object_free( key );
227 }
228 }
229
230 if ( !found )
231 {
232 /* Look for the obvious. */
233 /* This is a questionable move. Should we look in the obvious place if
234 * SEARCH is set?
235 */
236 OBJECT * key;
237
238 f->f_root.ptr = 0;
239 f->f_root.len = 0;
240
241 string_truncate( buf, 0 );
242 path_build( f, buf );
243
244 if ( DEBUG_SEARCH )
245 out_printf( "search %s: %s\n", object_str( target ), buf->value );
246
247 key = object_new( buf->value );
248 timestamp_from_path( time, key );
249 object_free( key );
250 }
251
252 boundname = object_new( buf->value );
253 string_free( buf );
254
255 /* Prepare a call to BINDRULE if the variable is set. */
256 call_bind_rule( target, boundname );
257
258 return boundname;
259 }
260
261
free_binding(void * xbinding,void * data)262 static void free_binding( void * xbinding, void * data )
263 {
264 object_free( ( (BINDING *)xbinding )->binding );
265 }
266
267
search_done(void)268 void search_done( void )
269 {
270 if ( explicit_bindings )
271 {
272 hashenumerate( explicit_bindings, free_binding, 0 );
273 hashdone( explicit_bindings );
274 }
275 }
276