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