| 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 | # include "jam.h" |
|---|
| 13 | # include "lists.h" |
|---|
| 14 | # include "parse.h" |
|---|
| 15 | # include "compile.h" |
|---|
| 16 | # include "rules.h" |
|---|
| 17 | # include "variable.h" |
|---|
| 18 | # include "regexp.h" |
|---|
| 19 | # include "headers.h" |
|---|
| 20 | # include "hdrmacro.h" |
|---|
| 21 | # include "newstr.h" |
|---|
| 22 | |
|---|
| 23 | #ifdef OPT_HEADER_CACHE_EXT |
|---|
| 24 | # include "hcache.h" |
|---|
| 25 | #endif |
|---|
| 26 | |
|---|
| 27 | /* |
|---|
| 28 | * headers.c - handle #includes in source files |
|---|
| 29 | * |
|---|
| 30 | * Using regular expressions provided as the variable $(HDRSCAN), |
|---|
| 31 | * headers() searches a file for #include files and phonies up a |
|---|
| 32 | * rule invocation: |
|---|
| 33 | * |
|---|
| 34 | * $(HDRRULE) <target> : <include files> ; |
|---|
| 35 | * |
|---|
| 36 | * External routines: |
|---|
| 37 | * headers() - scan a target for include files and call HDRRULE |
|---|
| 38 | * |
|---|
| 39 | * Internal routines: |
|---|
| 40 | * headers1() - using regexp, scan a file and build include LIST |
|---|
| 41 | * |
|---|
| 42 | * 04/13/94 (seiwald) - added shorthand L0 for null list pointer |
|---|
| 43 | * 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule, |
|---|
| 44 | * so that headers() doesn't have to mock up a parse structure |
|---|
| 45 | * just to invoke a rule. |
|---|
| 46 | */ |
|---|
| 47 | |
|---|
| 48 | #ifndef OPT_HEADER_CACHE_EXT |
|---|
| 49 | static LIST *headers1( LIST *l, char *file, int rec, regexp *re[]); |
|---|
| 50 | #endif |
|---|
| 51 | |
|---|
| 52 | /* |
|---|
| 53 | * headers() - scan a target for include files and call HDRRULE |
|---|
| 54 | */ |
|---|
| 55 | |
|---|
| 56 | # define MAXINC 10 |
|---|
| 57 | |
|---|
| 58 | void |
|---|
| 59 | headers( TARGET *t ) |
|---|
| 60 | { |
|---|
| 61 | LIST *hdrscan; |
|---|
| 62 | LIST *hdrrule; |
|---|
| 63 | LIST *headlist = 0; |
|---|
| 64 | regexp *re[ MAXINC ]; |
|---|
| 65 | int rec = 0; |
|---|
| 66 | |
|---|
| 67 | if( !( hdrscan = var_get( "HDRSCAN" ) ) || |
|---|
| 68 | !( hdrrule = var_get( "HDRRULE" ) ) ) |
|---|
| 69 | return; |
|---|
| 70 | |
|---|
| 71 | if( DEBUG_HEADER ) |
|---|
| 72 | printf( "header scan %s\n", t->name ); |
|---|
| 73 | |
|---|
| 74 | /* Compile all regular expressions in HDRSCAN */ |
|---|
| 75 | |
|---|
| 76 | while( rec < MAXINC && hdrscan ) |
|---|
| 77 | { |
|---|
| 78 | re[rec++] = regex_compile( hdrscan->string ); |
|---|
| 79 | hdrscan = list_next( hdrscan ); |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | /* Doctor up call to HDRRULE rule */ |
|---|
| 83 | /* Call headers1() to get LIST of included files. */ |
|---|
| 84 | { |
|---|
| 85 | FRAME frame[1]; |
|---|
| 86 | frame_init( frame ); |
|---|
| 87 | lol_add( frame->args, list_new( L0, t->name ) ); |
|---|
| 88 | #ifdef OPT_HEADER_CACHE_EXT |
|---|
| 89 | lol_add( frame->args, hcache( t, rec, re, hdrscan ) ); |
|---|
| 90 | #else |
|---|
| 91 | lol_add( frame->args, headers1( headlist, t->boundname, rec, re ) ); |
|---|
| 92 | #endif |
|---|
| 93 | |
|---|
| 94 | if( lol_get( frame->args, 1 ) ) |
|---|
| 95 | { |
|---|
| 96 | /* The third argument to HDRRULE is the bound name of |
|---|
| 97 | * $(<) */ |
|---|
| 98 | lol_add( frame->args, list_new( L0, t->boundname ) ); |
|---|
| 99 | |
|---|
| 100 | list_free( evaluate_rule( hdrrule->string, frame ) ); |
|---|
| 101 | } |
|---|
| 102 | |
|---|
| 103 | /* Clean up */ |
|---|
| 104 | |
|---|
| 105 | frame_free( frame ); |
|---|
| 106 | } |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | /* |
|---|
| 110 | * headers1() - using regexp, scan a file and build include LIST |
|---|
| 111 | */ |
|---|
| 112 | |
|---|
| 113 | #ifdef OPT_HEADER_CACHE_EXT |
|---|
| 114 | LIST * |
|---|
| 115 | #else |
|---|
| 116 | static LIST * |
|---|
| 117 | #endif |
|---|
| 118 | headers1( |
|---|
| 119 | LIST *l, |
|---|
| 120 | char *file, |
|---|
| 121 | int rec, |
|---|
| 122 | regexp *re[] ) |
|---|
| 123 | { |
|---|
| 124 | FILE *f; |
|---|
| 125 | char buf[ 1024 ]; |
|---|
| 126 | int i; |
|---|
| 127 | static regexp *re_macros = 0; |
|---|
| 128 | |
|---|
| 129 | |
|---|
| 130 | #ifdef OPT_IMPROVED_PATIENCE_EXT |
|---|
| 131 | static int count = 0; |
|---|
| 132 | ++count; |
|---|
| 133 | if ( ((count == 100) || !( count % 1000 )) && DEBUG_MAKE ) |
|---|
| 134 | printf("...patience...\n"); |
|---|
| 135 | #endif |
|---|
| 136 | |
|---|
| 137 | /* the following regexp is used to detect cases where a */ |
|---|
| 138 | /* file is included through a line line "#include MACRO" */ |
|---|
| 139 | if ( re_macros == 0 ) |
|---|
| 140 | { |
|---|
| 141 | re_macros = regex_compile( |
|---|
| 142 | "^[ ]*#[ ]*include[ ]*([A-Za-z][A-Za-z0-9_]*).*$" ); |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | |
|---|
| 146 | if( !( f = fopen( file, "r" ) ) ) |
|---|
| 147 | return l; |
|---|
| 148 | |
|---|
| 149 | while( fgets( buf, sizeof( buf ), f ) ) |
|---|
| 150 | { |
|---|
| 151 | for( i = 0; i < rec; i++ ) |
|---|
| 152 | if( regexec( re[i], buf ) && re[i]->startp[1] ) |
|---|
| 153 | { |
|---|
| 154 | re[i]->endp[1][0] = '\0'; |
|---|
| 155 | |
|---|
| 156 | if( DEBUG_HEADER ) |
|---|
| 157 | printf( "header found: %s\n", re[i]->startp[1] ); |
|---|
| 158 | |
|---|
| 159 | l = list_new( l, newstr( re[i]->startp[1] ) ); |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | /* special treatment for #include MACRO */ |
|---|
| 163 | if ( regexec( re_macros, buf ) && re_macros->startp[1] ) |
|---|
| 164 | { |
|---|
| 165 | char* header_filename; |
|---|
| 166 | |
|---|
| 167 | re_macros->endp[1][0] = '\0'; |
|---|
| 168 | |
|---|
| 169 | if ( DEBUG_HEADER ) |
|---|
| 170 | printf( "macro header found: %s", re_macros->startp[1] ); |
|---|
| 171 | |
|---|
| 172 | header_filename = macro_header_get( re_macros->startp[1] ); |
|---|
| 173 | if (header_filename) |
|---|
| 174 | { |
|---|
| 175 | if ( DEBUG_HEADER ) |
|---|
| 176 | printf( " resolved to '%s'\n", header_filename ); |
|---|
| 177 | l = list_new( l, newstr( header_filename ) ); |
|---|
| 178 | } |
|---|
| 179 | else |
|---|
| 180 | { |
|---|
| 181 | if ( DEBUG_HEADER ) |
|---|
| 182 | printf( " ignored !!\n" ); |
|---|
| 183 | } |
|---|
| 184 | } |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | fclose( f ); |
|---|
| 188 | |
|---|
| 189 | return l; |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | void |
|---|
| 193 | regerror( char *s ) |
|---|
| 194 | { |
|---|
| 195 | printf( "re error %s\n", s ); |
|---|
| 196 | } |
|---|