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