    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  | }