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