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  | }