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