1 | /*************************************** 2 | $Header: /home/amb/cxref/RCS/cxref.c 1.45 1999/01/26 19:40:12 amb Exp $ 3 | 4 | C Cross Referencing & Documentation tool. Version 1.5. 5 | ******************/ /****************** 6 | Written by Andrew M. Bishop 7 | 8 | This file Copyright 1995,96,97,98,99 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 | #include <stdio.h> 15 | #include <stdlib.h> 16 | #include <string.h> 17 | #include <sys/types.h> 18 | #include <sys/wait.h> 19 | #include <sys/stat.h> 20 | #include <unistd.h> 21 | 22 | #include "parse-yy.h" 23 | #include "memory.h" 24 | #include "datatype.h" 25 | #include "cxref.h" 26 | 27 | /*+ The default value of the CPP command. +*/ 28 | #ifdef CXREF_CPP 29 | #define CPP_COMMAND CXREF_CPP 30 | #else 31 | #define CPP_COMMAND "gcc -E -C -dD -dI" 32 | #endif 33 | 34 | /*+ The name of the file to read the configuration from. +*/ 35 | #define CXREF_CONFIG_FILE ".cxref" 36 | 37 | 38 | static void Usage(int verbose); 39 | static int ParseConfigFile(void); 40 | static int ParseOptions(int nargs,char **args,int fromfile); 41 | 42 | static int DocumentTheFile(char* name); 43 | static FILE* popen_execvp(char** command); 44 | static int pclose_execvp(FILE* f); 45 | 46 | static char** cpp_command; /*+ The actual cpp command that is built up, adding -D, -U and -I options. +*/ 47 | static int cpp_command_num=0; /*+ The number of arguments to the cpp command. +*/ 48 | static int cpp_argument_num=0; /*+ The number of arguments to the -CPP argument. +*/ 49 | 50 | /*+ The command line switch that sets the format of the output, +*/ 51 | int option_all_comments=0, /*+ use all comments. +*/ 52 | option_verbatim_comments=0, /*+ insert the comments verbatim into the output. +*/ 53 | option_block_comments=0, /*+ remove the leading block comment marker. +*/ 54 | option_no_comments=0, /*+ ignore all comments. +*/ 55 | option_xref=0, /*+ do cross referencing. +*/ 56 | option_warn=0, /*+ produce warnings. +*/ 57 | option_index=0, /*+ produce an index. +*/ 58 | option_raw=0, /*+ produce raw output. +*/ 59 | option_latex=0, /*+ produce LaTeX output. +*/ 60 | option_html=0, /*+ produce HTML output. +*/ 61 | option_rtf=0, /*+ produce RTF output. +*/ 62 | option_sgml=0; /*+ produce SGML output. +*/ 63 | 64 | /*+ The option to control the mode of operation. +*/ 65 | static int option_delete=0; 66 | 67 | /*+ The command line switch for the output name, +*/ 68 | char *option_odir=NULL, /*+ the directory to use. +*/ 69 | *option_name=NULL, /*+ the base part of the name. +*/ 70 | *option_root=NULL; /*+ the source tree root directory. +*/ 71 | 72 | /*+ The name of the include directories specified on the command line. +*/ 73 | char **option_incdirs=NULL; 74 | 75 | /*+ The number of include directories on the command line. +*/ 76 | int option_nincdirs=0; 77 | 78 | /*+ The names of the files to process. +*/ 79 | static char **option_files=NULL; 80 | 81 | /*+ The number of files to process. +*/ 82 | static int option_nfiles=0; 83 | 84 | /*+ The current file that is being processed. +*/ 85 | File CurFile=NULL; 86 | 87 | 88 | /*++++++++++++++++++++++++++++++++++++++ 89 | The main function that calls the parser. 90 | 91 | int main Returns the status, zero for normal termination, else an error. 92 | 93 | int argc The command line number of arguments. 94 | 95 | char** argv The actual command line arguments 96 | ++++++++++++++++++++++++++++++++++++++*/ 97 | 98 | int main(int argc,char** argv) 99 | { 100 | int i; 101 | char *root_prefix=NULL; 102 | char here[256],there[256]; 103 | 104 | if(argc==1) 105 | Usage(1); 106 | 107 | /* Setup the variables. */ 108 | 109 | cpp_command=(char**)Malloc(8*sizeof(char*)); 110 | cpp_command[cpp_command_num++]=MallocString(CPP_COMMAND); 111 | 112 | for(i=1;cpp_command[cpp_command_num-1][i];i++) 113 | if(cpp_command[cpp_command_num-1][i]==' ') 114 | { 115 | cpp_command[cpp_command_num-1][i]=0; 116 | if((cpp_command_num%8)==6) 117 | cpp_command=(char**)Realloc(cpp_command,(cpp_command_num+10)*sizeof(char*)); 118 | cpp_command[cpp_command_num++]=MallocString(&cpp_command[cpp_command_num-1][i+1]); 119 | i=1; 120 | } 121 | 122 | cpp_argument_num=cpp_command_num; 123 | 124 | option_incdirs=(char**)Malloc(8*sizeof(char*)); 125 | option_incdirs[0]=MallocString("."); 126 | option_nincdirs=1; 127 | 128 | option_odir=MallocString("."); 129 | 130 | option_name=MallocString("cxref"); 131 | 132 | option_files=(char**)Malloc(8*sizeof(char*)); 133 | 134 | /* Parse the command line options. */ 135 | 136 | if(ParseOptions(argc-1,&argv[1],0)) 137 | Usage(0); 138 | 139 | /* Parse the options in .cxref in this directory. */ 140 | 141 | if(ParseConfigFile()) 142 | Usage(0); 143 | 144 | /* Change directory. */ 145 | 146 | if(option_root) 147 | { 148 | if(!getcwd(there,255)) 149 | {fprintf(stderr,"cxref: Error cannot get current working directory (1).\n");exit(1);} 150 | if(chdir(option_root)) 151 | {fprintf(stderr,"cxref: Error cannot change directory to '%s'.\n",option_root);exit(1);} 152 | } 153 | 154 | if(!getcwd(here,255)) 155 | {fprintf(stderr,"cxref: Error cannot get current working directory (2).\n");exit(1);} 156 | 157 | if(option_root) 158 | { 159 | if(!strcmp(here,there)) 160 | root_prefix="."; 161 | else if(!strncmp(here,there,strlen(here))) 162 | root_prefix=there+strlen(here)+1; 163 | else 164 | {fprintf(stderr,"cxref: Error the -R option has not specified a parent directory of the current one.\n");exit(1);} 165 | } 166 | 167 | /* Modify the -I options for the new root directory. */ 168 | 169 | for(i=1;i<cpp_command_num;i++) 170 | if(cpp_command[i][0]=='-' && cpp_command[i][1]=='I') 171 | { 172 | if(cpp_command[i][2]==0) 173 | { 174 | char *old=cpp_command[++i]; 175 | if(cpp_command[i][0]!='/' && root_prefix) 176 | cpp_command[i]=MallocString(CanonicaliseName(ConcatStrings(3,root_prefix,"/",cpp_command[i]))); 177 | else if(cpp_command[i][0]=='/' && !strcmp(cpp_command[i],here)) 178 | cpp_command[i]=MallocString("."); 179 | else if(cpp_command[i][0]=='/' && !strncmp(cpp_command[i],here,strlen(here))) 180 | cpp_command[i]=MallocString(cpp_command[i]+strlen(here)+1); 181 | else 182 | cpp_command[i]=MallocString(CanonicaliseName(cpp_command[i])); 183 | Free(old); 184 | } 185 | else 186 | { 187 | char *old=cpp_command[i]; 188 | if(cpp_command[i][2]!='/' && root_prefix) 189 | cpp_command[i]=MallocString(ConcatStrings(2,"-I",CanonicaliseName(ConcatStrings(3,root_prefix,"/",cpp_command[i]+2)))); 190 | else if(cpp_command[i][2]=='/' && !strcmp(&cpp_command[i][2],here)) 191 | cpp_command[i]=MallocString("-I."); 192 | else if(cpp_command[i][2]=='/' && !strncmp(&cpp_command[i][2],here,strlen(here))) 193 | cpp_command[i]=MallocString(ConcatStrings(2,"-I",cpp_command[i]+2+strlen(here)+1)); 194 | else 195 | cpp_command[i]=MallocString(ConcatStrings(2,"-I",CanonicaliseName(cpp_command[i]+2))); 196 | Free(old); 197 | } 198 | } 199 | 200 | for(i=0;i<option_nincdirs;i++) 201 | { 202 | char *old=option_incdirs[i]; 203 | if(*option_incdirs[i]!='/' && root_prefix) 204 | option_incdirs[i]=MallocString(CanonicaliseName(ConcatStrings(3,root_prefix,"/",option_incdirs[i]))); 205 | else if(*option_incdirs[i]=='/' && !strcmp(option_incdirs[i],here)) 206 | option_incdirs[i]=MallocString("."); 207 | else if(*option_incdirs[i]=='/' && !strncmp(option_incdirs[i],here,strlen(here))) 208 | option_incdirs[i]=MallocString(option_incdirs[i]+strlen(here)+1); 209 | else 210 | option_incdirs[i]=MallocString(CanonicaliseName(option_incdirs[i])); 211 | Free(old); 212 | } 213 | 214 | /* Parse the options in .cxref in the root directory. */ 215 | 216 | if(option_root) 217 | if(ParseConfigFile()) 218 | Usage(0); 219 | 220 | TidyMemory(); 221 | 222 | /* Check the options for validity */ 223 | 224 | if(option_warn&WARN_XREF && !option_xref) 225 | fprintf(stderr,"cxref: Warning using '-warn-xref' without '-xref'.\n"); 226 | 227 | /* Process each file. */ 228 | 229 | if(option_files) 230 | for(i=0;i<option_nfiles;i++) 231 | { 232 | char *filename=CanonicaliseName(root_prefix?ConcatStrings(3,root_prefix,"/",option_files[i]):option_files[i]); 233 | 234 | if(!option_delete) 235 | { 236 | CurFile=NewFile(filename); 237 | 238 | if(!DocumentTheFile(filename)) 239 | { 240 | if(option_xref) 241 | CrossReference(CurFile); 242 | 243 | if(option_raw || option_warn) 244 | WriteWarnRawFile(CurFile); 245 | if(option_latex) 246 | WriteLatexFile(CurFile); 247 | if(option_html) 248 | WriteHTMLFile(CurFile); 249 | if(option_rtf) 250 | WriteRTFFile(CurFile); 251 | if(option_sgml) 252 | WriteSGMLFile(CurFile); 253 | } 254 | 255 | ResetLexer(); 256 | ResetParser(); 257 | ResetPreProcAnalyser(); 258 | ResetTypeAnalyser(); 259 | ResetVariableAnalyser(); 260 | ResetFunctionAnalyser(); 261 | 262 | DeleteComment(); 263 | 264 | DeleteFile(CurFile); 265 | CurFile=NULL; 266 | } 267 | else 268 | { 269 | CrossReferenceDelete(filename); 270 | 271 | WriteLatexFileDelete(filename); 272 | WriteHTMLFileDelete(filename); 273 | WriteRTFFileDelete(filename); 274 | WriteSGMLFileDelete(filename); 275 | } 276 | 277 | TidyMemory(); 278 | } 279 | 280 | /* Create the index */ 281 | 282 | if(option_index) 283 | { 284 | StringList files; 285 | StringList2 funcs,vars,types; 286 | 287 | files=NewStringList(); 288 | funcs=NewStringList2(); 289 | vars=NewStringList2(); 290 | types=NewStringList2(); 291 | 292 | CreateAppendix(files,funcs,vars,types); 293 | 294 | if(option_raw||option_warn) 295 | WriteWarnRawAppendix(files,funcs,vars,types); 296 | if(option_latex) 297 | WriteLatexAppendix(files,funcs,vars,types); 298 | if(option_html) 299 | WriteHTMLAppendix(files,funcs,vars,types); 300 | if(option_rtf) 301 | WriteRTFAppendix(files,funcs,vars,types); 302 | if(option_sgml) 303 | WriteSGMLAppendix(files,funcs,vars,types); 304 | 305 | DeleteStringList(files); 306 | DeleteStringList2(funcs); 307 | DeleteStringList2(vars); 308 | DeleteStringList2(types); 309 | 310 | TidyMemory(); 311 | } 312 | 313 | /* Tidy up */ 314 | 315 | Free(option_odir); 316 | Free(option_name); 317 | if(option_root) 318 | Free(option_root); 319 | 320 | for(i=0;i<cpp_command_num;i++) 321 | Free(cpp_command[i]); 322 | Free(cpp_command); 323 | 324 | for(i=0;i<option_nincdirs;i++) 325 | Free(option_incdirs[i]); 326 | Free(option_incdirs); 327 | 328 | for(i=0;i<option_nfiles;i++) 329 | Free(option_files[i]); 330 | Free(option_files); 331 | 332 | PrintMemoryStatistics(); 333 | 334 | return(0); 335 | } 336 | 337 | 338 | /*++++++++++++++++++++++++++++++++++++++ 339 | Print out the usage instructions. 340 | 341 | int verbose If true then output a long version of the information. 342 | ++++++++++++++++++++++++++++++++++++++*/ 343 | 344 | static void Usage(int verbose) 345 | { 346 | fputs("\n" 347 | " C Cross Referencing & Documenting tool - Version 1.5\n" 348 | " ----------------------------------------------------\n" 349 | "\n" 350 | "(c) Andrew M. Bishop 1995,96,97,98,99 [ amb@gedanken.demon.co.uk ]\n" 351 | " [http://www.gedanken.demon.co.uk/]\n" 352 | "\n" 353 | "Usage: cxref filename [ ... filename]\n" 354 | " [-Odirname] [-Nbasename] [-Rdirname]\n" 355 | " [-all-comments] [-no-comments]\n" 356 | " [-verbatim-comments] [-block-comments]\n" 357 | " [-xref[-all][-file][-func][-var][-type]]\n" 358 | " [-warn[-all][-comment][-xref]]\n" 359 | " [-index[-all][-file][-func][-var][-type]]\n" 360 | " [-latex209|-latex2e] [-html20|-html32] [-rtf] [-sgml] [-raw]\n" 361 | " [-Idirname] [-Ddefine] [-Udefine]\n" 362 | " [-CPP cpp_program] [-- cpp_arg [ ... cpp_arg]]\n" 363 | "\n" 364 | "Usage: cxref filename [ ... filename] -delete\n" 365 | " [-Odirname] [-Nbasename] [-Rdirname]\n" 366 | "\n", 367 | stderr); 368 | 369 | if(verbose) 370 | fputs("filename ... : Files to document.\n" 371 | "-delete : Delete all references to the named files.\n" 372 | "\n" 373 | "-Odirname : The output directory for the documentation.\n" 374 | "-Nbasename : The base filename for the output documentation.\n" 375 | "-Rdirname : The root directory of the source tree.\n" 376 | "\n" 377 | "-all-comments : Use all comments.\n" 378 | "-verbatim-comments : Insert the comments verbatim in the output.\n" 379 | "-block-comments : The comments are in block style.\n" 380 | "-no-comments : Ignore all of the comments.\n" 381 | "\n" 382 | "-xref[-*] : Do cross referencing (of specified types).\n" 383 | "-warn[-*] : Produce warnings (of comments or cross references).\n" 384 | "\n" 385 | "-index[-*] : Produce a cross reference index (of specified types).\n" 386 | "\n" 387 | "-latex209 | -latex2e : Produce LaTeX output (version 2.09 or 2e - default=2e).\n" 388 | "-html20 | -html32 : Produce HTML output (version 2.0 or 3.2 - default=3.2).\n" 389 | "-rtf : Produce RTF output (version 1.x).\n" 390 | "-sgml : Produce SGML output (for SGML tools version 1.0.x).\n" 391 | "-raw : Produce raw output .\n" 392 | "\n" 393 | "-I*, -D*, -U* : The usual compiler switches.\n" 394 | "-CPP cpp_program : The cpp program to use.\n" 395 | " : (default '" CPP_COMMAND "')\n" 396 | "-- cpp_arg ... : All arguments after the '--' are passed to cpp.\n" 397 | "\n" 398 | "The file .cxref in the current directory can also contain any of these arguments\n" 399 | "one per line, (except for filename and -delete).\n", 400 | stderr); 401 | else 402 | fputs("Run cxref with no arguments to get more verbose help\n", 403 | stderr); 404 | 405 | exit(1); 406 | } 407 | 408 | 409 | /*++++++++++++++++++++++++++++++++++++++ 410 | Read in the options from the configuration file. 411 | 412 | int ParseConfigFile Returns the values returned by ParseOptions(). 413 | ++++++++++++++++++++++++++++++++++++++*/ 414 | 415 | static int ParseConfigFile(void) 416 | { 417 | FILE *file=fopen(CXREF_CONFIG_FILE,"r"); 418 | char **lines=NULL; 419 | int nlines=0; 420 | char data[257]; 421 | 422 | if(file) 423 | { 424 | while(fgets(data,256,file)) 425 | { 426 | char *d=data+strlen(data)-1; 427 | 428 | if(*data=='#') 429 | continue; 430 | 431 | while(d>=data && (*d=='\r' || *d=='\n' || *d==' ')) 432 | *d--=0; 433 | 434 | if(d<data) 435 | continue; 436 | 437 | if(!lines) 438 | lines=(char**)Malloc(8*sizeof(char*)); 439 | else if((nlines%8)==7) 440 | lines=(char**)Realloc(lines,(nlines+9)*sizeof(char*)); 441 | 442 | if((!strncmp(data,"-I",2) || !strncmp(data,"-D",2) || !strncmp(data,"-U",2) || 443 | !strncmp(data,"-O",2) || !strncmp(data,"-N",2) || !strncmp(data,"-R",2)) && 444 | (data[2]==' ' || data[2]=='\t')) 445 | { 446 | int i=2; 447 | while(data[i]==' ' || data[i]=='\t') 448 | data[i++]=0; 449 | lines[nlines++]=CopyString(data); 450 | lines[nlines++]=CopyString(data+i); 451 | } 452 | else if(!strncmp(data,"-CPP",4) && 453 | (data[4]==' ' || data[4]=='\t')) 454 | { 455 | int i=4; 456 | while(data[i]==' ' || data[i]=='\t') 457 | data[i++]=0; 458 | lines[nlines++]=CopyString(data); 459 | lines[nlines++]=CopyString(data+i); 460 | } 461 | else 462 | if(*data) 463 | lines[nlines++]=CopyString(data); 464 | } 465 | 466 | if(nlines) 467 | { 468 | int n_files=option_nfiles; 469 | 470 | if(ParseOptions(nlines,lines,1)) 471 | { 472 | fprintf(stderr,"cxref: Error parsing the .cxref file\n"); 473 | return(1); 474 | } 475 | 476 | Free(lines); 477 | 478 | if(n_files!=option_nfiles) 479 | { 480 | for(;n_files<option_nfiles;n_files++) 481 | fprintf(stderr,"cxref: File names '%s' only allowed on command line.\n",option_files[n_files]); 482 | return(1); 483 | } 484 | } 485 | 486 | fclose(file); 487 | } 488 | 489 | return(0); 490 | } 491 | 492 | 493 | /*++++++++++++++++++++++++++++++++++++++ 494 | Parse the options from the command line or from the .cxref file. 495 | 496 | int ParseOptions Return 1 if there is an error. 497 | 498 | int nargs The number of arguments. 499 | 500 | char **args The actual arguments 501 | 502 | int fromfile A flag indicating that they are read from the .cxref file. 503 | ++++++++++++++++++++++++++++++++++++++*/ 504 | 505 | static int ParseOptions(int nargs,char **args,int fromfile) 506 | { 507 | int i,end_of_args=0; 508 | 509 | for(i=0;i<nargs;i++) 510 | { 511 | if(end_of_args) 512 | { 513 | if((cpp_command_num%8)==6) 514 | cpp_command=(char**)Realloc(cpp_command,(cpp_command_num+10)*sizeof(char*)); 515 | cpp_command[cpp_command_num++]=MallocString(args[i]); 516 | continue; 517 | } 518 | 519 | if(!strncmp(args[i],"-I",2) || !strncmp(args[i],"-D",2) || !strncmp(args[i],"-U",2)) 520 | { 521 | char *incdir=NULL; 522 | if((cpp_command_num%8)==6) 523 | cpp_command=(char**)Realloc(cpp_command,(cpp_command_num+10)*sizeof(char*)); 524 | cpp_command[cpp_command_num++]=MallocString(args[i]); 525 | if(args[i][2]==0) 526 | { 527 | if(args[i][1]=='I') 528 | incdir=args[i+1]; 529 | if(i==nargs-1) 530 | {fprintf(stderr,"cxref: The -%c option requires a following argument.\n",args[i][1]);return(1);} 531 | if((cpp_command_num%8)==6) 532 | cpp_command=(char**)Realloc(cpp_command,(cpp_command_num+10)*sizeof(char*)); 533 | cpp_command[cpp_command_num++]=MallocString(args[++i]); 534 | } 535 | else 536 | if(args[i][1]=='I') 537 | incdir=&args[i][2]; 538 | 539 | if(incdir) 540 | { 541 | if((option_nincdirs%8)==0) 542 | option_incdirs=(char**)Realloc(option_incdirs,(option_nincdirs+8)*sizeof(char*)); 543 | option_incdirs[option_nincdirs++]=MallocString(incdir); 544 | } 545 | continue; 546 | } 547 | 548 | if(!strcmp(args[i],"-CPP")) 549 | { 550 | char **old=cpp_command,*command; 551 | int j,old_com_num=cpp_command_num,old_arg_num=cpp_argument_num; 552 | 553 | if(args[i][4]==0) 554 | { 555 | if(i==nargs-1) 556 | {fprintf(stderr,"cxref: The -CPP option requires a following argument.\n");return(1);} 557 | command=args[++i]; 558 | } 559 | else 560 | command=&args[i][4]; 561 | 562 | cpp_command_num=0; 563 | cpp_command=(char**)Malloc(8*sizeof(char*)); 564 | cpp_command[cpp_command_num++]=MallocString(command); 565 | 566 | for(j=1;cpp_command[cpp_command_num-1][j];j++) 567 | if(cpp_command[cpp_command_num-1][j]==' ') 568 | { 569 | cpp_command[cpp_command_num-1][j]=0; 570 | if((cpp_command_num%8)==6) 571 | cpp_command=(char**)Realloc(cpp_command,(cpp_command_num+10)*sizeof(char*)); 572 | cpp_command[cpp_command_num++]=MallocString(&cpp_command[cpp_command_num-1][j+1]); 573 | j=1; 574 | } 575 | 576 | cpp_argument_num=cpp_command_num; 577 | 578 | for(j=old_arg_num;j<old_com_num;j++) 579 | { 580 | if((cpp_command_num%8)==6) 581 | cpp_command=(char**)Realloc(cpp_command,(cpp_command_num+10)*sizeof(char*)); 582 | cpp_command[cpp_command_num++]=old[j]; 583 | } 584 | 585 | for(j=0;j<old_arg_num;j++) 586 | Free(old[j]); 587 | Free(old); 588 | 589 | continue; 590 | } 591 | 592 | if(!strncmp(args[i],"-O",2)) 593 | { 594 | if(option_odir) 595 | Free(option_odir); 596 | if(args[i][2]==0) 597 | { 598 | if(i==nargs-1) 599 | {fprintf(stderr,"cxref: The -O option requires a following argument.\n");return(1);} 600 | option_odir=MallocString(args[++i]); 601 | } 602 | else 603 | option_odir=MallocString(&args[i][2]); 604 | continue; 605 | } 606 | 607 | if(!strncmp(args[i],"-N",2)) 608 | { 609 | if(option_name) 610 | Free(option_name); 611 | if(args[i][2]==0) 612 | { 613 | if(i==nargs-1) 614 | {fprintf(stderr,"cxref: The -N option requires a following argument.\n");return(1);} 615 | option_name=MallocString(args[++i]); 616 | } 617 | else 618 | option_name=MallocString(&args[i][2]); 619 | continue; 620 | } 621 | 622 | if(!strncmp(args[i],"-R",2)) 623 | { 624 | if(option_root) 625 | Free(option_root); 626 | if(args[i][2]==0) 627 | { 628 | if(i==nargs-1) 629 | {fprintf(stderr,"cxref: The -R option requires a following argument.\n");return(1);} 630 | option_root=MallocString(args[++i]); 631 | } 632 | else 633 | option_root=MallocString(&args[i][2]); 634 | if(*option_root=='.' && !*(option_root+1)) 635 | option_root=NULL; 636 | continue; 637 | } 638 | 639 | if(!strcmp(args[i],"-delete")) 640 | {if(fromfile) {fprintf(stderr,"cxref: The -delete option cannot be used in the .cxref file.\n");return(1);} 641 | option_delete=1; continue;} 642 | 643 | if(!strcmp(args[i],"-all-comments")) 644 | {option_all_comments=1; continue;} 645 | 646 | if(!strcmp(args[i],"-verbatim-comments")) 647 | {option_verbatim_comments=1; continue;} 648 | 649 | if(!strcmp(args[i],"-block-comments")) 650 | {option_block_comments=1; continue;} 651 | 652 | if(!strcmp(args[i],"-no-comments")) 653 | {option_no_comments=1; continue;} 654 | 655 | if(!strncmp(args[i],"-xref",5)) 656 | { 657 | char* p=&args[i][5]; 658 | 659 | if(!*p) 660 | option_xref=XREF_ALL; 661 | else 662 | while(*p) 663 | { 664 | if(!strncmp(p,"-all" ,4)) {option_xref|=XREF_ALL ; p=&p[4]; continue;} 665 | if(!strncmp(p,"-file",5)) {option_xref|=XREF_FILE; p=&p[5]; continue;} 666 | if(!strncmp(p,"-func",5)) {option_xref|=XREF_FUNC; p=&p[5]; continue;} 667 | if(!strncmp(p,"-var" ,4)) {option_xref|=XREF_VAR ; p=&p[4]; continue;} 668 | if(!strncmp(p,"-type",5)) {option_xref|=XREF_TYPE; p=&p[5]; continue;} 669 | break; 670 | } 671 | continue; 672 | } 673 | 674 | if(!strncmp(args[i],"-warn",5)) 675 | { 676 | char* p=&args[i][5]; 677 | 678 | if(!*p) 679 | option_warn=WARN_ALL; 680 | else 681 | while(*p) 682 | { 683 | if(!strncmp(p,"-all" ,4)) {option_warn|=WARN_ALL ; p=&p[4]; continue;} 684 | if(!strncmp(p,"-comment",8)) {option_warn|=WARN_COMMENT; p=&p[8]; continue;} 685 | if(!strncmp(p,"-xref" ,5)) {option_warn|=WARN_XREF ; p=&p[5]; continue;} 686 | break; 687 | } 688 | continue; 689 | } 690 | 691 | if(!strncmp(args[i],"-index",6)) 692 | { 693 | char* p=&args[i][6]; 694 | 695 | if(!*p) 696 | option_index=INDEX_ALL; 697 | else 698 | while(*p) 699 | { 700 | if(!strncmp(p,"-all" ,4)) {option_index|=INDEX_ALL ; p=&p[4]; continue;} 701 | if(!strncmp(p,"-file",5)) {option_index|=INDEX_FILE; p=&p[5]; continue;} 702 | if(!strncmp(p,"-func",5)) {option_index|=INDEX_FUNC; p=&p[5]; continue;} 703 | if(!strncmp(p,"-var" ,4)) {option_index|=INDEX_VAR ; p=&p[4]; continue;} 704 | if(!strncmp(p,"-type",5)) {option_index|=INDEX_TYPE; p=&p[5]; continue;} 705 | break; 706 | } 707 | continue; 708 | } 709 | 710 | if(!strcmp(args[i],"-raw")) 711 | {option_raw=1; continue;} 712 | 713 | if(!strcmp(args[i],"-latex209")) 714 | {option_latex=1; continue;} 715 | if(!strcmp(args[i],"-latex2e") || !strcmp(args[i],"-latex")) 716 | {option_latex=2; continue;} 717 | 718 | if(!strncmp(args[i],"-html20",7)) 719 | {option_html=1;if(!strcmp(args[i]+7,"-src"))option_html+=16;continue;} 720 | if(!strncmp(args[i],"-html32",7)) 721 | {option_html=2;if(!strcmp(args[i]+7,"-src"))option_html+=16;continue;} 722 | if(!strncmp(args[i],"-html",5)) 723 | {option_html=2;if(!strcmp(args[i]+5,"-src"))option_html+=16;continue;} 724 | 725 | if(!strcmp(args[i],"-rtf")) 726 | {option_rtf=1; continue;} 727 | 728 | if(!strcmp(args[i],"-sgml")) 729 | {option_sgml=1; continue;} 730 | 731 | if(!strcmp(args[i],"--")) 732 | {end_of_args=1; continue;} 733 | 734 | if(args[i][0]=='-') 735 | {fprintf(stderr,"cxref: Unknown option '%s'.\n",args[i]);return(1);} 736 | 737 | if(fromfile) 738 | {fprintf(stderr,"cxref: File names '%s' only allowed on command line.\n",args[i]);return(1);} 739 | 740 | if(option_files && (option_nfiles%8)==0) 741 | option_files=(char**)Realloc(option_files,(option_nfiles+8)*sizeof(char*)); 742 | option_files[option_nfiles++]=MallocString(args[i]); 743 | } 744 | 745 | return(0); 746 | } 747 | 748 | 749 | /*++++++++++++++++++++++++++++++++++++++ 750 | Canonicalise a file name by removing '/../', '/./' and '//' references. 751 | 752 | char *CanonicaliseName Returns the argument modified. 753 | 754 | char *name The original name 755 | ++++++++++++++++++++++++++++++++++++++*/ 756 | 757 | char *CanonicaliseName(char *name) 758 | { 759 | char *match; 760 | 761 | while((match=strstr(name,"/../"))) 762 | { 763 | char *prev=match; match+=4; 764 | while(prev>name && *--prev!='/'); 765 | if(prev!=name)prev++; 766 | while((*prev++=*match++)); 767 | } 768 | 769 | while((match=strstr(name,"/./")) || (match=strstr(name,"./"))==name) 770 | { 771 | char *prev=match; match+=(*match=='/')?3:2; 772 | while((*prev++=*match++)); 773 | } 774 | 775 | while((match=strstr(name,"//"))) 776 | { 777 | char *prev=match; match+=2; 778 | while((*prev++=*match++)); 779 | } 780 | 781 | match=&name[strlen(name)-2]; 782 | if(match>=name && !strcmp(match,"/.")) 783 | *match=0; 784 | 785 | match=&name[strlen(name)-3]; 786 | if(match>=name && !strcmp(match,"/..")) 787 | if(match==name) 788 | *match=0; 789 | else 790 | while(match>name && *--match!='/') 791 | *match=0; 792 | 793 | if(!*name) 794 | *name='.',*(name+1)=0; 795 | 796 | return(name); 797 | } 798 | 799 | 800 | /*++++++++++++++++++++++++++++++++++++++ 801 | Calls CPP for the file to get all of the needed information. 802 | 803 | int DocumentTheFile Returns 1 in case of error, else 0. 804 | 805 | char* name The name of the file to document. 806 | 807 | The CPP is started as a sub-process, (using popen to return a FILE* for lex to use). 808 | ++++++++++++++++++++++++++++++++++++++*/ 809 | 810 | static int DocumentTheFile(char* name) 811 | { 812 | struct stat stat_buf; 813 | int error1,error2; 814 | 815 | if(stat(name,&stat_buf)==-1) 816 | {fprintf(stderr,"cxref: Cannot access the file '%s'\n",name);return(1);} 817 | 818 | cpp_command[cpp_command_num ]=name; 819 | cpp_command[cpp_command_num+1]=NULL; 820 | 821 | yyin=popen_execvp(cpp_command); 822 | 823 | if(!yyin) 824 | {fprintf(stderr,"cxref: Failed to start the cpp command\n");exit(1);} 825 | 826 | yyrestart(yyin); 827 | 828 | #if YYDEBUG 829 | yydebug=(YYDEBUG==3); 830 | #endif 831 | 832 | error1=yyparse(); 833 | 834 | error2=pclose_execvp(yyin); 835 | 836 | if(error2) 837 | fprintf(stderr,"cxref: The preprocessor exited abnormally on '%s'\n",name); 838 | 839 | return(error1||error2); 840 | } 841 | 842 | 843 | /*+ The process id of the pre-processor. +*/ 844 | static pid_t popen_pid; 845 | 846 | /*++++++++++++++++++++++++++++++++++++++ 847 | A popen function that takes a list of arguments not a string. 848 | 849 | FILE* popen_execvp Returns a file descriptor. 850 | 851 | char** command The command arguments. 852 | ++++++++++++++++++++++++++++++++++++++*/ 853 | 854 | static FILE* popen_execvp(char** command) 855 | { 856 | int fdr[2]; 857 | 858 | if(pipe(fdr)==-1) 859 | {fprintf(stderr,"cxref: Can not pipe for the cpp command.\n");exit(1);} 860 | 861 | if((popen_pid=fork())==-1) 862 | {fprintf(stderr,"cxref: Can not fork for the cpp command.\n");exit(1);} 863 | 864 | if(popen_pid) /* The parent */ 865 | { 866 | close(fdr[1]); 867 | } 868 | else /* The child */ 869 | { 870 | close(1); 871 | dup(fdr[1]); 872 | close(fdr[1]); 873 | 874 | close(fdr[0]); 875 | 876 | execvp(command[0],command); 877 | fprintf(stderr,"cxref: Can not execvp for the cpp command.\n"); 878 | exit(1); 879 | } 880 | 881 | return(fdopen(fdr[0],"r")); 882 | } 883 | 884 | 885 | /*++++++++++++++++++++++++++++++++++++++ 886 | Close the file to the to the preprocessor 887 | 888 | int pclose_execvp Return the error status. 889 | 890 | FILE* f The file to close. 891 | ++++++++++++++++++++++++++++++++++++++*/ 892 | 893 | static int pclose_execvp(FILE* f) 894 | { 895 | int status,ret; 896 | 897 | waitpid(popen_pid,&status,0); 898 | fclose(f); 899 | 900 | if(WIFEXITED(status)) 901 | ret=WEXITSTATUS(status); 902 | else 903 | ret=-1; 904 | 905 | return(ret); 906 | }