1 | /*************************************** 2 | $Header: /home/amb/cxref/RCS/preproc.c 1.21 2003/06/22 13:49:58 amb Exp $ 3 | 4 | C Cross Referencing & Documentation tool. Version 1.5e. 5 | 6 | Collects the pre-processing instruction stuff. 7 | ******************/ /****************** 8 | Written by Andrew M. Bishop 9 | 10 | This file Copyright 1995,96,97,99,2000,01,02,03 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 output of debugging information for this file. +*/ 17 | #define DEBUG 0 18 | 19 | #include <stdlib.h> 20 | #include <stdio.h> 21 | #include <string.h> 22 | #include <unistd.h> 23 | 24 | #include <limits.h> 25 | #include <sys/stat.h> 26 | 27 | #include "memory.h" 28 | #include "datatype.h" 29 | #include "parse-yy.h" 30 | #include "cxref.h" 31 | 32 | /*+ The file that is currently being processed. +*/ 33 | extern File CurFile; 34 | 35 | /*+ The name of the include directories specified on the command line. +*/ 36 | extern char **option_incdirs; 37 | 38 | /*+ The number of include directories on the command line. +*/ 39 | extern int option_nincdirs; 40 | 41 | /*+ When in a header file, this is set to 1, to allow most of the stuff to be skipped. +*/ 42 | int in_header=0; 43 | 44 | /*+ The current #include we are looking at. +*/ 45 | static Include cur_inc=NULL; 46 | 47 | /*+ The current #define we are looking at. +*/ 48 | static Define cur_def=NULL; 49 | 50 | /*+ The depth of includes. +*/ 51 | static int inc_depth=0; 52 | 53 | /*+ The type of include at this depth. +*/ 54 | static char *inc_type=NULL; 55 | 56 | /*+ The name of the include file at this depth. +*/ 57 | static char **inc_name=NULL; 58 | 59 | /*+ The working directory. +*/ 60 | static char *cwd=NULL; 61 | 62 | 63 | static Include NewIncludeType(char *name); 64 | static Define NewDefineType(char *name); 65 | 66 | 67 | /*++++++++++++++++++++++++++++++++++++++ 68 | Function that is called when an included file is seen in the current file. 69 | 70 | char *name The name of the file from the source code. 71 | ++++++++++++++++++++++++++++++++++++++*/ 72 | 73 | void SeenInclude(char *name) 74 | { 75 | #if DEBUG 76 | printf("#Preproc.c# #include %s\n",name); 77 | #endif 78 | 79 | if(!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL) 80 | { 81 | Include inc,*t=&CurFile->includes; 82 | int inc_scope=(*name=='"')?LOCAL:GLOBAL; 83 | int i; 84 | 85 | name++; 86 | name[strlen(name)-1]=0; 87 | 88 | if(inc_scope==LOCAL && option_nincdirs) 89 | for(i=0;i<option_nincdirs;i++) 90 | { 91 | char *newname=CanonicaliseName(ConcatStrings(3,option_incdirs[i],"/",name)); 92 | struct stat buf; 93 | 94 | if(!lstat(newname,&buf)) 95 | {name=newname;break;} 96 | } 97 | 98 | for(i=0;i<inc_depth;i++) 99 | { 100 | while(*t && (*t)->next) 101 | t=&(*t)->next; 102 | t=&(*t)->includes; 103 | } 104 | 105 | inc=NewIncludeType(name); 106 | 107 | inc->comment=MallocString(GetCurrentComment()); 108 | inc->scope=inc_scope; 109 | 110 | AddToLinkedList(*t,Include,inc); 111 | 112 | cur_inc=inc; 113 | } 114 | else 115 | cur_inc=NULL; 116 | } 117 | 118 | 119 | /*++++++++++++++++++++++++++++++++++++++ 120 | Function that is called when a comment is seen following a #include. 121 | ++++++++++++++++++++++++++++++++++++++*/ 122 | 123 | void SeenIncludeComment(void) 124 | { 125 | char* comment=GetCurrentComment(); 126 | 127 | #if DEBUG 128 | printf("#Preproc.c# #include trailing comment '%s' for %s\n",comment,cur_inc->name); 129 | #endif 130 | 131 | if(!cur_inc->comment) 132 | cur_inc->comment=MallocString(comment); 133 | } 134 | 135 | 136 | /*++++++++++++++++++++++++++++++++++++++ 137 | Function that is called when a change in current file is seen. 138 | 139 | char *SeenFileChange Returns the filename that we are now in. 140 | 141 | char *name The pathname of the included file as determined by gcc. 142 | 143 | int flag The flags that GCC leaves in the file 144 | ++++++++++++++++++++++++++++++++++++++*/ 145 | 146 | char *SeenFileChange(char *name,int flag) 147 | { 148 | if(!cwd) 149 | { 150 | cwd=(char*)Malloc(PATH_MAX+1); 151 | if(!getcwd(cwd,PATH_MAX)) 152 | cwd[0]=0; 153 | } 154 | 155 | /* Special gcc-3.x fake names for built-in #defines. */ 156 | 157 | if(!strcmp(name,"<built-in>") || !strcmp(name,"<command line>")) 158 | { 159 | in_header=1; 160 | return(NULL); 161 | } 162 | 163 | name=CanonicaliseName(name); 164 | 165 | if(!strncmp(name,cwd,strlen(cwd))) 166 | name=name+strlen(cwd); 167 | 168 | if(flag&4) 169 | { 170 | if(inc_depth>=2) 171 | name=inc_name[inc_depth-2]; 172 | else 173 | name=CurFile->name; 174 | } 175 | 176 | #if DEBUG 177 | printf("#Preproc.c# FileChange - %s %s (flag=%d)\n",flag&2?"Included ":"Return to",name,flag); 178 | #endif 179 | 180 | /* Store the information. */ 181 | 182 | if(flag&2 && (!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL)) 183 | { 184 | if(!cur_inc) 185 | { 186 | if(flag&8) 187 | SeenInclude(ConcatStrings(3,"<",name,">")); 188 | else 189 | SeenInclude(ConcatStrings(3,"\"",name,"\"")); 190 | } 191 | else if(!(flag&8)) 192 | { 193 | Free(cur_inc->name); 194 | cur_inc->name=MallocString(name); 195 | } 196 | } 197 | 198 | if(flag&2) 199 | { 200 | inc_depth++; 201 | 202 | if(!inc_type) 203 | { 204 | inc_type=(char*)Malloc(16); 205 | inc_name=(char**)Malloc(16*sizeof(char*)); 206 | } 207 | else 208 | if(!(inc_depth%16)) 209 | { 210 | inc_type=(char*)Realloc(inc_type,(unsigned)(inc_depth+16)); 211 | inc_name=(char**)Realloc(inc_name,(unsigned)(sizeof(char*)*(inc_depth+16))); 212 | } 213 | 214 | if(inc_depth>1 && inc_type[inc_depth-2]==GLOBAL) 215 | inc_type[inc_depth-1]=GLOBAL; 216 | else 217 | inc_type[inc_depth-1]=cur_inc?cur_inc->scope:(flag&8)?GLOBAL:LOCAL; 218 | 219 | inc_name[inc_depth-1]=CopyString(name); 220 | } 221 | else 222 | inc_depth--; 223 | 224 | if(inc_type && inc_depth>0) 225 | in_header=inc_type[inc_depth-1]; 226 | else 227 | in_header=0; 228 | 229 | SetCurrentComment(NULL); 230 | 231 | cur_inc=NULL; 232 | 233 | return(name); 234 | } 235 | 236 | 237 | /*++++++++++++++++++++++++++++++++++++++ 238 | Function that is called when a #define is seen in the current file. 239 | 240 | char* name The name of the #defined symbol. 241 | ++++++++++++++++++++++++++++++++++++++*/ 242 | 243 | void SeenDefine(char* name) 244 | { 245 | Define def; 246 | 247 | #if DEBUG 248 | printf("#Preproc.c# Defined name '%s'\n",name); 249 | #endif 250 | 251 | def=NewDefineType(name); 252 | 253 | def->comment=MallocString(GetCurrentComment()); 254 | 255 | def->lineno=parse_line; 256 | 257 | AddToLinkedList(CurFile->defines,Define,def); 258 | 259 | cur_def=def; 260 | } 261 | 262 | 263 | /*++++++++++++++++++++++++++++++++++++++ 264 | Function that is called when a comment is seen in a #define definition. 265 | ++++++++++++++++++++++++++++++++++++++*/ 266 | 267 | void SeenDefineComment(void) 268 | { 269 | char* comment=GetCurrentComment(); 270 | 271 | #if DEBUG 272 | printf("#Preproc.c# #define inline comment '%s' in %s\n",comment,cur_def->name); 273 | #endif 274 | 275 | if(!cur_def->comment) 276 | cur_def->comment=MallocString(comment); 277 | } 278 | 279 | 280 | /*++++++++++++++++++++++++++++++++++++++ 281 | Function that is called when a #define value is seen in the current file. 282 | 283 | char* value The value of the #defined symbol. 284 | ++++++++++++++++++++++++++++++++++++++*/ 285 | 286 | void SeenDefineValue(char* value) 287 | { 288 | #if DEBUG 289 | printf("#Preproc.c# #define value '%s' for %s\n",value,cur_def->name); 290 | #endif 291 | 292 | cur_def->value=MallocString(value); 293 | } 294 | 295 | 296 | /*++++++++++++++++++++++++++++++++++++++ 297 | Function that is called when a #define function argument is seen in the current definition. 298 | 299 | char* name The argument. 300 | ++++++++++++++++++++++++++++++++++++++*/ 301 | 302 | void SeenDefineFunctionArg(char* name) 303 | { 304 | #if DEBUG 305 | printf("#Preproc.c# #define Function arg '%s' in %s()\n",name,cur_def->name); 306 | #endif 307 | 308 | AddToStringList2(cur_def->args,name,SplitComment(&cur_def->comment,name),0,0); 309 | } 310 | 311 | 312 | /*++++++++++++++++++++++++++++++++++++++ 313 | Function that is called when a comment is seen in a #define function definition. 314 | ++++++++++++++++++++++++++++++++++++++*/ 315 | 316 | void SeenDefineFuncArgComment(void) 317 | { 318 | char* comment=GetCurrentComment(); 319 | 320 | #if DEBUG 321 | printf("#Preproc.c# #define Function arg comment '%s' in %s()\n",comment,cur_def->name); 322 | #endif 323 | 324 | if(!cur_def->args->s2[cur_def->args->n-1]) 325 | cur_def->args->s2[cur_def->args->n-1]=MallocString(comment); 326 | } 327 | 328 | 329 | /*++++++++++++++++++++++++++++++++++++++ 330 | Tidy up all of the local variables in case of a problem and abnormal parser termination. 331 | ++++++++++++++++++++++++++++++++++++++*/ 332 | 333 | void ResetPreProcAnalyser(void) 334 | { 335 | in_header=0; 336 | 337 | cur_inc=NULL; 338 | cur_def=NULL; 339 | 340 | inc_depth=0; 341 | 342 | if(inc_type) Free(inc_type); 343 | inc_type=NULL; 344 | if(inc_name) Free(inc_name); 345 | inc_name=NULL; 346 | 347 | if(cwd) Free(cwd); 348 | cwd=NULL; 349 | } 350 | 351 | 352 | /*++++++++++++++++++++++++++++++++++++++ 353 | Create a new Include datatype. 354 | 355 | Include NewIncludeType Return the new Include type. 356 | 357 | char *name The name of the new include. 358 | ++++++++++++++++++++++++++++++++++++++*/ 359 | 360 | static Include NewIncludeType(char *name) 361 | { 362 | Include inc=(Include)Calloc(1,sizeof(struct _Include)); 363 | 364 | inc->name=MallocString(name); 365 | 366 | return(inc); 367 | } 368 | 369 | 370 | /*++++++++++++++++++++++++++++++++++++++ 371 | Delete the specified Include type. 372 | 373 | Include inc The Include type to be deleted. 374 | ++++++++++++++++++++++++++++++++++++++*/ 375 | 376 | void DeleteIncludeType(Include inc) 377 | { 378 | if(inc->comment) Free(inc->comment); 379 | if(inc->name) Free(inc->name); 380 | if(inc->includes) 381 | { 382 | Include p=inc->includes; 383 | do{ 384 | Include n=p->next; 385 | DeleteIncludeType(p); 386 | p=n; 387 | } 388 | while(p); 389 | } 390 | Free(inc); 391 | } 392 | 393 | 394 | /*++++++++++++++++++++++++++++++++++++++ 395 | Create a new Define datatype. 396 | 397 | Define NewDefineType Return the new Define type. 398 | 399 | char *name The name of the new define. 400 | ++++++++++++++++++++++++++++++++++++++*/ 401 | 402 | static Define NewDefineType(char *name) 403 | { 404 | Define def=(Define)Calloc(1,sizeof(struct _Define)); /* clear unused pointers */ 405 | 406 | def->name=MallocString(name); 407 | def->args=NewStringList2(); 408 | 409 | return(def); 410 | } 411 | 412 | 413 | /*++++++++++++++++++++++++++++++++++++++ 414 | Delete the specified Define type. 415 | 416 | Define def The Define type to be deleted. 417 | ++++++++++++++++++++++++++++++++++++++*/ 418 | 419 | void DeleteDefineType(Define def) 420 | { 421 | if(def->comment) Free(def->comment); 422 | if(def->name) Free(def->name); 423 | if(def->value) Free(def->value); 424 | if(def->args) DeleteStringList2(def->args); 425 | Free(def); 426 | }