1 | /*************************************** 2 | $Header: /home/amb/cxref/RCS/preproc.c 1.22 2004/01/18 11:38:35 amb Exp $ 3 | 4 | C Cross Referencing & Documentation tool. Version 1.5f. 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,04 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 | else if(flag==-1) 163 | { 164 | in_header=0; 165 | return(CurFile->name); 166 | } 167 | 168 | name=CanonicaliseName(name); 169 | 170 | if(!strncmp(name,cwd,strlen(cwd))) 171 | name=name+strlen(cwd); 172 | 173 | if(flag&4) 174 | { 175 | if(inc_depth>=2) 176 | name=inc_name[inc_depth-2]; 177 | else 178 | name=CurFile->name; 179 | } 180 | 181 | #if DEBUG 182 | printf("#Preproc.c# FileChange - %s %s (flag=%d)\n",flag&2?"Included ":"Return to",name,flag); 183 | #endif 184 | 185 | /* Store the information. */ 186 | 187 | if(flag&2 && (!inc_type || inc_depth==0 || inc_type[inc_depth-1]==LOCAL)) 188 | { 189 | if(!cur_inc) 190 | { 191 | if(flag&8) 192 | SeenInclude(ConcatStrings(3,"<",name,">")); 193 | else 194 | SeenInclude(ConcatStrings(3,"\"",name,"\"")); 195 | } 196 | else if(!(flag&8)) 197 | { 198 | Free(cur_inc->name); 199 | cur_inc->name=MallocString(name); 200 | } 201 | } 202 | 203 | if(flag&2) 204 | { 205 | inc_depth++; 206 | 207 | if(!inc_type) 208 | { 209 | inc_type=(char*)Malloc(16); 210 | inc_name=(char**)Malloc(16*sizeof(char*)); 211 | } 212 | else 213 | if(!(inc_depth%16)) 214 | { 215 | inc_type=(char*)Realloc(inc_type,(unsigned)(inc_depth+16)); 216 | inc_name=(char**)Realloc(inc_name,(unsigned)(sizeof(char*)*(inc_depth+16))); 217 | } 218 | 219 | if(inc_depth>1 && inc_type[inc_depth-2]==GLOBAL) 220 | inc_type[inc_depth-1]=GLOBAL; 221 | else 222 | inc_type[inc_depth-1]=cur_inc?cur_inc->scope:(flag&8)?GLOBAL:LOCAL; 223 | 224 | inc_name[inc_depth-1]=CopyString(name); 225 | } 226 | else 227 | inc_depth--; 228 | 229 | if(inc_type && inc_depth>0) 230 | in_header=inc_type[inc_depth-1]; 231 | else 232 | in_header=0; 233 | 234 | SetCurrentComment(NULL); 235 | 236 | cur_inc=NULL; 237 | 238 | return(name); 239 | } 240 | 241 | 242 | /*++++++++++++++++++++++++++++++++++++++ 243 | Function that is called when a #define is seen in the current file. 244 | 245 | char* name The name of the #defined symbol. 246 | ++++++++++++++++++++++++++++++++++++++*/ 247 | 248 | void SeenDefine(char* name) 249 | { 250 | Define def; 251 | 252 | #if DEBUG 253 | printf("#Preproc.c# Defined name '%s'\n",name); 254 | #endif 255 | 256 | def=NewDefineType(name); 257 | 258 | def->comment=MallocString(GetCurrentComment()); 259 | 260 | def->lineno=parse_line; 261 | 262 | AddToLinkedList(CurFile->defines,Define,def); 263 | 264 | cur_def=def; 265 | } 266 | 267 | 268 | /*++++++++++++++++++++++++++++++++++++++ 269 | Function that is called when a comment is seen in a #define definition. 270 | ++++++++++++++++++++++++++++++++++++++*/ 271 | 272 | void SeenDefineComment(void) 273 | { 274 | char* comment=GetCurrentComment(); 275 | 276 | #if DEBUG 277 | printf("#Preproc.c# #define inline comment '%s' in %s\n",comment,cur_def->name); 278 | #endif 279 | 280 | if(!cur_def->comment) 281 | cur_def->comment=MallocString(comment); 282 | } 283 | 284 | 285 | /*++++++++++++++++++++++++++++++++++++++ 286 | Function that is called when a #define value is seen in the current file. 287 | 288 | char* value The value of the #defined symbol. 289 | ++++++++++++++++++++++++++++++++++++++*/ 290 | 291 | void SeenDefineValue(char* value) 292 | { 293 | #if DEBUG 294 | printf("#Preproc.c# #define value '%s' for %s\n",value,cur_def->name); 295 | #endif 296 | 297 | cur_def->value=MallocString(value); 298 | } 299 | 300 | 301 | /*++++++++++++++++++++++++++++++++++++++ 302 | Function that is called when a #define function argument is seen in the current definition. 303 | 304 | char* name The argument. 305 | ++++++++++++++++++++++++++++++++++++++*/ 306 | 307 | void SeenDefineFunctionArg(char* name) 308 | { 309 | #if DEBUG 310 | printf("#Preproc.c# #define Function arg '%s' in %s()\n",name,cur_def->name); 311 | #endif 312 | 313 | AddToStringList2(cur_def->args,name,SplitComment(&cur_def->comment,name),0,0); 314 | } 315 | 316 | 317 | /*++++++++++++++++++++++++++++++++++++++ 318 | Function that is called when a comment is seen in a #define function definition. 319 | ++++++++++++++++++++++++++++++++++++++*/ 320 | 321 | void SeenDefineFuncArgComment(void) 322 | { 323 | char* comment=GetCurrentComment(); 324 | 325 | #if DEBUG 326 | printf("#Preproc.c# #define Function arg comment '%s' in %s()\n",comment,cur_def->name); 327 | #endif 328 | 329 | if(!cur_def->args->s2[cur_def->args->n-1]) 330 | cur_def->args->s2[cur_def->args->n-1]=MallocString(comment); 331 | } 332 | 333 | 334 | /*++++++++++++++++++++++++++++++++++++++ 335 | Tidy up all of the local variables in case of a problem and abnormal parser termination. 336 | ++++++++++++++++++++++++++++++++++++++*/ 337 | 338 | void ResetPreProcAnalyser(void) 339 | { 340 | in_header=0; 341 | 342 | cur_inc=NULL; 343 | cur_def=NULL; 344 | 345 | inc_depth=0; 346 | 347 | if(inc_type) Free(inc_type); 348 | inc_type=NULL; 349 | if(inc_name) Free(inc_name); 350 | inc_name=NULL; 351 | 352 | if(cwd) Free(cwd); 353 | cwd=NULL; 354 | } 355 | 356 | 357 | /*++++++++++++++++++++++++++++++++++++++ 358 | Create a new Include datatype. 359 | 360 | Include NewIncludeType Return the new Include type. 361 | 362 | char *name The name of the new include. 363 | ++++++++++++++++++++++++++++++++++++++*/ 364 | 365 | static Include NewIncludeType(char *name) 366 | { 367 | Include inc=(Include)Calloc(1,sizeof(struct _Include)); 368 | 369 | inc->name=MallocString(name); 370 | 371 | return(inc); 372 | } 373 | 374 | 375 | /*++++++++++++++++++++++++++++++++++++++ 376 | Delete the specified Include type. 377 | 378 | Include inc The Include type to be deleted. 379 | ++++++++++++++++++++++++++++++++++++++*/ 380 | 381 | void DeleteIncludeType(Include inc) 382 | { 383 | if(inc->comment) Free(inc->comment); 384 | if(inc->name) Free(inc->name); 385 | if(inc->includes) 386 | { 387 | Include p=inc->includes; 388 | do{ 389 | Include n=p->next; 390 | DeleteIncludeType(p); 391 | p=n; 392 | } 393 | while(p); 394 | } 395 | Free(inc); 396 | } 397 | 398 | 399 | /*++++++++++++++++++++++++++++++++++++++ 400 | Create a new Define datatype. 401 | 402 | Define NewDefineType Return the new Define type. 403 | 404 | char *name The name of the new define. 405 | ++++++++++++++++++++++++++++++++++++++*/ 406 | 407 | static Define NewDefineType(char *name) 408 | { 409 | Define def=(Define)Calloc(1,sizeof(struct _Define)); /* clear unused pointers */ 410 | 411 | def->name=MallocString(name); 412 | def->args=NewStringList2(); 413 | 414 | return(def); 415 | } 416 | 417 | 418 | /*++++++++++++++++++++++++++++++++++++++ 419 | Delete the specified Define type. 420 | 421 | Define def The Define type to be deleted. 422 | ++++++++++++++++++++++++++++++++++++++*/ 423 | 424 | void DeleteDefineType(Define def) 425 | { 426 | if(def->comment) Free(def->comment); 427 | if(def->name) Free(def->name); 428 | if(def->value) Free(def->value); 429 | if(def->args) DeleteStringList2(def->args); 430 | Free(def); 431 | }