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