1 | /*************************************** 2 | $Header: /home/amb/cxref/src/RCS/func.c 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 | }