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