1    | /***************************************
2    |   $Header: /home/amb/cxref/RCS/preproc.c 1.21 2003/06/22 13:49:58 amb Exp $
3    | 
4    |   C Cross Referencing & Documentation tool. Version 1.5e.
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 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  | 
163  |  name=CanonicaliseName(name);
164  | 
165  |  if(!strncmp(name,cwd,strlen(cwd)))
166  |     name=name+strlen(cwd);
167  | 
168  |  if(flag&4)
169  |    {
170  |     if(inc_depth>=2)
171  |        name=inc_name[inc_depth-2];
172  |     else
173  |        name=CurFile->name;
174  |    }
175  | 
176  | #if DEBUG
177  |  printf("#Preproc.c# FileChange - %s %s (flag=%d)\n",flag&2?"Included ":"Return to",name,flag);
178  | #endif
179  | 
180  |  /* Store the information. */
181  | 
182  |  if(flag&2 && (!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL))
183  |    {
184  |     if(!cur_inc)
185  |       {
186  |        if(flag&8)
187  |           SeenInclude(ConcatStrings(3,"<",name,">"));
188  |        else
189  |           SeenInclude(ConcatStrings(3,"\"",name,"\""));
190  |       }
191  |     else if(!(flag&8))
192  |       {
193  |        Free(cur_inc->name);
194  |        cur_inc->name=MallocString(name);
195  |       }
196  |    }
197  | 
198  |  if(flag&2)
199  |    {
200  |     inc_depth++;
201  | 
202  |     if(!inc_type)
203  |       {
204  |        inc_type=(char*)Malloc(16);
205  |        inc_name=(char**)Malloc(16*sizeof(char*));
206  |       }
207  |     else
208  |        if(!(inc_depth%16))
209  |          {
210  |           inc_type=(char*)Realloc(inc_type,(unsigned)(inc_depth+16));
211  |           inc_name=(char**)Realloc(inc_name,(unsigned)(sizeof(char*)*(inc_depth+16)));
212  |          }
213  | 
214  |     if(inc_depth>1 && inc_type[inc_depth-2]==GLOBAL)
215  |        inc_type[inc_depth-1]=GLOBAL;
216  |     else
217  |        inc_type[inc_depth-1]=cur_inc?cur_inc->scope:(flag&8)?GLOBAL:LOCAL;
218  | 
219  |     inc_name[inc_depth-1]=CopyString(name);
220  |    }
221  |  else
222  |     inc_depth--;
223  | 
224  |  if(inc_type && inc_depth>0)
225  |     in_header=inc_type[inc_depth-1];
226  |  else
227  |     in_header=0;
228  | 
229  |  SetCurrentComment(NULL);
230  | 
231  |  cur_inc=NULL;
232  | 
233  |  return(name);
234  | }
235  | 
236  | 
237  | /*++++++++++++++++++++++++++++++++++++++
238  |   Function that is called when a #define is seen in the current file.
239  | 
240  |   char* name The name of the #defined symbol.
241  |   ++++++++++++++++++++++++++++++++++++++*/
242  | 
243  | void SeenDefine(char* name)
244  | {
245  |  Define def;
246  | 
247  | #if DEBUG
248  |  printf("#Preproc.c# Defined name '%s'\n",name);
249  | #endif
250  | 
251  |  def=NewDefineType(name);
252  | 
253  |  def->comment=MallocString(GetCurrentComment());
254  | 
255  |  def->lineno=parse_line;
256  | 
257  |  AddToLinkedList(CurFile->defines,Define,def);
258  | 
259  |  cur_def=def;
260  | }
261  | 
262  | 
263  | /*++++++++++++++++++++++++++++++++++++++
264  |   Function that is called when a comment is seen in a #define definition.
265  |   ++++++++++++++++++++++++++++++++++++++*/
266  | 
267  | void SeenDefineComment(void)
268  | {
269  |  char* comment=GetCurrentComment();
270  | 
271  | #if DEBUG
272  |  printf("#Preproc.c# #define inline comment '%s' in %s\n",comment,cur_def->name);
273  | #endif
274  | 
275  |  if(!cur_def->comment)
276  |     cur_def->comment=MallocString(comment);
277  | }
278  | 
279  | 
280  | /*++++++++++++++++++++++++++++++++++++++
281  |   Function that is called when a #define value is seen in the current file.
282  | 
283  |   char* value The value of the #defined symbol.
284  |   ++++++++++++++++++++++++++++++++++++++*/
285  | 
286  | void SeenDefineValue(char* value)
287  | {
288  | #if DEBUG
289  |  printf("#Preproc.c# #define value '%s' for %s\n",value,cur_def->name);
290  | #endif
291  | 
292  |  cur_def->value=MallocString(value);
293  | }
294  | 
295  | 
296  | /*++++++++++++++++++++++++++++++++++++++
297  |   Function that is called when a #define function argument is seen in the current definition.
298  | 
299  |   char* name The argument.
300  |   ++++++++++++++++++++++++++++++++++++++*/
301  | 
302  | void SeenDefineFunctionArg(char* name)
303  | {
304  | #if DEBUG
305  |  printf("#Preproc.c# #define Function arg '%s' in %s()\n",name,cur_def->name);
306  | #endif
307  | 
308  |  AddToStringList2(cur_def->args,name,SplitComment(&cur_def->comment,name),0,0);
309  | }
310  | 
311  | 
312  | /*++++++++++++++++++++++++++++++++++++++
313  |   Function that is called when a comment is seen in a #define function definition.
314  |   ++++++++++++++++++++++++++++++++++++++*/
315  | 
316  | void SeenDefineFuncArgComment(void)
317  | {
318  |  char* comment=GetCurrentComment();
319  | 
320  | #if DEBUG
321  |  printf("#Preproc.c# #define Function arg comment '%s' in %s()\n",comment,cur_def->name);
322  | #endif
323  | 
324  |  if(!cur_def->args->s2[cur_def->args->n-1])
325  |     cur_def->args->s2[cur_def->args->n-1]=MallocString(comment);
326  | }
327  | 
328  | 
329  | /*++++++++++++++++++++++++++++++++++++++
330  |   Tidy up all of the local variables in case of a problem and abnormal parser termination.
331  |   ++++++++++++++++++++++++++++++++++++++*/
332  | 
333  | void ResetPreProcAnalyser(void)
334  | {
335  |  in_header=0;
336  | 
337  |  cur_inc=NULL;
338  |  cur_def=NULL;
339  | 
340  |  inc_depth=0;
341  | 
342  |  if(inc_type) Free(inc_type);
343  |  inc_type=NULL;
344  |  if(inc_name) Free(inc_name);
345  |  inc_name=NULL;
346  | 
347  |  if(cwd) Free(cwd);
348  |  cwd=NULL;
349  | }
350  | 
351  | 
352  | /*++++++++++++++++++++++++++++++++++++++
353  |   Create a new Include datatype.
354  | 
355  |   Include NewIncludeType Return the new Include type.
356  | 
357  |   char *name The name of the new include.
358  |   ++++++++++++++++++++++++++++++++++++++*/
359  | 
360  | static Include NewIncludeType(char *name)
361  | {
362  |  Include inc=(Include)Calloc(1,sizeof(struct _Include));
363  | 
364  |  inc->name=MallocString(name);
365  | 
366  |  return(inc);
367  | }
368  | 
369  | 
370  | /*++++++++++++++++++++++++++++++++++++++
371  |   Delete the specified Include type.
372  | 
373  |   Include inc The Include type to be deleted.
374  |   ++++++++++++++++++++++++++++++++++++++*/
375  | 
376  | void DeleteIncludeType(Include inc)
377  | {
378  |  if(inc->comment) Free(inc->comment);
379  |  if(inc->name)    Free(inc->name);
380  |  if(inc->includes)
381  |    {
382  |     Include p=inc->includes;
383  |     do{
384  |        Include n=p->next;
385  |        DeleteIncludeType(p);
386  |        p=n;
387  |       }
388  |     while(p);
389  |    }
390  |  Free(inc);
391  | }
392  | 
393  | 
394  | /*++++++++++++++++++++++++++++++++++++++
395  |   Create a new Define datatype.
396  | 
397  |   Define NewDefineType Return the new Define type.
398  | 
399  |   char *name The name of the new define.
400  |   ++++++++++++++++++++++++++++++++++++++*/
401  | 
402  | static Define NewDefineType(char *name)
403  | {
404  |  Define def=(Define)Calloc(1,sizeof(struct _Define)); /* clear unused pointers */
405  | 
406  |  def->name=MallocString(name);
407  |  def->args=NewStringList2();
408  | 
409  |  return(def);
410  | }
411  | 
412  | 
413  | /*++++++++++++++++++++++++++++++++++++++
414  |   Delete the specified Define type.
415  | 
416  |   Define def The Define type to be deleted.
417  |   ++++++++++++++++++++++++++++++++++++++*/
418  | 
419  | void DeleteDefineType(Define def)
420  | {
421  |  if(def->comment) Free(def->comment);
422  |  if(def->name)    Free(def->name);
423  |  if(def->value)   Free(def->value);
424  |  if(def->args)    DeleteStringList2(def->args);
425  |  Free(def);
426  | }