1    | /***************************************
2    |   $Header: /home/amb/cxref/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  | }