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