1    | /***************************************
2    |   $Header: /home/amb/CVS/cxref/src/sgml.c,v 1.10 2004-06-26 18:50:36 amb Exp $
3    | 
4    |   C Cross Referencing & Documentation tool. Version 1.6.
5    | 
6    |   Writes the SGML output.
7    |   ******************/ /******************
8    |   Written by Andrew M. Bishop
9    | 
10   |   This file Copyright 1995,96,97,98,2001,04 Andrew M. Bishop
11   |   It may be distributed under the GNU Public License, version 2, or
12   |   any higher version.  See section COPYING of the GNU Public license
13   |   for conditions under which this file may be redistributed.
14   |   ***************************************/
15   | 
16   | #include <stdlib.h>
17   | #include <stdio.h>
18   | #include <string.h>
19   | #include <sys/types.h>
20   | #include <sys/stat.h>
21   | #include <unistd.h>
22   | 
23   | #include "version.h"
24   | #include "memory.h"
25   | #include "datatype.h"
26   | #include "cxref.h"
27   | 
28   | /*+ The name of the output tex file that includes each of the others. +*/
29   | #define SGML_FILE        ".sgml"
30   | #define SGML_FILE_BACKUP ".sgml~"
31   | 
32   | /*+ The name of the output tex file that contains the appendix. +*/
33   | #define SGML_APDX        ".apdx"
34   | 
35   | /*+ The comments are to be inserted verbatim. +*/
36   | extern int option_verbatim_comments;
37   | 
38   | /*+ The name of the directory for the output. +*/
39   | extern char* option_odir;
40   | 
41   | /*+ The base name of the file for the output. +*/
42   | extern char* option_name;
43   | 
44   | /*+ The information about the cxref run, +*/
45   | extern char *run_command,       /*+ the command line options. +*/
46   |             *run_cpp_command;   /*+ the cpp command and options. +*/
47   | 
48   | /*+ The directories to go back to get to the base output directory. +*/
49   | static char* goback=NULL;
50   | 
51   | /* Local functions */
52   | 
53   | static void WriteSGMLFilePart(File file);
54   | static void WriteSGMLInclude(Include inc);
55   | static void WriteSGMLSubInclude(Include inc,int depth);
56   | static void WriteSGMLDefine(Define def);
57   | static void WriteSGMLTypedef(Typedef type);
58   | static void WriteSGMLStructUnion(StructUnion su,int depth);
59   | static void WriteSGMLVariable(Variable var);
60   | static void WriteSGMLFunction(Function func);
61   | 
62   | static void WriteSGMLPreamble(FILE* f,char* title);
63   | static void WriteSGMLPostamble(FILE* f);
64   | 
65   | static char* sgml(char* c,int verbatim);
66   | 
67   | /*+ The output file for the SGML. +*/
68   | static FILE* of;
69   | 
70   | /*+ The name of the file. +*/
71   | static char *filename;
72   | 
73   | 
74   | /*++++++++++++++++++++++++++++++++++++++
75   |   Write an sgml file for a complete File structure and all components.
76   | 
77   |   File file The File structure to output.
78   |   ++++++++++++++++++++++++++++++++++++++*/
79   | 
80   | void WriteSGMLFile(File file)
81   | {
82   |  char* ofile;
83   |  int i;
84   | 
85   |  filename=file->name;
86   | 
87   |  /* Open the file */
88   | 
89   |  ofile=ConcatStrings(4,option_odir,"/",file->name,SGML_FILE);
90   | 
91   |  of=fopen(ofile,"w");
92   |  if(!of)
93   |    {
94   |     struct stat stat_buf;
95   |     int i,ofl=strlen(ofile);
96   | 
97   |     for(i=strlen(option_odir)+1;i<ofl;i++)
98   |        if(ofile[i]=='/')
99   |          {
100  |           ofile[i]=0;
101  |           if(stat(ofile,&stat_buf))
102  |              mkdir(ofile,S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
103  |           ofile[i]='/';
104  |          }
105  | 
106  |     of=fopen(ofile,"w");
107  |    }
108  | 
109  |  if(!of)
110  |    {fprintf(stderr,"cxref: Failed to open the SGML output file '%s'\n",ofile);exit(1);}
111  | 
112  |  for(goback="",i=strlen(file->name);i>0;i--)
113  |     if(file->name[i]=='/')
114  |        goback=ConcatStrings(2,goback,"../");
115  | 
116  |  /* Write out a header. */
117  | 
118  |  WriteSGMLPreamble(of,ConcatStrings(5,"Cross reference for ",file->name," of ",option_name,"."));
119  | 
120  |  /*+ The file structure is broken into its components and they are each written out. +*/
121  | 
122  |  WriteSGMLFilePart(file);
123  | 
124  |  if(file->includes)
125  |    {
126  |     Include inc =file->includes;
127  |     fprintf(of,"\n<sect1>Included Files\n\n<p>\n");
128  |     do{
129  |        WriteSGMLInclude(inc);
130  |       }
131  |     while((inc=inc->next));
132  |    }
133  | 
134  |  if(file->defines)
135  |    {
136  |     Define def =file->defines;
137  |     fprintf(of,"\n<sect1>Preprocessor definitions\n\n<p>\n");
138  |     do{
139  |        if(def!=file->defines)
140  |           fprintf(of,"<p>\n");
141  |        WriteSGMLDefine(def);
142  |       }
143  |     while((def=def->next));
144  |    }
145  | 
146  |  if(file->typedefs)
147  |    {
148  |     Typedef type=file->typedefs;
149  |     do{
150  |        WriteSGMLTypedef(type);
151  |       }
152  |     while((type=type->next));
153  |    }
154  | 
155  |  if(file->variables)
156  |    {
157  |     int any_to_mention=0;
158  |     Variable var=file->variables;
159  | 
160  |     do{
161  |        if(var->scope&(GLOBAL|LOCAL|EXTERNAL|EXTERN_F))
162  |           any_to_mention=1;
163  |       }
164  |     while((var=var->next));
165  | 
166  |     if(any_to_mention)
167  |       {
168  |        int first_ext=1,first_local=1;
169  |        Variable var=file->variables;
170  |        do{
171  |           if(var->scope&GLOBAL)
172  |              WriteSGMLVariable(var);
173  |          }
174  |        while((var=var->next));
175  |        var=file->variables;
176  |        do{
177  |           if(var->scope&(EXTERNAL|EXTERN_F) && !(var->scope&GLOBAL))
178  |             {
179  |              if(first_ext)
180  |                {fprintf(of,"\n<sect1>External Variables\n\n"); first_ext=0;}
181  |              fprintf(of,"<p>\n");
182  |              WriteSGMLVariable(var);
183  |             }
184  |          }
185  |        while((var=var->next));
186  |        var=file->variables;
187  |        do{
188  |           if(var->scope&LOCAL)
189  |             {
190  |              if(first_local)
191  |                {fprintf(of,"\n<sect1>Local Variables\n\n"); first_local=0;}
192  |              fprintf(of,"<p>\n");
193  |              WriteSGMLVariable(var);
194  |             }
195  |          }
196  |        while((var=var->next));
197  |       }
198  |    }
199  | 
200  |  if(file->functions)
201  |    {
202  |     Function func=file->functions;
203  |     do{
204  |        if(func->scope&(GLOBAL|EXTERNAL))
205  |           WriteSGMLFunction(func);
206  |       }
207  |     while((func=func->next));
208  |     func=file->functions;
209  |     do{
210  |        if(func->scope&LOCAL)
211  |           WriteSGMLFunction(func);
212  |       }
213  |     while((func=func->next));
214  |    }
215  | 
216  |  WriteSGMLPostamble(of);
217  | 
218  |  fclose(of);
219  | 
220  |  /* Clear the memory in sgml() */
221  | 
222  |  sgml(NULL,0); sgml(NULL,0); sgml(NULL,0); sgml(NULL,0);
223  | }
224  | 
225  | 
226  | /*++++++++++++++++++++++++++++++++++++++
227  |   Write a File structure out.
228  | 
229  |   File file The File to output.
230  |   ++++++++++++++++++++++++++++++++++++++*/
231  | 
232  | static void WriteSGMLFilePart(File file)
233  | {
234  |  int i;
235  | 
236  |  fprintf(of,"<sect>File %s\n",sgml(file->name,0));
237  | 
238  |  if(file->comment)
239  |    {
240  |     if(option_verbatim_comments)
241  |        fprintf(of,"<p><tscreen><verb>\n%s\n</verb></tscreen>\n\n",sgml(file->comment,1));
242  |     else
243  |       {
244  |        char *rcs1=strstr(file->comment,"$Header"),*rcs2=NULL;
245  |        if(rcs1)
246  |          {
247  |           rcs2=strstr(&rcs1[1],"$");
248  |           if(rcs2)
249  |             {
250  |              rcs2[0]=0;
251  |              fprintf(of,"<bf>RCS %s</bf>\n<p>\n",sgml(&rcs1[1],0));
252  |              rcs2[0]='$';
253  |             }
254  |          }
255  |        if(rcs2)
256  |           fprintf(of,"%s\n<p>\n",sgml(&rcs2[2],0));
257  |        else
258  |           fprintf(of,"%s\n<p>\n",sgml(file->comment,0));
259  |       }
260  |    }
261  | 
262  |  if(file->inc_in->n)
263  |    {
264  |     int i;
265  | 
266  |     fprintf(of,"<p>\n<descrip>\n<tag>Included in:</tag>\n<itemize>\n");
267  |     for(i=0;i<file->inc_in->n;i++)
268  |        fprintf(of,"<item>%s\n",sgml(file->inc_in->s[i],0));
269  |     fprintf(of,"</itemize>\n</descrip>\n");
270  |    }
271  | 
272  |  if(file->f_refs->n || file->v_refs->n)
273  |     fprintf(of,"<descrip>\n");
274  | 
275  |  if(file->f_refs->n)
276  |    {
277  |     int others=0;
278  |     fprintf(of,"<tag>References Functions:</tag>\n<itemize>\n");
279  |     for(i=0;i<file->f_refs->n;i++)
280  |        if(file->f_refs->s2[i])
281  |           fprintf(of,"<item>%s()  :  %s\n",sgml(file->f_refs->s1[i],0),sgml(file->f_refs->s2[i],0));
282  |        else
283  |           others++;
284  | 
285  |     if(others)
286  |       {
287  |        fprintf(of,"<item>");
288  |        for(i=0;i<file->f_refs->n;i++)
289  |           if(!file->f_refs->s2[i])
290  |              fprintf(of,--others?" %s(),":" %s()",sgml(file->f_refs->s1[i],0));
291  |        fprintf(of,"\n");
292  |       }
293  |     fprintf(of,"</itemize>\n");
294  |    }
295  | 
296  |  if(file->v_refs->n)
297  |    {
298  |     int others=0;
299  |     fprintf(of,"<tag>References Variables:</tag>\n<itemize>\n");
300  |     for(i=0;i<file->v_refs->n;i++)
301  |       {
302  |        if(file->v_refs->s2[i])
303  |           fprintf(of,"<item>%s  :  %s\n",sgml(file->v_refs->s1[i],0),sgml(file->v_refs->s2[i],0));
304  |        else
305  |           others++;
306  |       }
307  | 
308  |     if(others)
309  |       {
310  |        fprintf(of,"<item>");
311  |        for(i=0;i<file->v_refs->n;i++)
312  |           if(!file->v_refs->s2[i])
313  |              fprintf(of,--others?" %s,":" %s",sgml(file->v_refs->s1[i],0));
314  |        fprintf(of,"\n");
315  |       }
316  |     fprintf(of,"</itemize>\n");
317  |    }
318  | 
319  |  if(file->f_refs->n || file->v_refs->n)
320  |     fprintf(of,"</descrip>\n");
321  | }
322  | 
323  | 
324  | /*++++++++++++++++++++++++++++++++++++++
325  |   Write an Include structure out.
326  | 
327  |   Include inc The Include structure to output.
328  |   ++++++++++++++++++++++++++++++++++++++*/
329  | 
330  | static void WriteSGMLInclude(Include inc)
331  | {
332  |  if(inc->comment)
333  |     fprintf(of,"%s\n<p>\n",sgml(inc->comment,0));
334  | 
335  |  fprintf(of,"<itemize>\n");
336  | 
337  |  if(inc->scope==LOCAL)
338  |     fprintf(of,"<item><tt>#include &quot;%s&quot;</tt>\n",sgml(inc->name,0));
339  |  else
340  |     fprintf(of,"<item><tt>#include &lt;%s&gt;</tt>\n",sgml(inc->name,0));
341  | 
342  |  if(inc->includes)
343  |     WriteSGMLSubInclude(inc->includes,1);
344  | 
345  |  fprintf(of,"</itemize>\n");
346  | }
347  | 
348  | 
349  | /*++++++++++++++++++++++++++++++++++++++
350  |   Write an Sub Include structure out. (An include structure that is included from another file.)
351  | 
352  |   Include inc The Include structure to output.
353  | 
354  |   int depth The depth of the include hierarchy.
355  |   ++++++++++++++++++++++++++++++++++++++*/
356  | 
357  | static void WriteSGMLSubInclude(Include inc,int depth)
358  | {
359  |  fprintf(of,"<itemize>\n");
360  | 
361  |  while(inc)
362  |    {
363  |     if(inc->scope==LOCAL)
364  |        fprintf(of,"<item><tt>#include &quot;%s&quot;</tt>\n",sgml(inc->name,0));
365  |     else
366  |        fprintf(of,"<item><tt>#include &lt;%s&gt;</tt>\n",sgml(inc->name,0));
367  | 
368  |     if(inc->includes)
369  |        WriteSGMLSubInclude(inc->includes,depth+1);
370  | 
371  |     inc=inc->next;
372  |    }
373  | 
374  |  fprintf(of,"</itemize>\n");
375  | }
376  | 
377  | 
378  | /*++++++++++++++++++++++++++++++++++++++
379  |   Write a Define structure out.
380  | 
381  |   Define def The Define structure to output.
382  |   ++++++++++++++++++++++++++++++++++++++*/
383  | 
384  | static void WriteSGMLDefine(Define def)
385  | {
386  |  int i;
387  |  int pargs=0;
388  | 
389  |  if(def->comment)
390  |     fprintf(of,"%s\n<p>\n",sgml(def->comment,0));
391  | 
392  |  fprintf(of,"<tt>#define %s",sgml(def->name,0));
393  | 
394  |  if(def->value)
395  |     fprintf(of," %s",sgml(def->value,0));
396  | 
397  |  if(def->args->n)
398  |    {
399  |     fprintf(of,"( ");
400  |     for(i=0;i<def->args->n;i++)
401  |        fprintf(of,i?", %s":"%s",sgml(def->args->s1[i],0));
402  |     fprintf(of," )");
403  |    }
404  |  fprintf(of,"</tt><newline>\n");
405  | 
406  |  for(i=0;i<def->args->n;i++)
407  |     if(def->args->s2[i])
408  |        pargs=1;
409  | 
410  |  if(pargs)
411  |    {
412  |     fprintf(of,"<descrip>\n");
413  |     for(i=0;i<def->args->n;i++)
414  |        fprintf(of,"<tag><tt>%s</tt></tag>\n%s\n",sgml(def->args->s1[i],0),def->args->s2[i]?sgml(def->args->s2[i],0):"");
415  |     fprintf(of,"</descrip>\n");
416  |    }
417  | }
418  | 
419  | 
420  | /*++++++++++++++++++++++++++++++++++++++
421  |   Write a Typedef structure out.
422  | 
423  |   Typedef type The Typedef structure to output.
424  |   ++++++++++++++++++++++++++++++++++++++*/
425  | 
426  | static void WriteSGMLTypedef(Typedef type)
427  | {
428  |  fprintf(of,"\n<sect1>");
429  | 
430  |  if(type->type)
431  |     fprintf(of,"Typedef %s",sgml(type->name,0));
432  |  else
433  |     fprintf(of,"Type %s",sgml(type->name,0));
434  | 
435  |  fprintf(of,"\n\n<p>\n");
436  | 
437  |  if(type->comment)
438  |     fprintf(of,"%s\n<p>\n",sgml(type->comment,0));
439  | 
440  |  if(type->type)
441  |     fprintf(of,"<tt>typedef %s</tt><newline>\n",sgml(type->type,0));
442  | 
443  |  if(type->sutype)
444  |    {
445  |     fprintf(of,"<itemize>\n");
446  |     WriteSGMLStructUnion(type->sutype,0);
447  |     fprintf(of,"</itemize>\n");
448  |    }
449  |  else
450  |     if(type->typexref)
451  |       {
452  |        fprintf(of,"<descrip>\n<tag>See:</tag>\n<itemize>\n");
453  |        if(type->typexref->type)
454  |           fprintf(of,"<item>Typedef %s\n",sgml(type->typexref->name,0));
455  |        else if(!strncmp("enum",type->typexref->name,4))
456  |           fprintf(of,"<item>Type %s\n",sgml(type->typexref->name,0));
457  |        else if(!strncmp("union",type->typexref->name,5))
458  |           fprintf(of,"<item>Type %s\n",sgml(type->typexref->name,0));
459  |        else if(!strncmp("struct",type->typexref->name,6))
460  |           fprintf(of,"<item>Type %s\n",sgml(type->typexref->name,0));
461  |        fprintf(of,"</itemize>\n</descrip>\n");
462  |       }
463  | }
464  | 
465  | 
466  | /*++++++++++++++++++++++++++++++++++++++
467  |   Write a structure / union structure out.
468  | 
469  |   StructUnion su The structure / union to write.
470  | 
471  |   int depth The current depth within the structure.
472  |   ++++++++++++++++++++++++++++++++++++++*/
473  | 
474  | static void WriteSGMLStructUnion(StructUnion su, int depth)
475  | {
476  |  int i;
477  |  char* splitsu=NULL;
478  | 
479  |  splitsu=strstr(su->name,"{...}");
480  |  if(splitsu) splitsu[-1]=0;
481  | 
482  |  if(depth && su->comment && !su->comps)
483  |     fprintf(of,"<item><tt>%s;      </tt>%s<newline>\n",sgml(su->name,0),sgml(su->comment,0));
484  |  else if(!depth || su->comps)
485  |     fprintf(of,"<item><tt>%s</tt><newline>\n",sgml(su->name,0));
486  |  else
487  |     fprintf(of,"<item><tt>%s;</tt><newline>\n",sgml(su->name,0));
488  | 
489  |  if(!depth || su->comps)
490  |    {
491  |     fprintf(of,"<itemize>\n");
492  | 
493  |     fprintf(of,"<item><tt>{</tt><newline>\n");
494  | 
495  |     for(i=0;i<su->n_comp;i++)
496  |        WriteSGMLStructUnion(su->comps[i],depth+1);
497  | 
498  |     fprintf(of,"<item><tt>}</tt><newline>\n");
499  | 
500  |     fprintf(of,"</itemize>\n");
501  | 
502  |     if(splitsu)
503  |       {
504  |        if(depth && su->comment)
505  |           fprintf(of,"<item><tt>%s;      </tt>%s<newline>\n",splitsu[5]?sgml(&splitsu[6],0):"",sgml(su->comment,0));
506  |        else
507  |           fprintf(of,"<item><tt>%s;</tt><newline>\n",splitsu[5]?sgml(&splitsu[6],0):"");
508  |       }
509  |    }
510  | 
511  |  if(splitsu) splitsu[-1]=' ';
512  | }
513  | 
514  | 
515  | /*++++++++++++++++++++++++++++++++++++++
516  |   Write a Variable structure out.
517  | 
518  |   Variable var The Variable structure to output.
519  |   ++++++++++++++++++++++++++++++++++++++*/
520  | 
521  | static void WriteSGMLVariable(Variable var)
522  | {
523  |  int i;
524  | 
525  |  if(var->scope&GLOBAL)
526  |     fprintf(of,"\n<sect1>Global Variable %s\n\n<p>\n",sgml(var->name,0));
527  |  else
528  |     fprintf(of,"<bf>%s</bf><newline>\n",sgml(var->name,0));
529  | 
530  |  if(var->comment)
531  |     fprintf(of,"%s\n<p>\n",sgml(var->comment,0));
532  | 
533  |  fprintf(of,"<tt>");
534  | 
535  |  if(var->scope&LOCAL)
536  |     fprintf(of,"static ");
537  |  else
538  |     if(!(var->scope&GLOBAL) && var->scope&(EXTERNAL|EXTERN_F))
539  |        fprintf(of,"extern ");
540  | 
541  |  fprintf(of,"%s</tt><newline>\n",sgml(var->type,0));
542  | 
543  |  if(var->scope&(GLOBAL|LOCAL))
544  |    {
545  |     if(var->incfrom || var->visible->n || var->used->n)
546  |        fprintf(of,"<descrip>\n");
547  | 
548  |     if(var->incfrom)
549  |       {
550  |        fprintf(of,"<tag>Included from:</tag>\n<itemize>\n");
551  |        fprintf(of,"<item>%s\n",sgml(var->incfrom,0));
552  |        fprintf(of,"</itemize>\n");
553  |       }
554  | 
555  |     if(var->visible->n)
556  |       {
557  |        fprintf(of,"<tag>Visible in:</tag>\n<itemize>\n");
558  |        for(i=0;i<var->visible->n;i++)
559  |           if(var->visible->s1[i][0]=='$' && !var->visible->s1[i][1])
560  |              fprintf(of,"<item>%s\n",sgml(var->visible->s2[i],0));
561  |           else
562  |              fprintf(of,"<item>%s()  :  %s\n",sgml(var->visible->s1[i],0),sgml(var->visible->s2[i],0));
563  |        fprintf(of,"</itemize>\n");
564  |       }
565  | 
566  |     if(var->used->n)
567  |       {
568  |        fprintf(of,"<tag>Used in:</tag>\n<itemize>\n");
569  |        for(i=0;i<var->used->n;i++)
570  |          {
571  |           if(var->used->s1[i][0]=='$' && !var->used->s1[i][1])
572  |              fprintf(of,"<item>%s\n",sgml(var->used->s2[i],0));
573  |           else
574  |             {
575  |              if(var->scope&LOCAL)
576  |                 fprintf(of,"<item>%s()\n",sgml(var->used->s1[i],0));
577  |              else
578  |                 fprintf(of,"<item>%s()  :  %s\n",sgml(var->used->s1[i],0),sgml(var->used->s2[i],0));
579  |             }
580  |          }
581  |        fprintf(of,"</itemize>\n");
582  |       }
583  | 
584  |     if(var->incfrom || var->visible->n || var->used->n)
585  |        fprintf(of,"</descrip>\n");
586  |    }
587  |  else
588  |     if(var->scope&(EXTERNAL|EXTERN_F) && var->defined)
589  |       {
590  |        fprintf(of,"<descrip>\n<tag>Defined in:</tag>\n<itemize>\n");
591  |        fprintf(of,"<item>%s",sgml(var->name,0));
592  |        fprintf(of,"</itemize>\n</descrip>\n");
593  |       }
594  | }
595  | 
596  | 
597  | /*++++++++++++++++++++++++++++++++++++++
598  |   Write a Function structure out.
599  | 
600  |   Function func The Function structure to output.
601  |   ++++++++++++++++++++++++++++++++++++++*/
602  | 
603  | static void WriteSGMLFunction(Function func)
604  | {
605  |  int i,pret,pargs;
606  |  char* comment2=NULL,*type;
607  | 
608  |  if(func->scope&(GLOBAL|EXTERNAL))
609  |     fprintf(of,"\n<sect1>Global Function %s()\n\n<p>",sgml(func->name,0));
610  |  else
611  |     fprintf(of,"\n<sect1>Local Function %s()\n\n<p>",sgml(func->name,0));
612  | 
613  |  if(func->comment)
614  |    {
615  |     if(option_verbatim_comments)
616  |        fprintf(of,"<tscreen><verb>\n%s\n</verb></tscreen>\n\n",sgml(func->comment,1));
617  |     else
618  |       {
619  |        comment2=strstr(func->comment,"\n\n");
620  |        if(comment2)
621  |           comment2[0]=0;
622  |        fprintf(of,"%s\n<p>\n",sgml(func->comment,0));
623  |       }
624  |    }
625  | 
626  |  fprintf(of,"<tt>");
627  | 
628  |  if(func->scope&LOCAL)
629  |     fprintf(of,"static ");
630  |  if(func->scope&INLINED)
631  |    fprintf(of,"inline ");
632  | 
633  |  if((type=strstr(func->type,"()")))
634  |     type[0]=0;
635  |  fprintf(of,"%s ( ",sgml(func->type,0));
636  | 
637  |  for(i=0;i<func->args->n;i++)
638  |     fprintf(of,i?", %s":"%s",sgml(func->args->s1[i],0));
639  | 
640  |  if(type)
641  |    {fprintf(of," %s</tt><newline>\n",sgml(&type[1],0));type[0]='(';}
642  |  else
643  |     fprintf(of," )</tt><newline>\n");
644  | 
645  |  pret =strncmp("void ",func->type,5) && func->cret;
646  |  for(pargs=0,i=0;i<func->args->n;i++)
647  |     pargs = pargs || ( strcmp("void",func->args->s1[i]) && func->args->s2[i] );
648  | 
649  |  if(pret || pargs)
650  |    {
651  |     fprintf(of,"<descrip>\n");
652  |     if(pret)
653  |        fprintf(of,"<tag><tt>%s</tt></tag>\n%s\n",sgml(func->type,0),func->cret?sgml(func->cret,0):"&nbsp;");
654  |     if(pargs)
655  |        for(i=0;i<func->args->n;i++)
656  |           fprintf(of,"<tag><tt>%s</tt></tag>\n%s\n",sgml(func->args->s1[i],0),func->args->s2[i]?sgml(func->args->s2[i],0):"&nbsp;");
657  |     fprintf(of,"</descrip>\n");
658  |    }
659  | 
660  |  if(comment2)
661  |    {
662  |     fprintf(of,"%s\n<p>\n",sgml(&comment2[2],0));
663  |     comment2[0]='\n';
664  |    }
665  | 
666  |  if(func->protofile || func->incfrom || func->calls->n || func->called->n || func->used->n || func->f_refs->n || func->v_refs->n)
667  |     fprintf(of,"<descrip>\n");
668  | 
669  |  if(func->protofile)
670  |    {
671  |     fprintf(of,"<tag>Prototyped in:</tag>\n<itemize>\n");
672  |     fprintf(of,"<item>%s\n",sgml(func->protofile,0));
673  |     fprintf(of,"</itemize>\n");
674  |    }
675  | 
676  |  if(func->incfrom)
677  |    {
678  |     fprintf(of,"<tag>Included from:</tag>\n<itemize>\n");
679  |     fprintf(of,"<item>%s\n",sgml(func->incfrom,0));
680  |     fprintf(of,"</itemize>\n");
681  |    }
682  | 
683  |  if(func->calls->n)
684  |    {
685  |     int others=0;
686  |     fprintf(of,"<tag>Calls:</tag>\n<itemize>\n");
687  |     for(i=0;i<func->calls->n;i++)
688  |       {
689  |        if(func->calls->s2[i])
690  |           fprintf(of,"<item>%s()  :  %s\n",sgml(func->calls->s1[i],0),sgml(func->calls->s2[i],0));
691  |        else
692  |           others++;
693  |       }
694  | 
695  |     if(others)
696  |       {
697  |        fprintf(of,"<item>");
698  |        for(i=0;i<func->calls->n;i++)
699  |           if(!func->calls->s2[i])
700  |              fprintf(of,--others?"%s(), ":"%s()",sgml(func->calls->s1[i],0));
701  |        fprintf(of,"\n");
702  |       }
703  |     fprintf(of,"</itemize>\n");
704  |    }
705  | 
706  |  if(func->called->n)
707  |    {
708  |     fprintf(of,"<tag>Called by:</tag>\n<itemize>\n");
709  |     for(i=0;i<func->called->n;i++)
710  |        fprintf(of,"<item>%s()  :  %s\n",sgml(func->called->s1[i],0),sgml(func->called->s2[i],0));
711  |     fprintf(of,"</itemize>\n");
712  |    }
713  | 
714  |  if(func->used->n)
715  |    {
716  |     fprintf(of,"<tag>Used in:</tag>\n<itemize>\n");
717  |     for(i=0;i<func->used->n;i++)
718  |       {
719  |        if(func->used->s1[i][0]=='$' && !func->used->s1[i][1])
720  |           fprintf(of,"<item>%s\n",sgml(func->used->s2[i],0));
721  |        else
722  |           fprintf(of,"<item>%s()  :  %s\n",sgml(func->used->s1[i],0),sgml(func->used->s2[i],0));
723  |       }
724  |     fprintf(of,"</itemize>\n");
725  |    }
726  | 
727  |  if(func->f_refs->n)
728  |    {
729  |     int others=0;
730  |     fprintf(of,"<tag>References Functions:</tag>\n<itemize>\n");
731  |     for(i=0;i<func->f_refs->n;i++)
732  |       {
733  |        if(func->f_refs->s2[i])
734  |           fprintf(of,"<item>%s()  :  %s\n",sgml(func->f_refs->s1[i],0),sgml(func->f_refs->s2[i],0));
735  |        else
736  |           others++;
737  |       }
738  | 
739  |     if(others)
740  |       {
741  |        fprintf(of,"<item>");
742  |        for(i=0;i<func->f_refs->n;i++)
743  |           if(!func->f_refs->s2[i])
744  |              fprintf(of,--others?"%s(), ":"%s()",sgml(func->f_refs->s1[i],0));
745  |        fprintf(of,"\n");
746  |       }
747  |     fprintf(of,"</itemize>\n");
748  |    }
749  | 
750  |  if(func->v_refs->n)
751  |    {
752  |     int others=0;
753  |     fprintf(of,"<tag>References Variables:</tag>\n<itemize>\n");
754  |     for(i=0;i<func->v_refs->n;i++)
755  |       {
756  |        if(func->v_refs->s2[i])
757  |           fprintf(of,"<item>%s  :  %s\n",sgml(func->v_refs->s1[i],0),sgml(func->v_refs->s2[i],0));
758  |        else
759  |           others++;
760  |       }
761  | 
762  |     if(others)
763  |       {
764  |        fprintf(of,"<item>");
765  |        for(i=0;i<func->v_refs->n;i++)
766  |           if(!func->v_refs->s2[i])
767  |              fprintf(of,--others?"%s, ":"%s",sgml(func->v_refs->s1[i],0));
768  |        fprintf(of,"\n");
769  |       }
770  |     fprintf(of,"</itemize>\n");
771  |    }
772  | 
773  |  if(func->protofile || func->incfrom || func->calls->n || func->called->n || func->used->n || func->f_refs->n || func->v_refs->n)
774  |     fprintf(of,"</descrip>\n");
775  | }
776  | 
777  | 
778  | /*++++++++++++++++++++++++++++++++++++++
779  |   Write out a standard pre-amble.
780  | 
781  |   FILE* f The file to write the pre amble to.
782  | 
783  |   char* title The title of the file.
784  |   ++++++++++++++++++++++++++++++++++++++*/
785  | 
786  | static void WriteSGMLPreamble(FILE* f,char* title)
787  | {
788  |  fputs("<!DOCTYPE LINUXDOC SYSTEM>\n",f);
789  |  fputs("\n",f);
790  |  fputs("<!-- This SGML file generated by cxref (version " CXREF_VERSION "). -->\n",f);
791  |  fputs("<!-- cxref program " CXREF_COPYRIGHT ". -->\n",f);
792  |  fputs("\n",f);
793  |  fputs("<!--\n",f);
794  |  if(filename)
795  |     fprintf(f,"Cxref: %s %s\n",run_command,filename);
796  |  else
797  |     fprintf(f,"Cxref: %s\n",run_command);
798  |  fprintf(f,"CPP  : %s\n",run_cpp_command);
799  |  fputs("-->\n",f);
800  |  fputs("\n",f);
801  |  fputs("<article>\n",f);
802  |  fputs("\n",f);
803  |  fputs("<title>",f);
804  |  fputs(title,f);
805  |  fputs("\n",f);
806  |  fputs("<author>cxref\n",f);
807  |  fputs("\n",f);
808  | }
809  | 
810  | 
811  | /*++++++++++++++++++++++++++++++++++++++
812  |   Write out a standard post-amble. This includes the end of document marker.
813  | 
814  |   FILE* f The file to write the post amble to.
815  |   ++++++++++++++++++++++++++++++++++++++*/
816  | 
817  | static void WriteSGMLPostamble(FILE* f)
818  | {
819  |  fputs("\n",f);
820  |  fputs("</article>\n",f);
821  | }
822  | 
823  | 
824  | /*++++++++++++++++++++++++++++++++++++++
825  |   Write out the appendix information.
826  | 
827  |   StringList files The list of files to write.
828  | 
829  |   StringList2 funcs The list of functions to write.
830  | 
831  |   StringList2 vars The list of variables to write.
832  | 
833  |   StringList2 types The list of types to write.
834  |   ++++++++++++++++++++++++++++++++++++++*/
835  | 
836  | void WriteSGMLAppendix(StringList files,StringList2 funcs,StringList2 vars,StringList2 types)
837  | {
838  |  char* ofile;
839  |  int i;
840  | 
841  |  filename=NULL;
842  | 
843  |  /* Open the file */
844  | 
845  |  ofile=ConcatStrings(5,option_odir,"/",option_name,SGML_APDX,SGML_FILE);
846  | 
847  |  of=fopen(ofile,"w");
848  | 
849  |  if(!of)
850  |    {fprintf(stderr,"cxref: Failed to open the SGML appendix file '%s'\n",ofile);exit(1);}
851  | 
852  |  /* Write the file structure out */
853  | 
854  |  WriteSGMLPreamble(of,ConcatStrings(3,"Cross reference index of ",option_name,"."));
855  | 
856  |  fprintf(of,"<sect>Cross References\n");
857  | 
858  |  /* Write out the appendix of files. */
859  | 
860  |  if(files->n)
861  |    {
862  |     fprintf(of,"\n<sect1>Files\n\n<p>\n");
863  |     fprintf(of,"<itemize>\n");
864  |     for(i=0;i<files->n;i++)
865  |        fprintf(of,"<item>%s>\n",sgml(files->s[i],0));
866  |     fprintf(of,"</itemize>\n");
867  |    }
868  | 
869  |  /* Write out the appendix of functions. */
870  | 
871  |  if(funcs->n)
872  |    {
873  |     fprintf(of,"\n<sect1>Global Functions\n\n<p>\n");
874  |     fprintf(of,"<itemize>\n");
875  |     for(i=0;i<funcs->n;i++)
876  |        fprintf(of,"<item>%s()  :  %s\n",sgml(funcs->s1[i],0),sgml(funcs->s2[i],0));
877  |     fprintf(of,"</itemize>\n");
878  |    }
879  | 
880  |  /* Write out the appendix of variables. */
881  | 
882  |  if(vars->n)
883  |    {
884  |     fprintf(of,"\n<sect1>Global Variables\n\n<p>\n");
885  |     fprintf(of,"<itemize>\n");
886  |     for(i=0;i<vars->n;i++)
887  |        fprintf(of,"<item>%s  :  %s\n",sgml(vars->s1[i],0),sgml(vars->s2[i],0));
888  |     fprintf(of,"</itemize>\n");
889  |    }
890  | 
891  |  /* Write out the appendix of types. */
892  | 
893  |  if(types->n)
894  |    {
895  |     fprintf(of,"\n<sect1>Defined Types\n\n<p>\n");
896  |     fprintf(of,"<itemize>\n");
897  |     for(i=0;i<types->n;i++)
898  |        if(!strncmp("enum",types->s1[i],4))
899  |           fprintf(of,"<item>%s  :  %s\n",sgml(types->s1[i],0),sgml(types->s2[i],0));
900  |        else if(!strncmp("union",types->s1[i],5))
901  |           fprintf(of,"<item>%s  :  %s\n",sgml(types->s1[i],0),sgml(types->s2[i],0));
902  |        else if(!strncmp("struct",types->s1[i],6))
903  |           fprintf(of,"<item>%s  :  %s\n",sgml(types->s1[i],0),sgml(types->s2[i],0));
904  |        else
905  |           fprintf(of,"<item>%s  :  %s\n",sgml(types->s1[i],0),sgml(types->s2[i],0));
906  |     fprintf(of,"</itemize>\n");
907  |    }
908  | 
909  |  WriteSGMLPostamble(of);
910  | 
911  |  fclose(of);
912  | 
913  |  /* Clear the memory in sgml(,0) */
914  | 
915  |  sgml(NULL,0); sgml(NULL,0); sgml(NULL,0); sgml(NULL,0);
916  | }
917  | 
918  | 
919  | /*++++++++++++++++++++++++++++++++++++++
920  |   Delete the SGML file and main file reference that belong to the named file.
921  | 
922  |   char *name The name of the file to delete.
923  |   ++++++++++++++++++++++++++++++++++++++*/
924  | 
925  | void WriteSGMLFileDelete(char *name)
926  | {
927  |  char *ofile;
928  | 
929  |  ofile=ConcatStrings(4,option_odir,"/",name,SGML_FILE);
930  |  unlink(ofile);
931  | }
932  | 
933  | 
934  | /*++++++++++++++++++++++++++++++++++++++
935  |   Make the input string safe to output as SGML ( not <,  >,  &,  ",  $,  #,  % or ~ ).
936  | 
937  |   char* sgml Returns a safe SGML string.
938  | 
939  |   char* c A non-safe SGML string.
940  | 
941  |   int verbatim Set to true inside a verbatim environment.
942  | 
943  |   The function can only be called four times in each fprintf() since it returns one of only four static strings.
944  |   ++++++++++++++++++++++++++++++++++++++*/
945  | 
946  | static char* sgml(char* c,int verbatim)
947  | {
948  |  static char safe[4][256],*malloced[4]={NULL,NULL,NULL,NULL};
949  |  static int which=0;
950  |  int copy=0,skip=0;
951  |  int i=0,j=0,delta=10,len=256-delta;
952  |  char* ret;
953  | 
954  |  which=(which+1)%4;
955  |  ret=safe[which];
956  | 
957  |  safe[which][0]=0;
958  | 
959  |  if(malloced[which])
960  |    {Free(malloced[which]);malloced[which]=NULL;}
961  | 
962  |  if(c)
963  |    {
964  |     i=CopyOrSkip(c,"sgml",&copy,&skip);
965  | 
966  |     while(1)
967  |       {
968  |        for(;j<len && c[i];i++)
969  |          {
970  |           if(copy)
971  |             {ret[j++]=c[i]; if(c[i]=='\n') copy=0;}
972  |           else if(skip)
973  |             {               if(c[i]=='\n') skip=0;}
974  |           else if(verbatim)
975  |              switch(c[i])
976  |                {
977  |                case '&':
978  |                 strcpy(&ret[j],"&ero;");j+=5;
979  |                 break;
980  |                case '<':
981  |                 if(c[i+1]=='/')
982  |                   {strcpy(&ret[j],"&etago;");j+=7; break;}
983  |                default:
984  |                 ret[j++]=c[i];
985  |                }
986  |           else
987  |              switch(c[i])
988  |                {
989  |                case '<':
990  |                 if(c[i+1]=='/')
991  |                   {strcpy(&ret[j],"&etago;");j+=7;}
992  |                 else
993  |                   {strcpy(&ret[j],"&lt;");j+=4;}
994  |                 break;
995  |                case '>':
996  |                 strcpy(&ret[j],"&gt;");j+=4;
997  |                 break;
998  |                case '"':
999  |                 strcpy(&ret[j],"&quot;");j+=6;
1000 |                 break;
1001 |                case '&':
1002 |                 strcpy(&ret[j],"&amp;");j+=5;
1003 |                 break;
1004 |                case '$':
1005 |                 strcpy(&ret[j],"&dollar;");j+=8;
1006 |                 break;
1007 |                case '#':
1008 |                 strcpy(&ret[j],"&num;");j+=5;
1009 |                 break;
1010 |                case '%':
1011 |                 strcpy(&ret[j],"&percnt;");j+=8;
1012 |                 break;
1013 |                case '~':
1014 |                 strcpy(&ret[j],"&tilde;");j+=7;
1015 |                 break;
1016 |                case '\n':
1017 |                 if(j && ret[j-1]=='\n')
1018 |                   {
1019 |                    strcpy(&ret[j],"<newline>");j+=9;
1020 |                   }
1021 |                 ret[j++]=c[i];
1022 |                 break;
1023 |                default:
1024 |                 ret[j++]=c[i];
1025 |                }
1026 |           if(c[i]=='\n')
1027 |              i+=CopyOrSkip(c+i,"sgml",&copy,&skip);
1028 |          }
1029 | 
1030 |        if(c[i])                 /* Not finished */
1031 |          {
1032 |           if(malloced[which])
1033 |              malloced[which]=Realloc(malloced[which],len+delta+256);
1034 |           else
1035 |             {malloced[which]=Malloc(len+delta+256); strncpy(malloced[which],ret,(unsigned)j);}
1036 |           ret=malloced[which];
1037 |           len+=256;
1038 |          }
1039 |        else
1040 |          {ret[j]=0; break;}
1041 |       }
1042 |    }
1043 | 
1044 |  return(ret);
1045 | }