1 /*
2 * -= Copyright 2005 Tim Baker (treectrl@hotmail.com) =-
3 *
4 * This file is part of depslib.
5 *
6 * License is hereby granted to use this software and distribute it
7 * freely, as long as this copyright notice is retained and modifications
8 * are clearly marked.
9 *
10 * ALL WARRANTIES ARE HEREBY DISCLAIMED.
11 *
12 * Modifications:
13 * - D support (search for "D support")
14 * - Depth level counting (needed for D support)
15 * - Simple optimization by avoiding regexec most of the time
16 * - Special cache keys for source files (needed for D support)
17 */
18 #include "jam.h"
19 #include "alloc.h"
20 #include "hash.h"
21 #include "lists.h"
22 #include "newstr.h"
23 #include "regexp.h"
24 #include "headers.h"
25 #ifdef USE_CACHE
26 #include "cache.h"
27 #endif
28
29 #include "depslib.h" /* for struct depsStats */
30 extern struct depsStats g_stats;
31
32 struct hash *headerhash = 0;
33 static regexp *hdrre = 0;
34 /*D support*/
35 static regexp *dimpre = 0;
36
headers1(const char * file,int depth)37 LIST *headers1(const char *file, int depth)
38 {
39 FILE *f;
40 regexp *re;
41 LIST *result = 0;
42 char buf[1024];
43 int fnlen=strlen(file);
44
45 /*D support */
46 int dMode=0;
47 int dState=0;
48 if(file[fnlen-2] == '.' && file[fnlen-1] == 'd')
49 {
50 dMode=1;
51 if( DEBUG_HEADER )
52 printf("D file detected\n");
53 }
54
55 /* C::B patch: Debug usage of root folder */
56 if( DEBUG_HEADER )
57 printf("header open %s\n", file);
58
59 if (!(f = fopen(file, "r")))
60 return result;
61
62 if( DEBUG_HEADER )
63 printf("header scan %s\n", file);
64
65 if (!hdrre)
66 hdrre = my_regcomp("^[ ]*#[ ]*include[ ]*([<\"])([^\">]*)([\">]).*$");
67 re = hdrre;
68
69 /* D support */
70 if(dMode)
71 {
72 if(!dimpre)
73 dimpre = my_regcomp(
74 "^.*import[ \t]*([[A-Za-z_ \t]+=[ \t]*)?([A-Za-z_\\.]+)(\\:.+)?;.*$");
75 re = dimpre;
76 }
77
78 while (fgets(buf, sizeof(buf), f))
79 {
80 /* D support */
81 if(dMode)
82 {
83 if(dState == 0)
84 {
85 if(strstr(buf, "public"))
86 dState=1;
87 }
88 if(dState >= 1)
89 {
90 if(strchr(buf, '{'))
91 ++dState;
92 if(strchr(buf, '}'))
93 --dState;
94 }
95 }
96
97 /* Simple reduction of regex overhead */
98 if(strstr(buf, dMode ? "import" : "include"))
99 if (my_regexec(re, buf))
100 {
101 char buf2[MAXSYM];
102
103 /* FIXME: don't add duplicate headers*/
104 if(!dMode && re->startp[3])
105 {
106 int l = re->endp[3] - re->startp[1];
107 memcpy(buf2, re->startp[1], l);
108 buf2[l] = '\0';
109 }
110 /* D support */
111 else if(re->startp[2])
112 {
113 if(depth > 0)
114 {
115 /* private import? */
116 if(dState == 0)
117 continue;
118 }
119
120 buf2[0] = '<';
121 const char* p;
122 int j = 0;
123 for(p = re->startp[2];p < re->endp[2];++p)
124 {
125 char c=*p;
126 ++j;
127 if(c == '.')
128 buf2[j] = '/';
129 else buf2[j] = c;
130 }
131 buf2[++j]='.';
132 buf2[++j]='d';
133 buf2[++j]='>';
134 buf2[++j] = '\0';
135 }
136 result = list_new(result, buf2, 0);
137
138 if (DEBUG_HEADER)
139 printf("header found: %s\n", buf2);
140 }
141
142 /* D support */
143 if(dMode)
144 {
145 if(dState == 1)
146 {
147 if(strchr(buf, ';'))
148 dState=0;
149
150 if(strchr(buf, '}'))
151 dState=0;
152 }
153 }
154 }
155
156 fclose(f);
157
158 g_stats.scanned++;
159
160 return result;
161 }
162
163 static ALLOC *hdralloc = 0;
164
headerentry(HEADERS * chain,HEADER * header)165 HEADERS *headerentry(HEADERS *chain, HEADER *header)
166 {
167 HEADERS *c;
168
169 #if 1
170 if (!hdralloc)
171 hdralloc = alloc_init(sizeof(HEADERS), 64);
172 c = (HEADERS *) alloc_enter(hdralloc);
173 #else
174 c = (HEADERS *)malloc(sizeof(HEADERS));
175 #endif
176 c->header = header;
177
178 if (!chain) chain = c;
179 else chain->tail->next = c;
180 chain->tail = c;
181 c->next = 0;
182
183 return chain;
184 }
185
headersDepth(const char * t,time_t time,int depth)186 HEADER *headersDepth(const char *t, time_t time, int depth)
187 {
188 HEADER hdr, *h = &hdr;
189 LIST *l;
190 const char* cachekey=t;
191
192 /* D support (doesn't affect C(++), because a source file is never included) */
193 if(depth == 0)
194 {
195 cachekey=malloc(strlen(t)+sizeof("source:"));
196 strcpy((char*)cachekey,"source:");
197 strcpy((char*)cachekey+7,t);
198 }
199
200 if (!headerhash)
201 headerhash = hashinit(sizeof(HEADER), "headers");
202
203 h->key = cachekey;
204 h->includes = 0;
205 h->time = time;
206 h->headers = 0;
207 h->newest = 0;
208 if (!hashenter(headerhash, (HASHDATA **)&h))
209 return h;
210
211 h->key = newstr(t);
212 #ifdef USE_CACHE
213 if (!cache_check(cachekey, time, &h->includes))
214 {
215 h->includes = headers1(t, depth);
216 cache_enter(cachekey, time, h->includes);
217 }
218 #else
219 h->includes = headers1(t, depth);
220 #endif
221 if(depth == 0)
222 free((char*)cachekey);
223
224 l = h->includes;
225 while (l)
226 {
227 const char *t2 = search(t, l->string, &time);
228 if (time)
229 h->headers = headerentry(h->headers, headersDepth(t2, time, depth+1));
230 l = list_next(l);
231 }
232
233 return h;
234 }
235
headers(const char * t,time_t time)236 HEADER *headers(const char *t, time_t time)
237 {
238 return headersDepth(t, time, 0);
239 }
240
headernewest(HEADER * h)241 void headernewest(HEADER *h)
242 {
243 HEADERS *hs = h->headers;
244
245 if (h->newest)
246 return;
247 h->newest = h;
248 while (hs)
249 {
250 headernewest(hs->header);
251 if (hs->header->newest->time > h->newest->time)
252 h->newest = hs->header->newest;
253 hs = hs->next;
254 }
255 }
256
donehdrs(void)257 void donehdrs(void)
258 {
259 my_redone(hdrre);
260 hdrre = 0;
261 /* D support */
262 my_redone(dimpre);
263 dimpre = 0;
264 hashdone(headerhash);
265 headerhash = 0;
266 alloc_free(hdralloc);
267 hdralloc = 0;
268 }
269