• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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