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