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