1 | /***************************************
2 | $Header: /home/amb/cxref/src/RCS/preproc.c 1.22 2004/01/18 11:38:35 amb Exp $
3 |
4 | C Cross Referencing & Documentation tool. Version 1.5f.
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,04 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 | else if(flag==-1)
163 | {
164 | in_header=0;
165 | return(CurFile->name);
166 | }
167 |
168 | name=CanonicaliseName(name);
169 |
170 | if(!strncmp(name,cwd,strlen(cwd)))
171 | name=name+strlen(cwd);
172 |
173 | if(flag&4)
174 | {
175 | if(inc_depth>=2)
176 | name=inc_name[inc_depth-2];
177 | else
178 | name=CurFile->name;
179 | }
180 |
181 | #if DEBUG
182 | printf("#Preproc.c# FileChange - %s %s (flag=%d)\n",flag&2?"Included ":"Return to",name,flag);
183 | #endif
184 |
185 | /* Store the information. */
186 |
187 | if(flag&2 && (!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL))
188 | {
189 | if(!cur_inc)
190 | {
191 | if(flag&8)
192 | SeenInclude(ConcatStrings(3,"<",name,">"));
193 | else
194 | SeenInclude(ConcatStrings(3,"\"",name,"\""));
195 | }
196 | else if(!(flag&8))
197 | {
198 | Free(cur_inc->name);
199 | cur_inc->name=MallocString(name);
200 | }
201 | }
202 |
203 | if(flag&2)
204 | {
205 | inc_depth++;
206 |
207 | if(!inc_type)
208 | {
209 | inc_type=(char*)Malloc(16);
210 | inc_name=(char**)Malloc(16*sizeof(char*));
211 | }
212 | else
213 | if(!(inc_depth%16))
214 | {
215 | inc_type=(char*)Realloc(inc_type,(unsigned)(inc_depth+16));
216 | inc_name=(char**)Realloc(inc_name,(unsigned)(sizeof(char*)*(inc_depth+16)));
217 | }
218 |
219 | if(inc_depth>1 && inc_type[inc_depth-2]==GLOBAL)
220 | inc_type[inc_depth-1]=GLOBAL;
221 | else
222 | inc_type[inc_depth-1]=cur_inc?cur_inc->scope:(flag&8)?GLOBAL:LOCAL;
223 |
224 | inc_name[inc_depth-1]=CopyString(name);
225 | }
226 | else
227 | inc_depth--;
228 |
229 | if(inc_type && inc_depth>0)
230 | in_header=inc_type[inc_depth-1];
231 | else
232 | in_header=0;
233 |
234 | SetCurrentComment(NULL);
235 |
236 | cur_inc=NULL;
237 |
238 | return(name);
239 | }
240 |
241 |
242 | /*++++++++++++++++++++++++++++++++++++++
243 | Function that is called when a #define is seen in the current file.
244 |
245 | char* name The name of the #defined symbol.
246 | ++++++++++++++++++++++++++++++++++++++*/
247 |
248 | void SeenDefine(char* name)
249 | {
250 | Define def;
251 |
252 | #if DEBUG
253 | printf("#Preproc.c# Defined name '%s'\n",name);
254 | #endif
255 |
256 | def=NewDefineType(name);
257 |
258 | def->comment=MallocString(GetCurrentComment());
259 |
260 | def->lineno=parse_line;
261 |
262 | AddToLinkedList(CurFile->defines,Define,def);
263 |
264 | cur_def=def;
265 | }
266 |
267 |
268 | /*++++++++++++++++++++++++++++++++++++++
269 | Function that is called when a comment is seen in a #define definition.
270 | ++++++++++++++++++++++++++++++++++++++*/
271 |
272 | void SeenDefineComment(void)
273 | {
274 | char* comment=GetCurrentComment();
275 |
276 | #if DEBUG
277 | printf("#Preproc.c# #define inline comment '%s' in %s\n",comment,cur_def->name);
278 | #endif
279 |
280 | if(!cur_def->comment)
281 | cur_def->comment=MallocString(comment);
282 | }
283 |
284 |
285 | /*++++++++++++++++++++++++++++++++++++++
286 | Function that is called when a #define value is seen in the current file.
287 |
288 | char* value The value of the #defined symbol.
289 | ++++++++++++++++++++++++++++++++++++++*/
290 |
291 | void SeenDefineValue(char* value)
292 | {
293 | #if DEBUG
294 | printf("#Preproc.c# #define value '%s' for %s\n",value,cur_def->name);
295 | #endif
296 |
297 | cur_def->value=MallocString(value);
298 | }
299 |
300 |
301 | /*++++++++++++++++++++++++++++++++++++++
302 | Function that is called when a #define function argument is seen in the current definition.
303 |
304 | char* name The argument.
305 | ++++++++++++++++++++++++++++++++++++++*/
306 |
307 | void SeenDefineFunctionArg(char* name)
308 | {
309 | #if DEBUG
310 | printf("#Preproc.c# #define Function arg '%s' in %s()\n",name,cur_def->name);
311 | #endif
312 |
313 | AddToStringList2(cur_def->args,name,SplitComment(&cur_def->comment,name),0,0);
314 | }
315 |
316 |
317 | /*++++++++++++++++++++++++++++++++++++++
318 | Function that is called when a comment is seen in a #define function definition.
319 | ++++++++++++++++++++++++++++++++++++++*/
320 |
321 | void SeenDefineFuncArgComment(void)
322 | {
323 | char* comment=GetCurrentComment();
324 |
325 | #if DEBUG
326 | printf("#Preproc.c# #define Function arg comment '%s' in %s()\n",comment,cur_def->name);
327 | #endif
328 |
329 | if(!cur_def->args->s2[cur_def->args->n-1])
330 | cur_def->args->s2[cur_def->args->n-1]=MallocString(comment);
331 | }
332 |
333 |
334 | /*++++++++++++++++++++++++++++++++++++++
335 | Tidy up all of the local variables in case of a problem and abnormal parser termination.
336 | ++++++++++++++++++++++++++++++++++++++*/
337 |
338 | void ResetPreProcAnalyser(void)
339 | {
340 | in_header=0;
341 |
342 | cur_inc=NULL;
343 | cur_def=NULL;
344 |
345 | inc_depth=0;
346 |
347 | if(inc_type) Free(inc_type);
348 | inc_type=NULL;
349 | if(inc_name) Free(inc_name);
350 | inc_name=NULL;
351 |
352 | if(cwd) Free(cwd);
353 | cwd=NULL;
354 | }
355 |
356 |
357 | /*++++++++++++++++++++++++++++++++++++++
358 | Create a new Include datatype.
359 |
360 | Include NewIncludeType Return the new Include type.
361 |
362 | char *name The name of the new include.
363 | ++++++++++++++++++++++++++++++++++++++*/
364 |
365 | static Include NewIncludeType(char *name)
366 | {
367 | Include inc=(Include)Calloc(1,sizeof(struct _Include));
368 |
369 | inc->name=MallocString(name);
370 |
371 | return(inc);
372 | }
373 |
374 |
375 | /*++++++++++++++++++++++++++++++++++++++
376 | Delete the specified Include type.
377 |
378 | Include inc The Include type to be deleted.
379 | ++++++++++++++++++++++++++++++++++++++*/
380 |
381 | void DeleteIncludeType(Include inc)
382 | {
383 | if(inc->comment) Free(inc->comment);
384 | if(inc->name) Free(inc->name);
385 | if(inc->includes)
386 | {
387 | Include p=inc->includes;
388 | do{
389 | Include n=p->next;
390 | DeleteIncludeType(p);
391 | p=n;
392 | }
393 | while(p);
394 | }
395 | Free(inc);
396 | }
397 |
398 |
399 | /*++++++++++++++++++++++++++++++++++++++
400 | Create a new Define datatype.
401 |
402 | Define NewDefineType Return the new Define type.
403 |
404 | char *name The name of the new define.
405 | ++++++++++++++++++++++++++++++++++++++*/
406 |
407 | static Define NewDefineType(char *name)
408 | {
409 | Define def=(Define)Calloc(1,sizeof(struct _Define)); /* clear unused pointers */
410 |
411 | def->name=MallocString(name);
412 | def->args=NewStringList2();
413 |
414 | return(def);
415 | }
416 |
417 |
418 | /*++++++++++++++++++++++++++++++++++++++
419 | Delete the specified Define type.
420 |
421 | Define def The Define type to be deleted.
422 | ++++++++++++++++++++++++++++++++++++++*/
423 |
424 | void DeleteDefineType(Define def)
425 | {
426 | if(def->comment) Free(def->comment);
427 | if(def->name) Free(def->name);
428 | if(def->value) Free(def->value);
429 | if(def->args) DeleteStringList2(def->args);
430 | Free(def);
431 | }