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