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