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 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);
111 re
[rec
] = regexp_compile("\\bimport\\s+(.+?)\\s*;", 0);
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);
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(); }
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
);
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
;
150 while (t
>= p
&& isspace(*t
)) --t
;
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);
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);
179 if (DEBUG_HEADER
) printf(" ignored !!\n");
187 if (re_dlinc
!= NULL
) regexp_free(re_dlinc
);
188 regexp_free(re_macros
);
189 while (--rec
>= 0) regexp_free(re
[rec
]);