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  | }