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