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