1    | /***************************************
2    |   $Header: /home/amb/cxref/RCS/func.c 1.18 1999/01/24 16:53:49 amb Exp $
3    | 
4    |   C Cross Referencing & Documentation tool. Version 1.5.
5    | 
6    |   Handle Function 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 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  |     if(type)
179  |       {
180  |        int i;
181  | 
182  |        for(i=0;i<cur_func->args->n;i++)
183  |           if(!strcmp(cur_func->args->s1[i],name))
184  |             {
185  |              Free(cur_func->args->s1[i]);
186  |              cur_func->args->s1[i]=MallocString(type);
187  |              cur_func->args->s2[i]=MallocString(SplitComment(&cur_func->comment,type));
188  |              break;
189  |             }
190  |        if(i==cur_func->args->n)
191  |           AddToStringList2(cur_func->args,type,SplitComment(&cur_func->comment,type),0,0);
192  | 
193  |        if(!cur_func->args->s2[i])
194  |           cur_func->args->s2[i]=MallocString(GetCurrentComment());
195  |       }
196  |     else
197  |        AddToStringList2(cur_func->args,name,NULL,0,0);
198  | }
199  | 
200  | 
201  | /*++++++++++++++++++++++++++++++++++++++
202  |   Function that is called when a comment is seen, that may be in a function body.
203  | 
204  |   int SeenFuncIntComment Returns a true value if the comment was accepted as an function internal comment.
205  | 
206  |   char* comment The comment that has been seen.
207  |   ++++++++++++++++++++++++++++++++++++++*/
208  | 
209  | int SeenFuncIntComment(char* comment)
210  | {
211  |  if(!cur_func || !cur_func->type)
212  |     return(0);
213  | 
214  | #if DEBUG
215  |  printf("#Func.c# Function internal comment '%s' in %s()\n",comment,cur_func->name);
216  | #endif
217  | 
218  |  if(cur_func->comment)
219  |    {
220  |     char* c=cur_func->comment;
221  | 
222  |     cur_func->comment=MallocString(ConcatStrings(3,c,"\n\n",comment));
223  |     Free(c);
224  |    }
225  |  else
226  |     cur_func->comment=MallocString(comment);
227  | 
228  |  return(1);
229  | }
230  | 
231  | 
232  | /*++++++++++++++++++++++++++++++++++++++
233  |   Function that is called when a function call is seen in the current function.
234  | 
235  |   char* name The name of the function that is called.
236  |   ++++++++++++++++++++++++++++++++++++++*/
237  | 
238  | void SeenFunctionCall(char* name)
239  | {
240  |  if(!(option_xref&XREF_FUNC))
241  |     return;
242  | 
243  | #if DEBUG
244  |  printf("#Func.c# Function call for '%s()' in %s()\n",name,cur_func->name);
245  | #endif
246  | 
247  |  AddToStringList2(cur_func->calls,name,NULL,1,1);
248  | }
249  | 
250  | 
251  | /*++++++++++++++++++++++++++++++++++++++
252  |   Function that is called when a function or variable is referenced in the current function.
253  | 
254  |   char* name The name of the function or variable that is referenced.
255  | 
256  |   int in_a_function Whether the reference is from within a function or at the top level of the file.
257  |   ++++++++++++++++++++++++++++++++++++++*/
258  | 
259  | void CheckFunctionVariableRef(char* name,int in_a_function)
260  | {
261  |  Variable var =CurFile->variables;
262  |  Function func=CurFile->functions;
263  |  StringList2 sl=NULL;
264  | 
265  |  if(!(option_xref&(XREF_VAR|XREF_FUNC)))
266  |     return;
267  | 
268  |  if(IsAScopeVariable(name))
269  |     return;
270  | 
271  | #if DEBUG
272  |  printf("#Func.c# Function/Variable reference for '%s' in %s\n",name,in_a_function?cur_func->name:CurFile->name);
273  | #endif
274  | 
275  |  if(option_xref&XREF_VAR)
276  |     while(var)
277  |       {
278  |        if(!strcmp(var->name,name))
279  |          {
280  |           if(in_a_function)
281  |              sl=cur_func->v_refs;
282  |           else
283  |              sl=CurFile->v_refs;
284  |           break;
285  |          }
286  |        var=var->next;
287  |       }
288  | 
289  |  if(!sl && option_xref&XREF_FUNC)
290  |     while(func)
291  |       {
292  |        if(!strcmp(func->name,name))
293  |          {
294  |           if(in_a_function)
295  |              sl=cur_func->f_refs;
296  |           else
297  |              sl=CurFile->f_refs;
298  |           break;
299  |          }
300  |        func=func->next;
301  |       }
302  | 
303  |  if(!sl && option_xref&XREF_FUNC)
304  |    {
305  |     int i;
306  |     if(in_a_function)
307  |        for(i=0;i<cur_func->protos->n;i++)
308  |           if(!strcmp(name,cur_func->protos->s[i]))
309  |             {
310  |              sl=cur_func->f_refs;
311  |              break;
312  |             }
313  | 
314  |     if(!sl && prototypes)
315  |        for(i=0;i<prototypes->n;i++)
316  |           if(!strcmp(name,prototypes->s1[i]))
317  |             {
318  |              if(in_a_function)
319  |                 sl=cur_func->f_refs;
320  |              else
321  |                 sl=CurFile->f_refs;
322  |              break;
323  |             }
324  |    }
325  | 
326  |  /* Now add the function or variable to the Function / File structure. */
327  | 
328  |  if(sl)
329  |     AddToStringList2(sl,name,NULL,1,1);
330  | }
331  | 
332  | 
333  | /*++++++++++++++++++++++++++++++++++++++
334  |   Tidy up all of the local variables in case of a problem and abnormal parser termination.
335  |   ++++++++++++++++++++++++++++++++++++++*/
336  | 
337  | void ResetFunctionAnalyser(void)
338  | {
339  |  if(prototypes) DeleteStringList2(prototypes);
340  |  prototypes=NULL;
341  | 
342  |  if(cur_func)
343  |    {
344  |     Function func=CurFile->functions;
345  |     int delete_cur_func=1;
346  | 
347  |     while(func)
348  |       {
349  |        if(func==cur_func)
350  |           delete_cur_func=0;
351  | 
352  |        func=func->next;
353  |       }
354  | 
355  |     if(delete_cur_func)
356  |        DeleteFunctionType(cur_func);
357  | 
358  |     cur_func=NULL;
359  |    }
360  | }
361  | 
362  | 
363  | /*++++++++++++++++++++++++++++++++++++++
364  |   Create a new Function Type variable.
365  | 
366  |   Function NewFunctionType Returns the new Function variable.
367  | 
368  |   char *name The name of the function.
369  | 
370  |   char *type The type of the function.
371  |   ++++++++++++++++++++++++++++++++++++++*/
372  | 
373  | static Function NewFunctionType(char *name,char *type)
374  | {
375  |  Function func=(Function)Calloc(1,sizeof(struct _Function)); /* clear unused pointers */
376  | 
377  |  func->name  =MallocString(name);
378  |  func->type  =MallocString(type);
379  |  func->args  =NewStringList2();
380  |  func->protos=NewStringList();
381  |  func->calls =NewStringList2();
382  |  func->called=NewStringList2();
383  |  func->used  =NewStringList2();
384  |  func->v_refs=NewStringList2();
385  |  func->f_refs=NewStringList2();
386  | 
387  |  return(func);
388  | }
389  | 
390  | 
391  | /*++++++++++++++++++++++++++++++++++++++
392  |   Delete the specified Function type.
393  | 
394  |   Function func The Function type to be deleted.
395  |   ++++++++++++++++++++++++++++++++++++++*/
396  | 
397  | void DeleteFunctionType(Function func)
398  | {
399  |  if(func->comment)   Free(func->comment);
400  |  if(func->name)      Free(func->name);
401  |  if(func->type)      Free(func->type);
402  |  if(func->cret)      Free(func->cret);
403  |  if(func->protofile) Free(func->protofile);
404  |  if(func->incfrom)   Free(func->incfrom);
405  |  if(func->args)      DeleteStringList2(func->args);
406  |  if(func->protos)    DeleteStringList(func->protos);
407  |  if(func->calls)     DeleteStringList2(func->calls);
408  |  if(func->called)    DeleteStringList2(func->called);
409  |  if(func->used)      DeleteStringList2(func->used);
410  |  if(func->v_refs)    DeleteStringList2(func->v_refs);
411  |  if(func->f_refs)    DeleteStringList2(func->f_refs);
412  |  Free(func);
413  | }