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