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