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