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