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