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