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