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