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