1 /*
2 * Copyright 1993, 2000 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6 /* This file is ALSO:
7 * Copyright 2001-2004 David Abrahams.
8 * Distributed under the Boost Software License, Version 1.0.
9 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
10 */
11
12 /*
13 * headers.c - handle #includes in source files
14 *
15 * Using regular expressions provided as the variable $(HDRSCAN), headers()
16 * searches a file for #include files and phonies up a rule invocation:
17 * $(HDRRULE) <target> : <include files> ;
18 *
19 * External routines:
20 * headers() - scan a target for include files and call HDRRULE
21 *
22 * Internal routines:
23 * headers1() - using regexp, scan a file and build include LIST
24 */
25
26 #include "jam.h"
27 #include "headers.h"
28
29 #include "compile.h"
30 #include "hdrmacro.h"
31 #include "lists.h"
32 #include "modules.h"
33 #include "object.h"
34 #include "parse.h"
35 #include "rules.h"
36 #include "subst.h"
37 #include "variable.h"
38 #include "output.h"
39
40 #ifdef OPT_HEADER_CACHE_EXT
41 # include "hcache.h"
42 #endif
43
44 #include <errno.h>
45 #include <string.h>
46
47 #ifndef OPT_HEADER_CACHE_EXT
48 static LIST * headers1( LIST *, OBJECT * file, int rec, regexp * re[] );
49 #endif
50
51
52 /*
53 * headers() - scan a target for include files and call HDRRULE
54 */
55
56 #define MAXINC 10
57
headers(TARGET * t)58 void headers( TARGET * t )
59 {
60 LIST * hdrscan;
61 LIST * hdrrule;
62 #ifndef OPT_HEADER_CACHE_EXT
63 LIST * headlist = L0;
64 #endif
65 regexp * re[ MAXINC ];
66 int rec = 0;
67 LISTITER iter;
68 LISTITER end;
69
70 hdrscan = var_get( root_module(), constant_HDRSCAN );
71 if ( list_empty( hdrscan ) )
72 return;
73
74 hdrrule = var_get( root_module(), constant_HDRRULE );
75 if ( list_empty( hdrrule ) )
76 return;
77
78 if ( DEBUG_HEADER )
79 out_printf( "header scan %s\n", object_str( t->name ) );
80
81 /* Compile all regular expressions in HDRSCAN */
82 iter = list_begin( hdrscan );
83 end = list_end( hdrscan );
84 for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) )
85 {
86 re[ rec++ ] = regex_compile( list_item( iter ) );
87 }
88
89 /* Doctor up call to HDRRULE rule */
90 /* Call headers1() to get LIST of included files. */
91 {
92 FRAME frame[ 1 ];
93 frame_init( frame );
94 lol_add( frame->args, list_new( object_copy( t->name ) ) );
95 #ifdef OPT_HEADER_CACHE_EXT
96 lol_add( frame->args, hcache( t, rec, re, hdrscan ) );
97 #else
98 lol_add( frame->args, headers1( headlist, t->boundname, rec, re ) );
99 #endif
100
101 if ( lol_get( frame->args, 1 ) )
102 {
103 OBJECT * rulename = list_front( hdrrule );
104 /* The third argument to HDRRULE is the bound name of $(<). */
105 lol_add( frame->args, list_new( object_copy( t->boundname ) ) );
106 list_free( evaluate_rule( bindrule( rulename, frame->module ), rulename, frame ) );
107 }
108
109 /* Clean up. */
110 frame_free( frame );
111 }
112 }
113
114
115 /*
116 * headers1() - using regexp, scan a file and build include LIST.
117 */
118
119 #ifndef OPT_HEADER_CACHE_EXT
120 static
121 #endif
headers1(LIST * l,OBJECT * file,int rec,regexp * re[])122 LIST * headers1( LIST * l, OBJECT * file, int rec, regexp * re[] )
123 {
124 FILE * f;
125 char buf[ 1024 ];
126 int i;
127 static regexp * re_macros = 0;
128
129 #ifdef OPT_IMPROVED_PATIENCE_EXT
130 static int count = 0;
131 ++count;
132 if ( ( ( count == 100 ) || !( count % 1000 ) ) && DEBUG_MAKE )
133 {
134 out_printf( "...patience...\n" );
135 out_flush();
136 }
137 #endif
138
139 /* The following regexp is used to detect cases where a file is included
140 * through a line like "#include MACRO".
141 */
142 if ( re_macros == 0 )
143 {
144 OBJECT * const re_str = object_new(
145 "#[ \t]*include[ \t]*([A-Za-z][A-Za-z0-9_]*).*$" );
146 re_macros = regex_compile( re_str );
147 object_free( re_str );
148 }
149
150 if ( !( f = fopen( object_str( file ), "r" ) ) )
151 {
152 /* No source files will be generated when -n flag is passed */
153 if ( !globs.noexec || errno != ENOENT )
154 err_printf( "[errno %d] failed to scan file '%s': %s",
155 errno, object_str( file ), strerror(errno) );
156 return l;
157 }
158
159 while ( fgets( buf, sizeof( buf ), f ) )
160 {
161 for ( i = 0; i < rec; ++i )
162 if ( regexec( re[ i ], buf ) && re[ i ]->startp[ 1 ] )
163 {
164 ( (char *)re[ i ]->endp[ 1 ] )[ 0 ] = '\0';
165 if ( DEBUG_HEADER )
166 out_printf( "header found: %s\n", re[ i ]->startp[ 1 ] );
167 l = list_push_back( l, object_new( re[ i ]->startp[ 1 ] ) );
168 }
169
170 /* Special treatment for #include MACRO. */
171 if ( regexec( re_macros, buf ) && re_macros->startp[ 1 ] )
172 {
173 OBJECT * header_filename;
174 OBJECT * macro_name;
175
176 ( (char *)re_macros->endp[ 1 ] )[ 0 ] = '\0';
177
178 if ( DEBUG_HEADER )
179 out_printf( "macro header found: %s", re_macros->startp[ 1 ] );
180
181 macro_name = object_new( re_macros->startp[ 1 ] );
182 header_filename = macro_header_get( macro_name );
183 object_free( macro_name );
184 if ( header_filename )
185 {
186 if ( DEBUG_HEADER )
187 out_printf( " resolved to '%s'\n", object_str( header_filename )
188 );
189 l = list_push_back( l, object_copy( header_filename ) );
190 }
191 else
192 {
193 if ( DEBUG_HEADER )
194 out_printf( " ignored !!\n" );
195 }
196 }
197 }
198
199 fclose( f );
200 return l;
201 }
202
203
regerror(char const * s)204 void regerror( char const * s )
205 {
206 out_printf( "re error %s\n", s );
207 }
208