1    | /***************************************
2    |   $Header: /home/amb/cxref/RCS/func.c 1.19 2001/01/06 13:05:12 amb Exp $
3    | 
4    |   C Cross Referencing & Documentation tool. Version 1.5c.
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)
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  | }