1 | /***************************************
2 | $Header: /home/amb/cxref/RCS/preproc.c 1.16 1999/01/24 16:53:49 amb Exp $
3 |
4 | C Cross Referencing & Documentation tool. Version 1.5.
5 |
6 | Collects the pre-processing instruction stuff.
7 | ******************/ /******************
8 | Written by Andrew M. Bishop
9 |
10 | This file Copyright 1995,96,97,99 Andrew M. Bishop
11 | It may be distributed under the GNU Public License, version 2, or
12 | any higher version. See section COPYING of the GNU Public license
13 | for conditions under which this file may be redistributed.
14 | ***************************************/
15 |
16 | /*+ Control the output of debugging information for this file. +*/
17 | #define DEBUG 0
18 |
19 | #include <stdlib.h>
20 | #include <stdio.h>
21 | #include <string.h>
22 | #include <unistd.h>
23 |
24 | #include <sys/stat.h>
25 |
26 | #include "memory.h"
27 | #include "datatype.h"
28 | #include "parse-yy.h"
29 | #include "cxref.h"
30 |
31 | /*+ The file that is currently being processed. +*/
32 | extern File CurFile;
33 |
34 | /*+ The name of the include directories specified on the command line. +*/
35 | extern char **option_incdirs;
36 |
37 | /*+ The number of include directories on the command line. +*/
38 | extern int option_nincdirs;
39 |
40 | /*+ When in a header file, this is set to 1, to allow most of the stuff to be skipped. +*/
41 | int in_header=0;
42 |
43 | /*+ The current #include we are looking at. +*/
44 | static Include cur_inc=NULL;
45 |
46 | /*+ The current #define we are looking at. +*/
47 | static Define cur_def=NULL;
48 |
49 | /*+ The depth of includes. +*/
50 | static int inc_depth=0;
51 |
52 | /*+ The type of include at this depth. +*/
53 | static char *inc_type=NULL;
54 |
55 | /*+ The working directory. +*/
56 | static char *cwd=NULL;
57 |
58 |
59 | static Include NewIncludeType(char *name);
60 | static Define NewDefineType(char *name);
61 |
62 | #ifdef __EMX__
63 | #define lstat stat
64 | #endif
65 |
66 | /*++++++++++++++++++++++++++++++++++++++
67 | Function that is called when an included file is seen in the current file.
68 |
69 | char *name The name of the file from the source code.
70 | ++++++++++++++++++++++++++++++++++++++*/
71 |
72 | void SeenInclude(char *name)
73 | {
74 | #if DEBUG
75 | printf("#Preproc.c# #include %s\n",name);
76 | #endif
77 |
78 | if(!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL)
79 | {
80 | Include inc,*t=&CurFile->includes;
81 | int inc_scope=(*name=='"')?LOCAL:GLOBAL;
82 | int i;
83 |
84 | name++;
85 | name[strlen(name)-1]=0;
86 |
87 | if(inc_scope==LOCAL && option_nincdirs)
88 | for(i=0;i<option_nincdirs;i++)
89 | {
90 | char *newname=CanonicaliseName(ConcatStrings(3,option_incdirs[i],"/",name));
91 | struct stat buf;
92 |
93 | if(!lstat(newname,&buf))
94 | {name=newname;break;}
95 | }
96 |
97 | for(i=0;i<inc_depth;i++)
98 | {
99 | while(*t && (*t)->next)
100 | t=&(*t)->next;
101 | t=&(*t)->includes;
102 | }
103 |
104 | inc=NewIncludeType(name);
105 |
106 | inc->comment=MallocString(GetCurrentComment());
107 | inc->scope=inc_scope;
108 |
109 | AddToLinkedList(*t,Include,inc);
110 |
111 | cur_inc=inc;
112 | }
113 | else
114 | cur_inc=NULL;
115 | }
116 |
117 |
118 | /*++++++++++++++++++++++++++++++++++++++
119 | Function that is called when a comment is seen following a #include.
120 | ++++++++++++++++++++++++++++++++++++++*/
121 |
122 | void SeenIncludeComment(void)
123 | {
124 | char* comment=GetCurrentComment();
125 |
126 | #if DEBUG
127 | printf("#Preproc.c# #include trailing comment '%s' for %s\n",comment,cur_inc->name);
128 | #endif
129 |
130 | if(!cur_inc->comment)
131 | cur_inc->comment=MallocString(comment);
132 | }
133 |
134 |
135 | /*++++++++++++++++++++++++++++++++++++++
136 | Function that is called when a change in current file is seen.
137 |
138 | char *name The pathname of the included file as determined by gcc.
139 |
140 | int flag The flags that GCC leaves in the file
141 | ++++++++++++++++++++++++++++++++++++++*/
142 |
143 | void SeenFileChange(char *name,int flag)
144 | {
145 | if(!cwd)
146 | {
147 | cwd=(char*)Malloc(256);
148 | if(!getcwd(cwd,255))
149 | cwd[0]=0;
150 | }
151 |
152 | #if DEBUG
153 | printf("#Preproc.c# FileChange - %s %s (flag=%d)\n",flag&2?"Included ":"Return to",name,flag);
154 | #endif
155 |
156 | name=CanonicaliseName(name);
157 |
158 | if(!strncmp(name,cwd,strlen(cwd)))
159 | name=name+strlen(cwd);
160 |
161 | /* Store the information. */
162 |
163 | if(flag&2 && (!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL))
164 | {
165 | if(!cur_inc)
166 | {
167 | if(flag&8)
168 | SeenInclude(ConcatStrings(3,"<",name,">"));
169 | else
170 | SeenInclude(ConcatStrings(3,"\"",name,"\""));
171 | }
172 | else if(!(flag&8))
173 | {
174 | Free(cur_inc->name);
175 | cur_inc->name=MallocString(name);
176 | }
177 | }
178 |
179 | cur_inc=NULL;
180 |
181 | if(flag&2)
182 | {
183 | inc_depth++;
184 |
185 | if(!inc_type)
186 | inc_type=(char*)Malloc(16);
187 | else
188 | if(!(inc_depth%16))
189 | inc_type=(char*)Realloc(inc_type,(unsigned)(inc_depth+16));
190 |
191 | if(inc_depth>1 && inc_type[inc_depth-2]==GLOBAL)
192 | inc_type[inc_depth-1]=GLOBAL;
193 | else
194 | inc_type[inc_depth-1]=(flag&8)?GLOBAL:LOCAL;
195 | }
196 | else
197 | inc_depth--;
198 |
199 | if(inc_type && inc_depth>0)
200 | in_header=inc_type[inc_depth-1];
201 | else
202 | in_header=0;
203 |
204 | SetCurrentComment(NULL);
205 | }
206 |
207 |
208 | /*++++++++++++++++++++++++++++++++++++++
209 | Function that is called when a #define is seen in the current file.
210 |
211 | char* name The name of the #defined symbol.
212 | ++++++++++++++++++++++++++++++++++++++*/
213 |
214 | void SeenDefine(char* name)
215 | {
216 | Define def;
217 |
218 | #if DEBUG
219 | printf("#Preproc.c# Defined name '%s'\n",name);
220 | #endif
221 |
222 | def=NewDefineType(name);
223 |
224 | def->comment=MallocString(GetCurrentComment());
225 |
226 | def->lineno=parse_line;
227 |
228 | AddToLinkedList(CurFile->defines,Define,def);
229 |
230 | cur_def=def;
231 | }
232 |
233 |
234 | /*++++++++++++++++++++++++++++++++++++++
235 | Function that is called when a comment is seen in a #define definition.
236 | ++++++++++++++++++++++++++++++++++++++*/
237 |
238 | void SeenDefineComment(void)
239 | {
240 | char* comment=GetCurrentComment();
241 |
242 | #if DEBUG
243 | printf("#Preproc.c# #define inline comment '%s' in %s\n",comment,cur_def->name);
244 | #endif
245 |
246 | if(!cur_def->comment)
247 | cur_def->comment=MallocString(comment);
248 | }
249 |
250 |
251 | /*++++++++++++++++++++++++++++++++++++++
252 | Function that is called when a #define value is seen in the current file.
253 |
254 | char* value The value of the #defined symbol.
255 | ++++++++++++++++++++++++++++++++++++++*/
256 |
257 | void SeenDefineValue(char* value)
258 | {
259 | #if DEBUG
260 | printf("#Preproc.c# #define value '%s' for %s\n",value,cur_def->name);
261 | #endif
262 |
263 | cur_def->value=MallocString(value);
264 | }
265 |
266 |
267 | /*++++++++++++++++++++++++++++++++++++++
268 | Function that is called when a #define function argument is seen in the current definition.
269 |
270 | char* name The argument.
271 | ++++++++++++++++++++++++++++++++++++++*/
272 |
273 | void SeenDefineFunctionArg(char* name)
274 | {
275 | #if DEBUG
276 | printf("#Preproc.c# #define Function arg '%s' in %s()\n",name,cur_def->name);
277 | #endif
278 |
279 | AddToStringList2(cur_def->args,name,SplitComment(&cur_def->comment,name),0,0);
280 | }
281 |
282 |
283 | /*++++++++++++++++++++++++++++++++++++++
284 | Function that is called when a comment is seen in a #define function definition.
285 | ++++++++++++++++++++++++++++++++++++++*/
286 |
287 | void SeenDefineFuncArgComment(void)
288 | {
289 | char* comment=GetCurrentComment();
290 |
291 | #if DEBUG
292 | printf("#Preproc.c# #define Function arg comment '%s' in %s()\n",comment,cur_def->name);
293 | #endif
294 |
295 | if(!cur_def->args->s2[cur_def->args->n-1])
296 | cur_def->args->s2[cur_def->args->n-1]=MallocString(comment);
297 | }
298 |
299 |
300 | /*++++++++++++++++++++++++++++++++++++++
301 | Tidy up all of the local variables in case of a problem and abnormal parser termination.
302 | ++++++++++++++++++++++++++++++++++++++*/
303 |
304 | void ResetPreProcAnalyser(void)
305 | {
306 | in_header=0;
307 |
308 | cur_inc=NULL;
309 | cur_def=NULL;
310 |
311 | inc_depth=0;
312 |
313 | if(inc_type) Free(inc_type);
314 | inc_type=NULL;
315 |
316 | if(cwd) Free(cwd);
317 | cwd=NULL;
318 | }
319 |
320 |
321 | /*++++++++++++++++++++++++++++++++++++++
322 | Create a new Include datatype.
323 |
324 | Include NewIncludeType Return the new Include type.
325 |
326 | char *name The name of the new include.
327 | ++++++++++++++++++++++++++++++++++++++*/
328 |
329 | static Include NewIncludeType(char *name)
330 | {
331 | Include inc=(Include)Calloc(1,sizeof(struct _Include));
332 |
333 | inc->name=MallocString(name);
334 |
335 | return(inc);
336 | }
337 |
338 |
339 | /*++++++++++++++++++++++++++++++++++++++
340 | Delete the specified Include type.
341 |
342 | Include inc The Include type to be deleted.
343 | ++++++++++++++++++++++++++++++++++++++*/
344 |
345 | void DeleteIncludeType(Include inc)
346 | {
347 | if(inc->comment) Free(inc->comment);
348 | if(inc->name) Free(inc->name);
349 | if(inc->includes)
350 | {
351 | Include p=inc->includes;
352 | do{
353 | Include n=p->next;
354 | DeleteIncludeType(p);
355 | p=n;
356 | }
357 | while(p);
358 | }
359 | Free(inc);
360 | }
361 |
362 |
363 | /*++++++++++++++++++++++++++++++++++++++
364 | Create a new Define datatype.
365 |
366 | Define NewDefineType Return the new Define type.
367 |
368 | char *name The name of the new define.
369 | ++++++++++++++++++++++++++++++++++++++*/
370 |
371 | static Define NewDefineType(char *name)
372 | {
373 | Define def=(Define)Calloc(1,sizeof(struct _Define)); /* clear unused pointers */
374 |
375 | def->name=MallocString(name);
376 | def->args=NewStringList2();
377 |
378 | return(def);
379 | }
380 |
381 |
382 | /*++++++++++++++++++++++++++++++++++++++
383 | Delete the specified Define type.
384 |
385 | Define def The Define type to be deleted.
386 | ++++++++++++++++++++++++++++++++++++++*/
387 |
388 | void DeleteDefineType(Define def)
389 | {
390 | if(def->comment) Free(def->comment);
391 | if(def->name) Free(def->name);
392 | if(def->value) Free(def->value);
393 | if(def->args) DeleteStringList2(def->args);
394 | Free(def);
395 | }