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