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 | }