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
SeenInclude(char * name)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
SeenIncludeComment(void)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
SeenFileChange(char * name,int flag)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
SeenDefine(char * name)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
SeenDefineComment(void)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
SeenDefineValue(char * value)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
SeenDefineFunctionArg(char * name)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
SeenDefineFuncArgComment(void)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
ResetPreProcAnalyser(void)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
NewIncludeType(char * name)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
DeleteIncludeType(Include inc)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
NewDefineType(char * name)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
DeleteDefineType(Define def)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 }
453