blob: 0d9558d5da5a7d238eaffe6a82502d5362fa9431 [file] [log] [blame]
/*
* Copyright 1993, 2000 Christopher Seiwald.
*
* 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)
*/
/*
* headers.c - handle #includes in source files
*
* Using regular expressions provided as the variable $(HDRSCAN), headers()
* searches a file for #include files and phonies up a rule invocation:
* $(HDRRULE) <target> : <include files> ;
*
* External routines:
* headers() - scan a target for include files and call HDRRULE
*
* Internal routines:
* headers1() - using regexp, scan a file and build include LIST
*/
#include "jam.h"
#include "headers.h"
#include "compile.h"
#include "hdrmacro.h"
#include "lists.h"
#include "modules.h"
#include "object.h"
#include "parse.h"
#include "rules.h"
#include "subst.h"
#include "variable.h"
#ifdef OPT_HEADER_CACHE_EXT
# include "hcache.h"
#endif
#ifndef OPT_HEADER_CACHE_EXT
static LIST * headers1( LIST *, OBJECT * file, int rec, regexp * re[] );
#endif
/*
* headers() - scan a target for include files and call HDRRULE
*/
#define MAXINC 10
void headers( TARGET * t )
{
LIST * hdrscan;
LIST * hdrrule;
#ifndef OPT_HEADER_CACHE_EXT
LIST * headlist = L0;
#endif
regexp * re[ MAXINC ];
int rec = 0;
LISTITER iter;
LISTITER end;
hdrscan = var_get( root_module(), constant_HDRSCAN );
if ( list_empty( hdrscan ) )
return;
hdrrule = var_get( root_module(), constant_HDRRULE );
if ( list_empty( hdrrule ) )
return;
if ( DEBUG_HEADER )
printf( "header scan %s\n", object_str( t->name ) );
/* Compile all regular expressions in HDRSCAN */
iter = list_begin( hdrscan );
end = list_end( hdrscan );
for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) )
{
re[ rec++ ] = regex_compile( list_item( iter ) );
}
/* Doctor up call to HDRRULE rule */
/* Call headers1() to get LIST of included files. */
{
FRAME frame[ 1 ];
frame_init( frame );
lol_add( frame->args, list_new( object_copy( t->name ) ) );
#ifdef OPT_HEADER_CACHE_EXT
lol_add( frame->args, hcache( t, rec, re, hdrscan ) );
#else
lol_add( frame->args, headers1( headlist, t->boundname, rec, re ) );
#endif
if ( lol_get( frame->args, 1 ) )
{
OBJECT * rulename = list_front( hdrrule );
/* The third argument to HDRRULE is the bound name of $(<). */
lol_add( frame->args, list_new( object_copy( t->boundname ) ) );
list_free( evaluate_rule( bindrule( rulename, frame->module ), rulename, frame ) );
}
/* Clean up. */
frame_free( frame );
}
}
/*
* headers1() - using regexp, scan a file and build include LIST.
*/
#ifndef OPT_HEADER_CACHE_EXT
static
#endif
LIST * headers1( LIST * l, OBJECT * file, int rec, regexp * re[] )
{
FILE * f;
char buf[ 1024 ];
int i;
static regexp * re_macros = 0;
#ifdef OPT_IMPROVED_PATIENCE_EXT
static int count = 0;
++count;
if ( ( ( count == 100 ) || !( count % 1000 ) ) && DEBUG_MAKE )
{
printf( "...patience...\n" );
fflush( stdout );
}
#endif
/* The following regexp is used to detect cases where a file is included
* through a line like "#include MACRO".
*/
if ( re_macros == 0 )
{
OBJECT * const re_str = object_new(
"#[ \t]*include[ \t]*([A-Za-z][A-Za-z0-9_]*).*$" );
re_macros = regex_compile( re_str );
object_free( re_str );
}
if ( !( f = fopen( object_str( file ), "r" ) ) )
return l;
while ( fgets( buf, sizeof( buf ), f ) )
{
for ( i = 0; i < rec; ++i )
if ( regexec( re[ i ], buf ) && re[ i ]->startp[ 1 ] )
{
( (char *)re[ i ]->endp[ 1 ] )[ 0 ] = '\0';
if ( DEBUG_HEADER )
printf( "header found: %s\n", re[ i ]->startp[ 1 ] );
l = list_push_back( l, object_new( re[ i ]->startp[ 1 ] ) );
}
/* Special treatment for #include MACRO. */
if ( regexec( re_macros, buf ) && re_macros->startp[ 1 ] )
{
OBJECT * header_filename;
OBJECT * macro_name;
( (char *)re_macros->endp[ 1 ] )[ 0 ] = '\0';
if ( DEBUG_HEADER )
printf( "macro header found: %s", re_macros->startp[ 1 ] );
macro_name = object_new( re_macros->startp[ 1 ] );
header_filename = macro_header_get( macro_name );
object_free( macro_name );
if ( header_filename )
{
if ( DEBUG_HEADER )
printf( " resolved to '%s'\n", object_str( header_filename )
);
l = list_push_back( l, object_copy( header_filename ) );
}
else
{
if ( DEBUG_HEADER )
printf( " ignored !!\n" );
}
}
}
fclose( f );
return l;
}
void regerror( char const * s )
{
printf( "re error %s\n", s );
}