2 * Copyright 1993, 2000 Christopher Seiwald.
3 * This file is part of Jam - see jam.c for Copyright information.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * headers.c - handle #includes in source files
21 * Using regular expressions provided as the variable $(HDRSCAN),
22 * headers() searches a file for #include files and phonies up a
25 * $(HDRRULE) <target> : <include files> ;
28 * headers() - scan a target for include files and call HDRRULE
31 * headers1() - using regexp, scan a file and build include LIST
48 #ifndef OPT_HEADER_CACHE_EXT
49 static LIST *headers1 (const char *file, LIST *hdrscan);
55 * headers() - scan a target for include files and call HDRRULE
59 void headers (TARGET
*t
) {
63 if (!(hdrscan
= var_get("HDRSCAN")) || !(hdrrule
= var_get("HDRRULE"))) return;
64 /* doctor up call to HDRRULE rule */
65 /* call headers1() to get LIST of included files */
66 if (DEBUG_HEADER
) printf("header scan %s\n", t
->name
);
68 lol_add(&lol
, list_new(L0
, t
->name
, 1));
70 #ifdef OPT_HEADER_CACHE_EXT
71 lol_add(&lol, hcache(t, hdrscan));
73 lol_add(&lol, headers1(t->boundname, hdrscan));
76 lol_add(&lol
, hcache(t
, hdrscan
));
77 if (lol_get(&lol
, 1)) list_free(evaluate_rule(hdrrule
->string
, &lol
, L0
));
84 * headers1() - using regexp, scan a file and build include LIST
87 #ifndef OPT_HEADER_CACHE_EXT
91 LIST
*headers1 (const char *file
, LIST
*hdrscan
) {
97 regexp_t
*re_macros
, *re_dlinc
= NULL
;
99 int line_size
= 16384;
100 char *buf
; /* line_size size */
101 dstring_t buf2
, buf3
;
103 for (const LIST
*t
= var_get("HDRPATH_IGNORE"); t
!= NULL
; t
= t
->next
) {
104 if (t
->string
&& t
->string
[0]) {
105 if (strncmp(file
, t
->string
, strlen(t
->string
)) == 0) {
106 if (DEBUG_HEADER
) printf("DBG: ignoring header [%s]\n", file
);
112 char *t
= strrchr(file
, '.');
113 dlang
= (t
!= NULL
&& (strcmp(t
, ".d") == 0 || strcmp(t
, ".di") == 0));
115 if (DEBUG_HEADER
) printf("DBG: trying header [%s] (D=%d)\n", file
, dlang
);
116 //fprintf(stderr, "DBG: trying header [%s] (D=%d)\n", file, dlang);
117 if (!(f
= fopen(file
, "r"))) {
118 // for D: try package.d
120 char *na
= alloca(strlen(file
)*2);
122 char *t
= strrchr(na
, '.');
123 if (t
!= NULL
) *na
= 0;
124 strcat(na
, "/package.d");
125 //fprintf(stderr, "*** TRYING package: [%s]\n", na);
127 if (!(f
= fopen(file
, "r"))) return result
;
128 //fprintf(stderr, "*** FOUND package: [%s]\n", na);
134 //fprintf(stderr, "DBG: processing header [%s] (D=%d)\n", file, dlang);
137 LIST *t = var_get("DLANG");
138 dlang = (t != NULL && t->string[0]);
139 //fprintf(stderr, "DLANG: %d\n", dlang);
143 re
[rec
++] = regexp_compile("\\bimport\\s+(.+?)\\s*;", 0);
144 re
[rec
++] = regexp_compile("\\bimport\\s*\\((.+?)\\)", 0);
145 re_dlinc
= regexp_compile("\\s*([^,;]+?)\\s*", 0);
148 while (rec
< MAXINC
&& hdrscan
) {
149 //printf("header re %d: [%s]\n", rec, hdrscan->string);
150 re
[rec
] = regexp_compile(hdrscan
->string
, 0);
152 hdrscan
= list_next(hdrscan
);
155 /* the following regexp is used to detect cases where a */
156 /* file is included through a line line "#include MACRO" */
157 re_macros
= regexp_compile("^\\s*#\\s*include\\s+([A-Za-z_][A-Za-z0-9_]*).*$", 0);
158 if (DEBUG_HEADER
) printf("header processing: [%s] (%d)\n", file
, rec
);
159 if ((buf
= malloc(line_size
)) == NULL
) { fprintf(stderr
, "FATAL: out of memory!\n"); abort(); }
162 while (fgets(buf
, line_size
, f
)) {
163 for (i
= 0; i
< rec
; ++i
) {
164 mt
[0].sp
= mt
[0].ep
= NULL
;
165 if (regexp_execute(re
[i
], buf
, mt
, 2) > 0 && mt
[1].sp
!= NULL
) {
166 /* copy and terminate extracted string */
167 int l
= mt
[1].ep
-mt
[1].sp
;
168 dstr_set_buf(&buf2
, mt
[1].sp
, l
);
169 if (dlang
&& i
<= 1) {
170 //fprintf(stderr, "dlang: [%s]\n", dstr_cstr(&buf2));
172 /* this is DLang 'import' directive */
173 const char *s
= dstr_cstr(&buf2
);
176 if (!regexp_execute(re_dlinc
, s
, mt
, 2) || mt
[1].sp
== NULL
) break;
177 dstr_set_buf(&buf3
, mt
[1].sp
, mt
[1].ep
-mt
[1].sp
);
178 dstr_push_cstr(&buf3
, ".d");
179 p
= dstr_cstr(&buf3
);
180 if ((t
= strchr(p
, ':')) != NULL
) *t
= 0;
181 if ((t
= strchr(p
, '=')) != NULL
) p
= t
+1;
182 while (*p
&& isspace(*p
)) ++p
;
185 while (t
>= p
&& isspace(*t
)) --t
;
189 for (t
= p
; *t
; ++t
) if (*t
== '.') *t
= '/';
190 *(strrchr(p
, '/')) = '.'; // restore '.d'
191 //fprintf(stderr, "dlang include: [%s]\n", p);
192 result
= list_new(result
, p
, 0);
197 /* this is DLang import() operator */
198 /* TODO: process string escapes */
199 //fprintf(stderr, "II: [%s]\n", dstr_cstr(&buf2));
200 if (dstr_cstr(&buf2
)[0] == '"' || dstr_cstr(&buf2
)[0] == '`') {
201 char *fn
= strdup(dstr_cstr(&buf2
)+1);
202 if (fn
[0] && fn
[1] && fn
[strlen(fn
)-1] == dstr_cstr(&buf2
)[dstr_len(&buf2
)-1]) {
203 fn
[strlen(fn
)-1] = 0;
204 //fprintf(stderr, "import directive: [%s]\n", fn);
205 result
= list_new(result
, fn
, 0);
211 result
= list_new(result
, dstr_cstr(&buf2
), 0);
213 if (DEBUG_HEADER
) printf("header found: %s\n", dstr_cstr(&buf2
));
216 /* special treatment for #include MACRO */
217 mt
[0].sp
= mt
[0].ep
= NULL
;
218 if (regexp_execute(re_macros
, buf
, mt
, 2) > 0 && mt
[1].sp
!= NULL
) {
219 const char *header_filename
;
220 int l
= mt
[1].ep
-mt
[1].sp
;
221 dstr_set_buf(&buf2
, mt
[1].sp
, l
);
222 if (DEBUG_HEADER
) printf("macro header found: %s", dstr_cstr(&buf2
));
223 header_filename
= macro_header_get(dstr_cstr(&buf2
));
224 if (header_filename
) {
225 if (DEBUG_HEADER
) printf(" resolved to '%s'\n", header_filename
);
226 result
= list_new(result
, header_filename
, 0);
228 if (DEBUG_HEADER
) printf(" ignored !!\n");
236 if (re_dlinc
!= NULL
) regexp_free(re_dlinc
);
237 regexp_free(re_macros
);
238 while (--rec
>= 0) regexp_free(re
[rec
]);