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