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