nothing
[k8jam.git] / src / headers.c
blob7ded295cc984ed4837b7901bab0b85c72afc4b5d
1 /*
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
23 * rule invocation:
25 * $(HDRRULE) <target> : <include files> ;
27 * External routines:
28 * headers() - scan a target for include files and call HDRRULE
30 * Internal routines:
31 * headers1() - using regexp, scan a file and build include LIST
33 #include "jam.h"
34 #include "lists.h"
35 #include "parse.h"
36 #include "compile.h"
37 #include "rules.h"
38 #include "variable.h"
39 #include "re9.h"
40 #include "headers.h"
41 #include "newstr.h"
42 #include "hdrmacro.h"
43 #include "hcache.h"
44 #include "dstrings.h"
48 #ifndef OPT_HEADER_CACHE_EXT
49 static LIST *headers1 (const char *file, LIST *hdrscan);
50 #endif
55 * headers() - scan a target for include files and call HDRRULE
57 #define MAXINC (32)
59 void headers (TARGET *t) {
60 LIST *hdrscan;
61 LIST *hdrrule;
62 LOL lol;
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);
67 lol_init(&lol);
68 lol_add(&lol, list_new(L0, t->name, 1));
70 #ifdef OPT_HEADER_CACHE_EXT
71 lol_add(&lol, hcache(t, hdrscan));
72 #else
73 lol_add(&lol, headers1(t->boundname, hdrscan));
74 #endif
76 lol_add(&lol, hcache(t, hdrscan));
77 if (lol_get(&lol, 1)) list_free(evaluate_rule(hdrrule->string, &lol, L0));
78 /* clean up */
79 lol_free(&lol);
84 * headers1() - using regexp, scan a file and build include LIST
87 #ifndef OPT_HEADER_CACHE_EXT
88 static
89 #endif
91 LIST *headers1 (const char *file, LIST *hdrscan) {
92 FILE *f;
93 int i;
94 int rec = 0;
95 LIST *result = 0;
96 regexp_t *re[MAXINC];
97 regexp_t *re_macros, *re_dlinc = NULL;
98 re9_sub_t mt[4];
99 int line_size = 16384;
100 char *buf; /* line_size size */
101 dstring_t buf2, buf3;
102 int dlang = 0;
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);
107 return result;
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
119 if (dlang) {
120 char *na = alloca(strlen(file)*2);
121 strcpy(na, file);
122 char *t = strrchr(na, '.');
123 if (t != NULL) *na = 0;
124 strcat(na, "/package.d");
125 //fprintf(stderr, "*** TRYING package: [%s]\n", na);
126 file = na;
127 if (!(f = fopen(file, "r"))) return result;
128 //fprintf(stderr, "*** FOUND package: [%s]\n", na);
129 } else {
130 return result;
132 return result;
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);
142 if (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);
147 if (!dlang) {
148 while (rec < MAXINC && hdrscan) {
149 //printf("header re %d: [%s]\n", rec, hdrscan->string);
150 re[rec] = regexp_compile(hdrscan->string, 0);
151 ++rec;
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(); }
160 dstr_init(&buf2);
161 dstr_init(&buf3);
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));
171 if (i == 0) {
172 /* this is DLang 'import' directive */
173 const char *s = dstr_cstr(&buf2);
174 while (*s) {
175 char *p, *t;
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;
183 if (*p) {
184 t = p+strlen(p)-1;
185 while (t >= p && isspace(*t)) --t;
186 t[1] = 0;
188 if (*p) {
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);
194 s = mt[1].ep;
196 } else {
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);
207 free(fn);
210 } else {
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);
227 } else {
228 if (DEBUG_HEADER) printf(" ignored !!\n");
232 dstr_done(&buf3);
233 dstr_done(&buf2);
234 free(buf);
235 fclose(f);
236 if (re_dlinc != NULL) regexp_free(re_dlinc);
237 regexp_free(re_macros);
238 while (--rec >= 0) regexp_free(re[rec]);
239 return result;