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