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