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 | }