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