1    | /***************************************
2    |   $Header: /home/amb/cxref/src/RCS/preproc.c 1.23 2006/03/11 14:39:24 amb Exp $
3    | 
4    |   C Cross Referencing & Documentation tool. Version 1.6b.
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   | #ifndef PATH_MAX
33   | #define PATH_MAX 4096           /*+ The maximum pathname length. +*/
34   | #endif
35   | 
36   | 
37   | /*+ The file that is currently being processed. +*/
38   | extern File CurFile;
39   | 
40   | /*+ The name of the include directories specified on the command line. +*/
41   | extern char **option_incdirs;
42   | 
43   | /*+ The number of include directories on the command line. +*/
44   | extern int option_nincdirs;
45   | 
46   | /*+ When in a header file, this is set to 1, to allow most of the stuff to be skipped. +*/
47   | int in_header=0;
48   | 
49   | /*+ The current #include we are looking at. +*/
50   | static Include cur_inc=NULL;
51   | 
52   | /*+ The current #define we are looking at. +*/
53   | static Define cur_def=NULL;
54   | 
55   | /*+ The depth of includes. +*/
56   | static int inc_depth=0;
57   | 
58   | /*+ The type of include at this depth. +*/
59   | static char *inc_type=NULL;
60   | 
61   | /*+ The name of the include file at this depth. +*/
62   | static char **inc_name=NULL;
63   | 
64   | /*+ The working directory. +*/
65   | static char *cwd=NULL;
66   | 
67   | 
68   | static Include NewIncludeType(char *name);
69   | static Define NewDefineType(char *name);
70   | 
71   | 
72   | /*++++++++++++++++++++++++++++++++++++++
73   |   Function that is called when an included file is seen in the current file.
74   | 
75   |   char *name The name of the file from the source code.
76   |   ++++++++++++++++++++++++++++++++++++++*/
77   | 
78   | void SeenInclude(char *name)
79   | {
80   | #if DEBUG
81   |  printf("#Preproc.c# #include %s\n",name);
82   | #endif
83   | 
84   |  if(!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL)
85   |    {
86   |     Include inc,*t=&CurFile->includes;
87   |     int inc_scope=(*name=='"')?LOCAL:GLOBAL;
88   |     int i;
89   | 
90   |     name++;
91   |     name[strlen(name)-1]=0;
92   | 
93   |     if(inc_scope==LOCAL && option_nincdirs)
94   |        for(i=0;i<option_nincdirs;i++)
95   |          {
96   |           char *newname=CanonicaliseName(ConcatStrings(3,option_incdirs[i],"/",name));
97   |           struct stat buf;
98   | 
99   |           if(!lstat(newname,&buf))
100  |             {name=newname;break;}
101  |          }
102  | 
103  |     for(i=0;i<inc_depth;i++)
104  |       {
105  |        while(*t && (*t)->next)
106  |           t=&(*t)->next;
107  |        t=&(*t)->includes;
108  |       }
109  | 
110  |     inc=NewIncludeType(name);
111  | 
112  |     inc->comment=MallocString(GetCurrentComment());
113  |     inc->scope=inc_scope;
114  | 
115  |     AddToLinkedList(*t,Include,inc);
116  | 
117  |     cur_inc=inc;
118  |    }
119  |  else
120  |     cur_inc=NULL;
121  | }
122  | 
123  | 
124  | /*++++++++++++++++++++++++++++++++++++++
125  |   Function that is called when a comment is seen following a #include.
126  |   ++++++++++++++++++++++++++++++++++++++*/
127  | 
128  | void SeenIncludeComment(void)
129  | {
130  |  char* comment=GetCurrentComment();
131  | 
132  | #if DEBUG
133  |  printf("#Preproc.c# #include trailing comment '%s' for %s\n",comment,cur_inc->name);
134  | #endif
135  | 
136  |  if(!cur_inc->comment)
137  |     cur_inc->comment=MallocString(comment);
138  | }
139  | 
140  | 
141  | /*++++++++++++++++++++++++++++++++++++++
142  |   Function that is called when a change in current file is seen.
143  | 
144  |   char *SeenFileChange Returns the filename that we are now in.
145  | 
146  |   char *name The pathname of the included file as determined by gcc.
147  | 
148  |   int flag The flags that GCC leaves in the file
149  |   ++++++++++++++++++++++++++++++++++++++*/
150  | 
151  | char *SeenFileChange(char *name,int flag)
152  | {
153  |  if(!cwd)
154  |    {
155  |     cwd=(char*)Malloc(PATH_MAX+1);
156  |     if(!getcwd(cwd,PATH_MAX))
157  |        cwd[0]=0;
158  |    }
159  | 
160  |  /* Special gcc-3.x fake names for built-in #defines. */
161  | 
162  |  if(!strcmp(name,"<built-in>") || !strcmp(name,"<command line>"))
163  |    {
164  |     in_header=1;
165  |     return(NULL);
166  |    }
167  |  else if(flag==-1)
168  |    {
169  |     in_header=0;
170  |     return(CurFile->name);
171  |    }
172  | 
173  |  name=CanonicaliseName(name);
174  | 
175  |  if(!strncmp(name,cwd,strlen(cwd)))
176  |     name=name+strlen(cwd);
177  | 
178  |  if(flag&4)
179  |    {
180  |     if(inc_depth>=2)
181  |        name=inc_name[inc_depth-2];
182  |     else
183  |        name=CurFile->name;
184  |    }
185  | 
186  | #if DEBUG
187  |  printf("#Preproc.c# FileChange - %s %s (flag=%d)\n",flag&2?"Included ":"Return to",name,flag);
188  | #endif
189  | 
190  |  /* Store the information. */
191  | 
192  |  if(flag&2 && (!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL))
193  |    {
194  |     if(!cur_inc)
195  |       {
196  |        if(flag&8)
197  |           SeenInclude(ConcatStrings(3,"<",name,">"));
198  |        else
199  |           SeenInclude(ConcatStrings(3,"\"",name,"\""));
200  |       }
201  |     else if(!(flag&8))
202  |       {
203  |        Free(cur_inc->name);
204  |        cur_inc->name=MallocString(name);
205  |       }
206  |    }
207  | 
208  |  if(flag&2)
209  |    {
210  |     inc_depth++;
211  | 
212  |     if(!inc_type)
213  |       {
214  |        inc_type=(char*)Malloc(16);
215  |        inc_name=(char**)Malloc(16*sizeof(char*));
216  |       }
217  |     else
218  |        if(!(inc_depth%16))
219  |          {
220  |           inc_type=(char*)Realloc(inc_type,(unsigned)(inc_depth+16));
221  |           inc_name=(char**)Realloc(inc_name,(unsigned)(sizeof(char*)*(inc_depth+16)));
222  |          }
223  | 
224  |     if(inc_depth>1 && inc_type[inc_depth-2]==GLOBAL)
225  |        inc_type[inc_depth-1]=GLOBAL;
226  |     else
227  |        inc_type[inc_depth-1]=cur_inc?cur_inc->scope:(flag&8)?GLOBAL:LOCAL;
228  | 
229  |     inc_name[inc_depth-1]=CopyString(name);
230  |    }
231  |  else
232  |     inc_depth--;
233  | 
234  |  if(inc_type && inc_depth>0)
235  |     in_header=inc_type[inc_depth-1];
236  |  else
237  |     in_header=0;
238  | 
239  |  SetCurrentComment(NULL);
240  | 
241  |  cur_inc=NULL;
242  | 
243  |  return(name);
244  | }
245  | 
246  | 
247  | /*++++++++++++++++++++++++++++++++++++++
248  |   Function that is called when a #define is seen in the current file.
249  | 
250  |   char* name The name of the #defined symbol.
251  |   ++++++++++++++++++++++++++++++++++++++*/
252  | 
253  | void SeenDefine(char* name)
254  | {
255  |  Define def;
256  | 
257  | #if DEBUG
258  |  printf("#Preproc.c# Defined name '%s'\n",name);
259  | #endif
260  | 
261  |  def=NewDefineType(name);
262  | 
263  |  def->comment=MallocString(GetCurrentComment());
264  | 
265  |  def->lineno=parse_line;
266  | 
267  |  AddToLinkedList(CurFile->defines,Define,def);
268  | 
269  |  cur_def=def;
270  | }
271  | 
272  | 
273  | /*++++++++++++++++++++++++++++++++++++++
274  |   Function that is called when a comment is seen in a #define definition.
275  |   ++++++++++++++++++++++++++++++++++++++*/
276  | 
277  | void SeenDefineComment(void)
278  | {
279  |  char* comment=GetCurrentComment();
280  | 
281  | #if DEBUG
282  |  printf("#Preproc.c# #define inline comment '%s' in %s\n",comment,cur_def->name);
283  | #endif
284  | 
285  |  if(!cur_def->comment)
286  |     cur_def->comment=MallocString(comment);
287  | }
288  | 
289  | 
290  | /*++++++++++++++++++++++++++++++++++++++
291  |   Function that is called when a #define value is seen in the current file.
292  | 
293  |   char* value The value of the #defined symbol.
294  |   ++++++++++++++++++++++++++++++++++++++*/
295  | 
296  | void SeenDefineValue(char* value)
297  | {
298  | #if DEBUG
299  |  printf("#Preproc.c# #define value '%s' for %s\n",value,cur_def->name);
300  | #endif
301  | 
302  |  cur_def->value=MallocString(value);
303  | }
304  | 
305  | 
306  | /*++++++++++++++++++++++++++++++++++++++
307  |   Function that is called when a #define function argument is seen in the current definition.
308  | 
309  |   char* name The argument.
310  |   ++++++++++++++++++++++++++++++++++++++*/
311  | 
312  | void SeenDefineFunctionArg(char* name)
313  | {
314  | #if DEBUG
315  |  printf("#Preproc.c# #define Function arg '%s' in %s()\n",name,cur_def->name);
316  | #endif
317  | 
318  |  AddToStringList2(cur_def->args,name,SplitComment(&cur_def->comment,name),0,0);
319  | }
320  | 
321  | 
322  | /*++++++++++++++++++++++++++++++++++++++
323  |   Function that is called when a comment is seen in a #define function definition.
324  |   ++++++++++++++++++++++++++++++++++++++*/
325  | 
326  | void SeenDefineFuncArgComment(void)
327  | {
328  |  char* comment=GetCurrentComment();
329  | 
330  | #if DEBUG
331  |  printf("#Preproc.c# #define Function arg comment '%s' in %s()\n",comment,cur_def->name);
332  | #endif
333  | 
334  |  if(!cur_def->args->s2[cur_def->args->n-1])
335  |     cur_def->args->s2[cur_def->args->n-1]=MallocString(comment);
336  | }
337  | 
338  | 
339  | /*++++++++++++++++++++++++++++++++++++++
340  |   Tidy up all of the local variables in case of a problem and abnormal parser termination.
341  |   ++++++++++++++++++++++++++++++++++++++*/
342  | 
343  | void ResetPreProcAnalyser(void)
344  | {
345  |  in_header=0;
346  | 
347  |  cur_inc=NULL;
348  |  cur_def=NULL;
349  | 
350  |  inc_depth=0;
351  | 
352  |  if(inc_type) Free(inc_type);
353  |  inc_type=NULL;
354  |  if(inc_name) Free(inc_name);
355  |  inc_name=NULL;
356  | 
357  |  if(cwd) Free(cwd);
358  |  cwd=NULL;
359  | }
360  | 
361  | 
362  | /*++++++++++++++++++++++++++++++++++++++
363  |   Create a new Include datatype.
364  | 
365  |   Include NewIncludeType Return the new Include type.
366  | 
367  |   char *name The name of the new include.
368  |   ++++++++++++++++++++++++++++++++++++++*/
369  | 
370  | static Include NewIncludeType(char *name)
371  | {
372  |  Include inc=(Include)Calloc(1,sizeof(struct _Include));
373  | 
374  |  inc->name=MallocString(name);
375  | 
376  |  return(inc);
377  | }
378  | 
379  | 
380  | /*++++++++++++++++++++++++++++++++++++++
381  |   Delete the specified Include type.
382  | 
383  |   Include inc The Include type to be deleted.
384  |   ++++++++++++++++++++++++++++++++++++++*/
385  | 
386  | void DeleteIncludeType(Include inc)
387  | {
388  |  if(inc->comment) Free(inc->comment);
389  |  if(inc->name)    Free(inc->name);
390  |  if(inc->includes)
391  |    {
392  |     Include p=inc->includes;
393  |     do{
394  |        Include n=p->next;
395  |        DeleteIncludeType(p);
396  |        p=n;
397  |       }
398  |     while(p);
399  |    }
400  |  Free(inc);
401  | }
402  | 
403  | 
404  | /*++++++++++++++++++++++++++++++++++++++
405  |   Create a new Define datatype.
406  | 
407  |   Define NewDefineType Return the new Define type.
408  | 
409  |   char *name The name of the new define.
410  |   ++++++++++++++++++++++++++++++++++++++*/
411  | 
412  | static Define NewDefineType(char *name)
413  | {
414  |  Define def=(Define)Calloc(1,sizeof(struct _Define)); /* clear unused pointers */
415  | 
416  |  def->name=MallocString(name);
417  |  def->args=NewStringList2();
418  | 
419  |  return(def);
420  | }
421  | 
422  | 
423  | /*++++++++++++++++++++++++++++++++++++++
424  |   Delete the specified Define type.
425  | 
426  |   Define def The Define type to be deleted.
427  |   ++++++++++++++++++++++++++++++++++++++*/
428  | 
429  | void DeleteDefineType(Define def)
430  | {
431  |  if(def->comment) Free(def->comment);
432  |  if(def->name)    Free(def->name);
433  |  if(def->value)   Free(def->value);
434  |  if(def->args)    DeleteStringList2(def->args);
435  |  Free(def);
436  | }