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