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