1 | /***************************************
2 | $Header: /home/amb/CVS/cxref/src/func.c,v 1.20 2003-12-02 19:51:08 amb Exp $
3 |
4 | C Cross Referencing & Documentation tool. Version 1.5f.
5 |
6 | Handle Function 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 debugging information from this file. +*/
17 | #define DEBUG 0
18 |
19 | #include <stdlib.h>
20 | #include <stdio.h>
21 | #include <string.h>
22 |
23 | #include "memory.h"
24 | #include "datatype.h"
25 | #include "parse-yy.h"
26 | #include "cxref.h"
27 |
28 | /*+ The current parsing options. +*/
29 | extern int option_xref;
30 |
31 | /*+ The current file that is being processed. +*/
32 | extern File CurFile;
33 |
34 | /*+ When in a header file include functions from that file (except inline functions). +*/
35 | extern int in_header;
36 |
37 | /*+ The current function, this is initialised by the start of a possible declaration and maintained until all of the
38 | arguments have been added and confirmation that it is a definition and not a prototype is seen. +*/
39 | static Function cur_func=NULL;
40 |
41 | /*+ The list of function prototypes and the files that they are defined in. +*/
42 | static StringList2 prototypes=NULL;
43 |
44 | static Function NewFunctionType(char *name,char *type);
45 |
46 |
47 | /*++++++++++++++++++++++++++++++++++++++
48 | Function that is called when a function prototype is seen.
49 |
50 | char* name The name of the function.
51 |
52 | int in_a_function Whether the reference is from within a function or at the top level of the file.
53 | ++++++++++++++++++++++++++++++++++++++*/
54 |
55 | void SeenFunctionProto(char* name,int in_a_function)
56 | {
57 | if(!(option_xref&XREF_FUNC))
58 | return;
59 |
60 | #if DEBUG
61 | printf("#Func.c# Function prototype '%s'\n",name);
62 | #endif
63 |
64 | if(!in_a_function)
65 | {
66 | if(!prototypes)
67 | prototypes=NewStringList2();
68 | AddToStringList2(prototypes,name,parse_file,0,1);
69 | }
70 | else
71 | AddToStringList(cur_func->protos,name,0,1);
72 | }
73 |
74 |
75 | /*++++++++++++++++++++++++++++++++++++++
76 | Function that is called when a function declaration is seen.
77 | This may or may not be a function defintion, we will need to wait and see.
78 |
79 | char* name The name of the function.
80 |
81 | int scope The scope of the function definition.
82 | ++++++++++++++++++++++++++++++++++++++*/
83 |
84 | void SeenFunctionDeclaration(char* name,int scope)
85 | {
86 | #if DEBUG
87 | printf("#Func.c# Function declaration for '%s()'\n",name);
88 | #endif
89 |
90 | if(cur_func)
91 | DeleteFunctionType(cur_func);
92 |
93 | cur_func=NewFunctionType(name,NULL);
94 |
95 | cur_func->comment=MallocString(GetCurrentComment());
96 | cur_func->scope=scope;
97 |
98 | cur_func->lineno=parse_line;
99 |
100 | if(in_header)
101 | cur_func->incfrom=MallocString(parse_file);
102 | }
103 |
104 |
105 | /*++++++++++++++++++++++++++++++++++++++
106 | Called when a possible function definition is confirmed.
107 |
108 | char* type The type of the function, or NULL at the end of a definition.
109 | ++++++++++++++++++++++++++++++++++++++*/
110 |
111 | void SeenFunctionDefinition(char* type)
112 | {
113 | Function *func=&CurFile->functions;
114 | int i;
115 |
116 | if(cur_func->scope&INLINED && cur_func->incfrom)
117 | return;
118 |
119 | #if DEBUG
120 | printf("#Func.c# Function definition %s for '%s()'\n",type?"start":"end",cur_func->name);
121 | #endif
122 |
123 | if(!type)
124 | {cur_func=NULL;return;}
125 |
126 | cur_func->type=MallocString(type);
127 |
128 | cur_func->cret=MallocString(SplitComment(&cur_func->comment,type));
129 | if(!cur_func->cret)
130 | cur_func->cret=MallocString(GetCurrentComment());
131 |
132 | if(option_xref&XREF_FUNC)
133 | if(prototypes)
134 | for(i=0;i<prototypes->n;i++)
135 | if(!strcmp(cur_func->name,prototypes->s1[i]))
136 | {cur_func->protofile=MallocString(prototypes->s2[i]); break;}
137 |
138 | for(i=0;i<cur_func->args->n;i++)
139 | if(strcmp(cur_func->args->s1[i],"void") && strcmp(cur_func->args->s1[i],"...") && !strchr(cur_func->args->s1[i],' '))
140 | {
141 | char *old=cur_func->args->s1[i];
142 | cur_func->args->s1[i]=MallocString(ConcatStrings(2,"int ",old));
143 | cur_func->args->s2[i]=MallocString(SplitComment(&cur_func->comment,cur_func->args->s1[i]));
144 | Free(old);
145 | }
146 |
147 | while(*func)
148 | {
149 | if(strcmp(cur_func->name,(*func)->name)<0)
150 | {
151 | Function temp=*func;
152 | *func=cur_func;
153 | cur_func->next=temp;
154 | break;
155 | }
156 | func=&(*func)->next;
157 | }
158 |
159 | if(!cur_func->next)
160 | *func=cur_func;
161 | }
162 |
163 | /*++++++++++++++++++++++++++++++++++++++
164 | Function that is called when a function argument is seen in the current function declaration.
165 |
166 | char* name The name of the argument.
167 |
168 | char* type The type of the argument, or NULL if a traditional style function definition.
169 | ++++++++++++++++++++++++++++++++++++++*/
170 |
171 | void SeenFunctionArg(char* name,char *type)
172 | {
173 | #if DEBUG
174 | printf("#Func.c# Function arg %s '%s' in %s()\n",name?name:"K&R",type?type:"K&R",cur_func->name);
175 | #endif
176 |
177 | if(name)
178 | {
179 | if(type && strcmp(type,"void"))
180 | {
181 | int i;
182 |
183 | for(i=0;i<cur_func->args->n;i++)
184 | if(!strcmp(cur_func->args->s1[i],name))
185 | {
186 | Free(cur_func->args->s1[i]);
187 | cur_func->args->s1[i]=MallocString(type);
188 | cur_func->args->s2[i]=MallocString(SplitComment(&cur_func->comment,type));
189 | break;
190 | }
191 | if(i==cur_func->args->n)
192 | AddToStringList2(cur_func->args,type,SplitComment(&cur_func->comment,type),0,0);
193 |
194 | if(!cur_func->args->s2[i])
195 | cur_func->args->s2[i]=MallocString(GetCurrentComment());
196 | }
197 | else
198 | AddToStringList2(cur_func->args,name,NULL,0,0);
199 | }
200 | }
201 |
202 |
203 | /*++++++++++++++++++++++++++++++++++++++
204 | Function that is called when a comment is seen, that may be in a function body.
205 |
206 | int SeenFuncIntComment Returns a true value if the comment was accepted as an function internal comment.
207 |
208 | char* comment The comment that has been seen.
209 | ++++++++++++++++++++++++++++++++++++++*/
210 |
211 | int SeenFuncIntComment(char* comment)
212 | {
213 | if(!cur_func || !cur_func->type)
214 | return(0);
215 |
216 | #if DEBUG
217 | printf("#Func.c# Function internal comment '%s' in %s()\n",comment,cur_func->name);
218 | #endif
219 |
220 | if(cur_func->comment)
221 | {
222 | char* c=cur_func->comment;
223 |
224 | cur_func->comment=MallocString(ConcatStrings(3,c,"\n\n",comment));
225 | Free(c);
226 | }
227 | else
228 | cur_func->comment=MallocString(comment);
229 |
230 | return(1);
231 | }
232 |
233 |
234 | /*++++++++++++++++++++++++++++++++++++++
235 | Function that is called when a function call is seen in the current function.
236 |
237 | char* name The name of the function that is called.
238 | ++++++++++++++++++++++++++++++++++++++*/
239 |
240 | void SeenFunctionCall(char* name)
241 | {
242 | if(!(option_xref&XREF_FUNC))
243 | return;
244 |
245 | #if DEBUG
246 | printf("#Func.c# Function call for '%s()' in %s()\n",name,cur_func->name);
247 | #endif
248 |
249 | AddToStringList2(cur_func->calls,name,NULL,1,1);
250 | }
251 |
252 |
253 | /*++++++++++++++++++++++++++++++++++++++
254 | Function that is called when a function or variable is referenced in the current function.
255 |
256 | char* name The name of the function or variable that is referenced.
257 |
258 | int in_a_function Whether the reference is from within a function or at the top level of the file.
259 | ++++++++++++++++++++++++++++++++++++++*/
260 |
261 | void CheckFunctionVariableRef(char* name,int in_a_function)
262 | {
263 | Variable var =CurFile->variables;
264 | Function func=CurFile->functions;
265 | StringList2 sl=NULL;
266 |
267 | if(!(option_xref&(XREF_VAR|XREF_FUNC)))
268 | return;
269 |
270 | if(IsAScopeVariable(name))
271 | return;
272 |
273 | #if DEBUG
274 | printf("#Func.c# Function/Variable reference for '%s' in %s\n",name,in_a_function?cur_func->name:CurFile->name);
275 | #endif
276 |
277 | if(option_xref&XREF_VAR)
278 | while(var)
279 | {
280 | if(!strcmp(var->name,name))
281 | {
282 | if(in_a_function)
283 | sl=cur_func->v_refs;
284 | else
285 | sl=CurFile->v_refs;
286 | break;
287 | }
288 | var=var->next;
289 | }
290 |
291 | if(!sl && option_xref&XREF_FUNC)
292 | while(func)
293 | {
294 | if(!strcmp(func->name,name))
295 | {
296 | if(in_a_function)
297 | sl=cur_func->f_refs;
298 | else
299 | sl=CurFile->f_refs;
300 | break;
301 | }
302 | func=func->next;
303 | }
304 |
305 | if(!sl && option_xref&XREF_FUNC)
306 | {
307 | int i;
308 | if(in_a_function)
309 | for(i=0;i<cur_func->protos->n;i++)
310 | if(!strcmp(name,cur_func->protos->s[i]))
311 | {
312 | sl=cur_func->f_refs;
313 | break;
314 | }
315 |
316 | if(!sl && prototypes)
317 | for(i=0;i<prototypes->n;i++)
318 | if(!strcmp(name,prototypes->s1[i]))
319 | {
320 | if(in_a_function)
321 | sl=cur_func->f_refs;
322 | else
323 | sl=CurFile->f_refs;
324 | break;
325 | }
326 | }
327 |
328 | /* Now add the function or variable to the Function / File structure. */
329 |
330 | if(sl)
331 | AddToStringList2(sl,name,NULL,1,1);
332 | }
333 |
334 |
335 | /*++++++++++++++++++++++++++++++++++++++
336 | Tidy up all of the local variables in case of a problem and abnormal parser termination.
337 | ++++++++++++++++++++++++++++++++++++++*/
338 |
339 | void ResetFunctionAnalyser(void)
340 | {
341 | if(prototypes) DeleteStringList2(prototypes);
342 | prototypes=NULL;
343 |
344 | if(cur_func)
345 | {
346 | Function func=CurFile->functions;
347 | int delete_cur_func=1;
348 |
349 | while(func)
350 | {
351 | if(func==cur_func)
352 | delete_cur_func=0;
353 |
354 | func=func->next;
355 | }
356 |
357 | if(delete_cur_func)
358 | DeleteFunctionType(cur_func);
359 |
360 | cur_func=NULL;
361 | }
362 | }
363 |
364 |
365 | /*++++++++++++++++++++++++++++++++++++++
366 | Create a new Function Type variable.
367 |
368 | Function NewFunctionType Returns the new Function variable.
369 |
370 | char *name The name of the function.
371 |
372 | char *type The type of the function.
373 | ++++++++++++++++++++++++++++++++++++++*/
374 |
375 | static Function NewFunctionType(char *name,char *type)
376 | {
377 | Function func=(Function)Calloc(1,sizeof(struct _Function)); /* clear unused pointers */
378 |
379 | func->name =MallocString(name);
380 | func->type =MallocString(type);
381 | func->args =NewStringList2();
382 | func->protos=NewStringList();
383 | func->calls =NewStringList2();
384 | func->called=NewStringList2();
385 | func->used =NewStringList2();
386 | func->v_refs=NewStringList2();
387 | func->f_refs=NewStringList2();
388 |
389 | return(func);
390 | }
391 |
392 |
393 | /*++++++++++++++++++++++++++++++++++++++
394 | Delete the specified Function type.
395 |
396 | Function func The Function type to be deleted.
397 | ++++++++++++++++++++++++++++++++++++++*/
398 |
399 | void DeleteFunctionType(Function func)
400 | {
401 | if(func->comment) Free(func->comment);
402 | if(func->name) Free(func->name);
403 | if(func->type) Free(func->type);
404 | if(func->cret) Free(func->cret);
405 | if(func->protofile) Free(func->protofile);
406 | if(func->incfrom) Free(func->incfrom);
407 | if(func->args) DeleteStringList2(func->args);
408 | if(func->protos) DeleteStringList(func->protos);
409 | if(func->calls) DeleteStringList2(func->calls);
410 | if(func->called) DeleteStringList2(func->called);
411 | if(func->used) DeleteStringList2(func->used);
412 | if(func->v_refs) DeleteStringList2(func->v_refs);
413 | if(func->f_refs) DeleteStringList2(func->f_refs);
414 | Free(func);
415 | }