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