added '-configure-pkg-config-var-' rule
[k8jam.git] / src / headers.c
blob1f422ddad5ccfac90a1bee2960c8f575edcdf5cf
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 if (DEBUG_HEADER) printf("DBG: trying header [%s]\n", file);
104 if (!(f = fopen(file, "r"))) return result;
106 LIST *t = var_get("DLANG");
107 dlang = (t != NULL && t->string[0]);
108 //fprintf(stderr, "DLANG: %d\n", dlang);
110 if (dlang) {
111 re[rec] = regexp_compile("\\bimport\\s+(.+?)\\s*;", 0);
112 ++rec;
113 re_dlinc = regexp_compile("\\s*([^,;]+?)\\s*", 0);
115 while (rec < MAXINC && hdrscan) {
116 //printf("header re %d: [%s]\n", rec, hdrscan->string);
117 re[rec] = regexp_compile(hdrscan->string, 0);
118 ++rec;
119 hdrscan = list_next(hdrscan);
121 /* the following regexp is used to detect cases where a */
122 /* file is included through a line line "#include MACRO" */
123 re_macros = regexp_compile("^\\s*#\\s*include\\s+([A-Za-z_][A-Za-z0-9_]*).*$", 0);
124 if (DEBUG_HEADER) printf("header processing: [%s] (%d)\n", file, rec);
125 if ((buf = malloc(line_size)) == NULL) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
126 dstr_init(&buf2);
127 dstr_init(&buf3);
128 while (fgets(buf, line_size, f)) {
129 for (i = 0; i < rec; ++i) {
130 mt[0].sp = mt[0].ep = NULL;
131 if (regexp_execute(re[i], buf, mt, 2) > 0 && mt[1].sp != NULL) {
132 /* copy and terminate extracted string */
133 int l = mt[1].ep-mt[1].sp;
134 dstr_set_buf(&buf2, mt[1].sp, l);
135 if (dlang && i == 0) {
136 /* this is DLang 'import' directive */
137 //fprintf(stderr, "dlang: [%s]\n", dstr_cstr(&buf2));
138 const char *s = dstr_cstr(&buf2);
139 while (*s) {
140 char *p, *t;
141 if (!regexp_execute(re_dlinc, s, mt, 2) || mt[1].sp == NULL) break;
142 dstr_set_buf(&buf3, mt[1].sp, mt[1].ep-mt[1].sp);
143 dstr_push_cstr(&buf3, ".d");
144 p = dstr_cstr(&buf3);
145 if ((t = strchr(p, ':')) != NULL) *t = 0;
146 if ((t = strchr(p, '=')) != NULL) p = t+1;
147 while (*p && isspace(*p)) ++p;
148 if (*p) {
149 t = p+strlen(p)-1;
150 while (t >= p && isspace(*t)) --t;
151 t[1] = 0;
153 if (*p) {
154 for (t = p; *t; ++t) if (*t == '.') *t = '/';
155 *(strrchr(p, '/')) = '.'; // restore '.d'
156 //fprintf(stderr, "dlang include: [%s]\n", p);
157 result = list_new(result, p, 0);
159 s = mt[1].ep;
161 } else {
162 result = list_new(result, dstr_cstr(&buf2), 0);
164 if (DEBUG_HEADER) printf("header found: %s\n", dstr_cstr(&buf2));
167 /* special treatment for #include MACRO */
168 mt[0].sp = mt[0].ep = NULL;
169 if (regexp_execute(re_macros, buf, mt, 2) > 0 && mt[1].sp != NULL) {
170 const char *header_filename;
171 int l = mt[1].ep-mt[1].sp;
172 dstr_set_buf(&buf2, mt[1].sp, l);
173 if (DEBUG_HEADER) printf("macro header found: %s", dstr_cstr(&buf2));
174 header_filename = macro_header_get(dstr_cstr(&buf2));
175 if (header_filename) {
176 if (DEBUG_HEADER) printf(" resolved to '%s'\n", header_filename);
177 result = list_new(result, header_filename, 0);
178 } else {
179 if (DEBUG_HEADER) printf(" ignored !!\n");
183 dstr_done(&buf3);
184 dstr_done(&buf2);
185 free(buf);
186 fclose(f);
187 if (re_dlinc != NULL) regexp_free(re_dlinc);
188 regexp_free(re_macros);
189 while (--rec >= 0) regexp_free(re[rec]);
190 return result;