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