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