1    | /***************************************
2    |   $Header: /home/amb/cxref/RCS/latex.c 1.30 1998/12/22 14:25:50 amb Exp $
3    | 
4    |   C Cross Referencing & Documentation tool. Version 1.5.
5    | 
6    |   Writes the Latex 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   | #ifndef min
24   | #define min(x,y) ( (x) < (y) ? (x) : (y) )
25   | #endif
26   | 
27   | #include "memory.h"
28   | #include "datatype.h"
29   | #include "cxref.h"
30   | 
31   | /*+ The name of the output tex file that includes each of the others. +*/
32   | #define LATEX_FILE        ".tex"
33   | #define LATEX_FILE_BACKUP ".tex~"
34   | 
35   | /*+ The name of the output tex file that contains the appendix. +*/
36   | #define LATEX_APDX        ".apdx"
37   | 
38   | /*+ The comments are to be inserted verbatim. +*/
39   | extern int option_verbatim_comments;
40   | 
41   | /*+ The type of LaTeX output to produce. +*/
42   | extern int option_latex;
43   | 
44   | /*+ The name of the directory for the output. +*/
45   | extern char* option_odir;
46   | 
47   | /*+ The base name of the file for the output. +*/
48   | extern char* option_name;
49   | 
50   | extern char *latex_fonts_style,*latex_page_style,*latex_cxref_style;
51   | 
52   | static void WriteLatexFilePart(File file);
53   | static void WriteLatexInclude(Include inc);
54   | static void WriteLatexSubInclude(Include inc,int depth);
55   | static void WriteLatexDefine(Define def);
56   | static void WriteLatexTypedef(Typedef type,char* filename);
57   | static void WriteLatexStructUnion(StructUnion su,int depth);
58   | static void WriteLatexVariable(Variable var,char* filename);
59   | static void WriteLatexFunction(Function func,char* filename);
60   | 
61   | static void WriteLatexDocument(char* name,int appendix);
62   | static void WriteLatexTemplate(char* name);
63   | 
64   | static char* latex(char* c);
65   | 
66   | /*+ The output file for the latex. +*/
67   | static FILE* of;
68   | 
69   | /*+ Counts the lines in a table to insert breaks. +*/
70   | static int countlines=0;
71   | 
72   | 
73   | /*++++++++++++++++++++++++++++++++++++++
74   |   Write a Latex file for a complete File structure and all components.
75   | 
76   |   File file The File structure to output.
77   |   ++++++++++++++++++++++++++++++++++++++*/
78   | 
79   | void WriteLatexFile(File file)
80   | {
81   |  char* ofile;
82   | 
83   |  /* Write the including file. */
84   | 
85   |  WriteLatexDocument(file->name,0);
86   | 
87   |  /* Open the file */
88   | 
89   |  ofile=ConcatStrings(4,option_odir,"/",file->name,LATEX_FILE);
90   | 
91   |  of=fopen(ofile,"w");
92   |  if(!of)
93   |    {
94   |     struct stat stat_buf;
95   |     int i,ofl=strlen(ofile);
96   | 
97   |     for(i=strlen(option_odir)+1;i<ofl;i++)
98   |        if(ofile[i]=='/')
99   |          {
100  |           ofile[i]=0;
101  |           if(stat(ofile,&stat_buf))
102  |              mkdir(ofile,S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
103  |           ofile[i]='/';
104  |          }
105  | 
106  |     of=fopen(ofile,"w");
107  |    }
108  | 
109  |  if(!of)
110  |    {fprintf(stderr,"cxref: Failed to open the LaTeX output file '%s'\n",ofile);exit(1);}
111  | 
112  |  /* Write out a header. */
113  | 
114  |  fputs("% This LaTeX file generated by cxref\n",of);
115  |  fputs("% cxref program (c) Andrew M. Bishop 1995,96,97.\n",of);
116  |  fputs("\n",of);
117  | 
118  |  /*+ The file structure is broken into its components and they are each written out. +*/
119  | 
120  |  WriteLatexFilePart(file);
121  | 
122  |  if(file->includes)
123  |    {
124  |     Include inc =file->includes;
125  |     fprintf(of,"\n\\subsection*{Included Files}\n\n");
126  |     do{
127  |        if(inc!=file->includes)
128  |           fprintf(of,"\\medskip\n");
129  |        WriteLatexInclude(inc);
130  |       }
131  |     while((inc=inc->next));
132  |    }
133  | 
134  |  if(file->defines)
135  |    {
136  |     Define def =file->defines;
137  |     fprintf(of,"\n\\subsection*{Preprocessor definitions}\n\n");
138  |     do{
139  |        if(def!=file->defines)
140  |           fprintf(of,"\\medskip\n");
141  |        WriteLatexDefine(def);
142  |       }
143  |     while((def=def->next));
144  |    }
145  | 
146  |  if(file->typedefs)
147  |    {
148  |     Typedef type=file->typedefs;
149  |     fprintf(of,"\n\\subsection{Type definitions}\n\n");
150  |     do{
151  |        WriteLatexTypedef(type,file->name);
152  |       }
153  |     while((type=type->next));
154  |    }
155  | 
156  |  if(file->variables)
157  |    {
158  |     int any_to_mention=0;
159  |     Variable var=file->variables;
160  | 
161  |     do{
162  |        if(var->scope&(GLOBAL|LOCAL|EXTERNAL|EXTERN_F))
163  |           any_to_mention=1;
164  |       }
165  |     while((var=var->next));
166  | 
167  |     if(any_to_mention)
168  |       {
169  |        int first_ext=1,first_local=1;
170  |        Variable var=file->variables;
171  |        fprintf(of,"\n\\subsection{Variables}\n\n");
172  |        do{
173  |           if(var->scope&GLOBAL)
174  |              WriteLatexVariable(var,file->name);
175  |          }
176  |        while((var=var->next));
177  |        var=file->variables;
178  |        do{
179  |           if(var->scope&(EXTERNAL|EXTERN_F) && !(var->scope&GLOBAL))
180  |             {
181  |              if(first_ext)
182  |                {fprintf(of,"\n\\subsubsection{External Variables}\n\n"); first_ext=0;}
183  |              else
184  |                 fprintf(of,"\\medskip\n");
185  |              WriteLatexVariable(var,file->name);
186  |             }
187  |          }
188  |        while((var=var->next));
189  |        var=file->variables;
190  |        do{
191  |           if(var->scope&LOCAL)
192  |             {
193  |              if(first_local)
194  |                {fprintf(of,"\n\\subsubsection{Local Variables}\n\n"); first_local=0;}
195  |              else
196  |                 fprintf(of,"\\medskip\n");
197  |              WriteLatexVariable(var,file->name);
198  |             }
199  |          }
200  |        while((var=var->next));
201  |       }
202  |    }
203  | 
204  |  if(file->functions)
205  |    {
206  |     Function func=file->functions;
207  |     fprintf(of,"\n\\subsection{Functions}\n\n");
208  |     do{
209  |        if(func->scope&(GLOBAL|EXTERNAL))
210  |           WriteLatexFunction(func,file->name);
211  |       }
212  |     while((func=func->next));
213  |     func=file->functions;
214  |     do{
215  |        if(func->scope&LOCAL)
216  |           WriteLatexFunction(func,file->name);
217  |       }
218  |     while((func=func->next));
219  |    }
220  | 
221  |  fclose(of);
222  | 
223  |  /* Clear the memory in latex() */
224  | 
225  |  latex(NULL); latex(NULL); latex(NULL); latex(NULL);
226  | }
227  | 
228  | 
229  | /*++++++++++++++++++++++++++++++++++++++
230  |   Write a File structure out.
231  | 
232  |   File file The File to output.
233  |   ++++++++++++++++++++++++++++++++++++++*/
234  | 
235  | static void WriteLatexFilePart(File file)
236  | {
237  |  int i;
238  | 
239  |  fprintf(of,"\\markboth{File %s}{File %s}\n",latex(file->name),latex(file->name));
240  |  fprintf(of,"\\section{File %s}\n",latex(file->name));
241  |  fprintf(of,"\\label{file_%s}\n\n",file->name);
242  | 
243  |  if(file->comment)
244  |     if(option_verbatim_comments)
245  |        fprintf(of,"\\begin{verbatim}\n%s\n\\end{verbatim}\n\n",latex(file->comment));
246  |     else
247  |       {
248  |        char *rcs1=strstr(file->comment,"$Header"),*rcs2=NULL;
249  |        if(rcs1)
250  |          {
251  |           rcs2=strstr(&rcs1[1],"$");
252  |           if(rcs2)
253  |             {
254  |              rcs2[0]=0;
255  |              fprintf(of,"{\\bf RCS %s}\n\n",latex(&rcs1[1]));
256  |              fprintf(of,"\\smallskip\n");
257  |              rcs2[0]='$';
258  |             }
259  |          }
260  |        if(rcs2)
261  |           fprintf(of,"%s\n\n",latex(&rcs2[2]));
262  |        else
263  |           fprintf(of,"%s\n\n",latex(file->comment));
264  |       }
265  | 
266  |  if(file->inc_in->n)
267  |    {
268  |     int i;
269  | 
270  |     if(file->comment)
271  |        fprintf(of,"\\medskip\n");
272  |     fprintf(of,"\\begin{cxreftabii}\nIncluded in:");
273  |     for(i=0;i<file->inc_in->n;i++)
274  |       {/* Allow a break in every 8 (or so) items to allow the table to break over the page. */
275  |        if(min(i,file->inc_in->n-i)%8 == 4)
276  |           fprintf(of,"\\cxreftabbreak{cxreftabii}\n");
277  |        fprintf(of,"\\ & %s & \\cxreffile{%s}\\\\\n",latex(file->inc_in->s[i]),file->inc_in->s[i]);
278  |       }
279  |     fprintf(of,"\\end{cxreftabii}\n\n");
280  |    }
281  | 
282  |  if(file->f_refs->n || file->v_refs->n)
283  |    {
284  |     int tabcount=0;
285  |     fprintf(of,"\\smallskip\n");
286  |     fprintf(of,"\\begin{cxreftabiii}\n");
287  | 
288  |     if(file->f_refs->n)
289  |       {
290  |        int others=0;
291  | 
292  |        fprintf(of,"Refs Func:");
293  | 
294  |        for(i=0;i<file->f_refs->n;i++)
295  |           if(file->f_refs->s2[i])
296  |             {
297  |              fprintf(of,"\\ & %s() & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(file->f_refs->s1[i]),latex(file->f_refs->s2[i]),file->f_refs->s1[i],file->f_refs->s2[i]);
298  |              if(++tabcount%8 == 4)
299  |                 fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
300  |             }
301  |           else
302  |              others++;
303  | 
304  |        if(others)
305  |          {
306  |           fprintf(of,"\\ & \\cxreftabiiispan{");
307  |           for(i=0;i<file->f_refs->n;i++)
308  |              if(!file->f_refs->s2[i])
309  |                 fprintf(of,--others?"%s(), ":"%s()",latex(file->f_refs->s1[i]));
310  |           fprintf(of,"} &\\\\\n");
311  |          }
312  |       }
313  | 
314  |     if(file->v_refs->n)
315  |       {
316  |        int others=0;
317  | 
318  |        fprintf(of,"Refs Var:");
319  | 
320  |        for(i=0;i<file->v_refs->n;i++)
321  |           if(file->v_refs->s2[i])
322  |             {
323  |              fprintf(of,"\\ & %s & %s & \\cxrefvar{%s}{%s}\\\\\n",latex(file->v_refs->s1[i]),latex(file->v_refs->s2[i]),file->v_refs->s1[i],file->v_refs->s2[i]);
324  |              if(++tabcount%8 == 4)
325  |                 fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
326  |             }
327  |           else
328  |              others++;
329  | 
330  |        if(others)
331  |          {
332  |           fprintf(of,"\\ & \\cxreftabiiispan{");
333  |           for(i=0;i<file->v_refs->n;i++)
334  |              if(!file->v_refs->s2[i])
335  |                 fprintf(of,--others?" %s,":" %s",latex(file->v_refs->s1[i]));
336  |           fprintf(of,"} &\\\\\n");
337  |          }
338  |       }
339  | 
340  |     fprintf(of,"\\end{cxreftabiii}\n\n");
341  |    }
342  | }
343  | 
344  | 
345  | /*++++++++++++++++++++++++++++++++++++++
346  |   Write an Include structure out.
347  | 
348  |   Include inc The Include structure to output.
349  |   ++++++++++++++++++++++++++++++++++++++*/
350  | 
351  | static void WriteLatexInclude(Include inc)
352  | {
353  |  if(inc->comment)
354  |     fprintf(of,"%s\n\n\\smallskip\n",latex(inc->comment));
355  | 
356  |  fprintf(of,"\\begin{cxreftabi}\n"); countlines=1;
357  | 
358  |  if(inc->scope==LOCAL)
359  |     fprintf(of,"{\\stt \\#include \"%s\"} &\\cxreffile{%s}\\\\\n",latex(inc->name),inc->name);
360  |  else
361  |     fprintf(of,"{\\stt \\#include <%s>} &\\\\\n",latex(inc->name));
362  | 
363  |  if(inc->includes)
364  |     WriteLatexSubInclude(inc->includes,1);
365  | 
366  |  fprintf(of,"\\end{cxreftabi}\n\n");
367  | }
368  | 
369  | 
370  | /*++++++++++++++++++++++++++++++++++++++
371  |   Write an Sub Include structure out. (An include structure that is included from another file.)
372  | 
373  |   Include inc The Include structure to output.
374  | 
375  |   int depth The depth of the include hierarchy.
376  |   ++++++++++++++++++++++++++++++++++++++*/
377  | 
378  | static void WriteLatexSubInclude(Include inc,int depth)
379  | {
380  |  while(inc)
381  |    {
382  |     if(countlines++%8==4)
383  |        fprintf(of,"\\cxreftabbreak{cxreftabi}\n");
384  | 
385  |     fprintf(of,"\\hspace*{%3.1fin}",0.2*depth);
386  | 
387  |     if(inc->scope==LOCAL)
388  |        fprintf(of,"{\\stt \\#include \"%s\"} &\\cxreffile{%s}\\\\\n",latex(inc->name),inc->name);
389  |     else
390  |        fprintf(of,"{\\stt \\#include <%s>} &\\\\\n",latex(inc->name));
391  | 
392  |     if(inc->includes)
393  |        WriteLatexSubInclude(inc->includes,depth+1);
394  | 
395  |     inc=inc->next;
396  |    }
397  | }
398  | 
399  | 
400  | /*++++++++++++++++++++++++++++++++++++++
401  |   Write a Define structure out.
402  | 
403  |   Define def The Define structure to output.
404  |   ++++++++++++++++++++++++++++++++++++++*/
405  | 
406  | static void WriteLatexDefine(Define def)
407  | {
408  |  int i;
409  |  int pargs=0;
410  | 
411  |  if(def->comment)
412  |     fprintf(of,"%s\n\n\\smallskip\n",latex(def->comment));
413  | 
414  |  fprintf(of,"{\\stt \\#define %s",latex(def->name));
415  | 
416  |  if(def->value)
417  |     fprintf(of," %s",latex(def->value));
418  | 
419  |  if(def->args->n)
420  |    {
421  |     fprintf(of,"( ");
422  |     for(i=0;i<def->args->n;i++)
423  |        fprintf(of,i?", %s":"%s",latex(def->args->s1[i]));
424  |     fprintf(of," )");
425  |    }
426  |  fprintf(of,"}\n\n");
427  | 
428  |  for(i=0;i<def->args->n;i++)
429  |     if(def->args->s2[i])
430  |        pargs=1;
431  | 
432  |  if(pargs)
433  |    {
434  |     fprintf(of,"\\smallskip\n");
435  |     fprintf(of,"\\begin{cxrefarglist}\n");
436  |     for(i=0;i<def->args->n;i++)
437  |        fprintf(of,"\\cxrefargitem{%s} %s\n",latex(def->args->s1[i]),def->args->s2[i]?latex(def->args->s2[i]):"\\ ");
438  |     fprintf(of,"\\end{cxrefarglist}\n\n");
439  |    }
440  | }
441  | 
442  | 
443  | /*++++++++++++++++++++++++++++++++++++++
444  |   Write a Typedef structure out.
445  | 
446  |   Typedef type The Typedef structure to output.
447  | 
448  |   char* filename The name of the file that is being processed (required for the cross reference label).
449  |   ++++++++++++++++++++++++++++++++++++++*/
450  | 
451  | static void WriteLatexTypedef(Typedef type,char* filename)
452  | {
453  |  if(type->type)
454  |     fprintf(of,"\n\\subsubsection{Typedef %s}\n",latex(type->name));
455  |  else
456  |     fprintf(of,"\n\\subsubsection{Type %s}\n",latex(type->name));
457  | 
458  |  if(!strncmp("enum",type->name,4))
459  |     fprintf(of,"\\label{type_enum_%s_%s}\n\n",&type->name[5],filename);
460  |  else
461  |     if(!strncmp("union",type->name,5))
462  |        fprintf(of,"\\label{type_union_%s_%s}\n\n",&type->name[6],filename);
463  |     else
464  |        if(!strncmp("struct",type->name,6))
465  |           fprintf(of,"\\label{type_struct_%s_%s}\n\n",&type->name[7],filename);
466  |        else
467  |           fprintf(of,"\\label{type_%s_%s}\n\n",type->name,filename);
468  | 
469  |  if(type->comment)
470  |     fprintf(of,"%s\n\n\\smallskip\n",latex(type->comment));
471  | 
472  |  if(type->type)
473  |     fprintf(of,"{\\stt typedef %s}\n\n",latex(type->type));
474  | 
475  |  if(type->sutype)
476  |    {
477  |     fprintf(of,"\\smallskip\n");
478  |     fprintf(of,"\\begin{cxreftabiia}\n"); countlines=0;
479  |     WriteLatexStructUnion(type->sutype,0);
480  |     fprintf(of,"\\end{cxreftabiia}\n\n");
481  |    }
482  |  else
483  |     if(type->typexref)
484  |       {
485  |        fprintf(of,"\\smallskip\n");
486  |        fprintf(of,"\\begin{cxreftabii}\n");
487  |        if(type->typexref->type)
488  |           fprintf(of,"See:& Typedef %s & \\cxreftype{%s}{%s}\\\\\n",latex(type->typexref->name),type->typexref->name,filename);
489  |        else
490  |           if(!strncmp("enum",type->typexref->name,4))
491  |              fprintf(of,"See:& Type %s & \\cxreftype{enum_%s}{%s}\\\\\n",latex(type->typexref->name),&type->typexref->name[5],filename);
492  |           else
493  |              if(!strncmp("union",type->typexref->name,5))
494  |                 fprintf(of,"See:& Type %s & \\cxreftype{union_%s}{%s}\\\\\n",latex(type->typexref->name),&type->typexref->name[6],filename);
495  |              else
496  |                 if(!strncmp("struct",type->typexref->name,6))
497  |                    fprintf(of,"See:& Type %s & \\cxreftype{struct_%s}{%s}\\\\\n",latex(type->typexref->name),&type->typexref->name[7],filename);
498  |        fprintf(of,"\\end{cxreftabii}\n\n");
499  |       }
500  | }
501  | 
502  | 
503  | /*++++++++++++++++++++++++++++++++++++++
504  |   Write a structure / union structure out.
505  | 
506  |   StructUnion su The structure / union to write.
507  | 
508  |   int depth The current depth within the structure.
509  |   ++++++++++++++++++++++++++++++++++++++*/
510  | 
511  | static void WriteLatexStructUnion(StructUnion su, int depth)
512  | {
513  |  int i;
514  |  char* splitsu=NULL;
515  | 
516  |  splitsu=strstr(su->name,"{...}");
517  |  if(splitsu) splitsu[-1]=0;
518  | 
519  |  if(countlines++%8==4)
520  |     fprintf(of,"\\cxreftabbreak{cxreftabiia}\n");
521  |  fprintf(of,"\\hspace*{%3.1fin}",0.2*depth);
522  | 
523  |  if(depth && su->comment && !su->comps)
524  |     fprintf(of,"{\\stt %s;} & %s \\\\\n",latex(su->name),latex(su->comment));
525  |  else if(!depth || su->comps)
526  |     fprintf(of,"{\\stt %s} &\\\\\n",latex(su->name));
527  |  else
528  |     fprintf(of,"{\\stt %s;} &\\\\\n",latex(su->name));
529  | 
530  |  if(!depth || su->comps)
531  |    {
532  |     fprintf(of,"\\hspace*{%3.1fin}",0.1+0.2*depth);
533  |     fprintf(of,"{\\stt \\{} &\\\\\n");
534  | 
535  |     for(i=0;i<su->n_comp;i++)
536  |        WriteLatexStructUnion(su->comps[i],depth+1);
537  | 
538  |     fprintf(of,"\\hspace*{%3.1fin}",0.1+0.2*depth);
539  |     fprintf(of,"{\\stt \\}} &\\\\\n");
540  |     if(splitsu)
541  |       {
542  |        fprintf(of,"\\hspace*{%3.1fin}",0.1+0.2*depth);
543  |        if(depth && su->comment)
544  |           fprintf(of,"{\\stt %s;} & %s \\\\\n",splitsu[5]?latex(&splitsu[6]):"",latex(su->comment));
545  |        else
546  |           fprintf(of,"{\\stt %s;} &\\\\\n",splitsu[5]?latex(&splitsu[6]):"");
547  |       }
548  |    }
549  | 
550  |  if(splitsu) splitsu[-1]=' ';
551  | }
552  | 
553  | 
554  | /*++++++++++++++++++++++++++++++++++++++
555  |   Write a Variable structure out.
556  | 
557  |   Variable var The Variable structure to output.
558  | 
559  |   char* filename The name of the file that is being processed (required for the cross reference label).
560  |   ++++++++++++++++++++++++++++++++++++++*/
561  | 
562  | static void WriteLatexVariable(Variable var,char* filename)
563  | {
564  |  int i;
565  | 
566  |  if(var->scope&GLOBAL)
567  |     fprintf(of,"\n\\subsubsection{Variable %s}\n",latex(var->name));
568  |  else
569  |     fprintf(of,"{\\bf %s}\n",latex(var->name));
570  | 
571  |  fprintf(of,"\\label{var_%s_%s}\n\n",var->name,filename);
572  | 
573  |  if(var->comment)
574  |     fprintf(of,"%s\n\n\\smallskip\n",latex(var->comment));
575  | 
576  |  fprintf(of,"{\\stt ");
577  | 
578  |  if(var->scope&LOCAL)
579  |     fprintf(of,"static ");
580  |  else
581  |     if(!(var->scope&GLOBAL) && var->scope&(EXTERNAL|EXTERN_F))
582  |        fprintf(of,"extern ");
583  | 
584  |  fprintf(of,"%s}\n\n",latex(var->type));
585  | 
586  |  if(var->scope&(GLOBAL|LOCAL))
587  |    {
588  |     if(var->incfrom || var->used->n || var->visible->n)
589  |       {
590  |        fprintf(of,"\\smallskip\n");
591  |        fprintf(of,"\\begin{cxreftabiii}\n");
592  | 
593  |        if(var->incfrom)
594  |           fprintf(of,"Inc. from:& %s & \\ & \\cxrefvar{%s}{%s}\\\\\n",latex(var->incfrom),var->name,var->incfrom);
595  | 
596  |        for(i=0;i<var->visible->n;i++)
597  |          {
598  |           if(min(i,var->visible->n+var->used->n-i)%8 == 4)
599  |              fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
600  |           if(i==0) fprintf(of,"Visible in:");
601  |           if(var->visible->s1[i][0]=='$')
602  |              fprintf(of,"\\ & %s & \\ & \\cxreffile{%s}\\\\\n",latex(var->visible->s2[i]),var->visible->s2[i]);
603  |           else
604  |              fprintf(of,"\\ & %s() & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(var->visible->s1[i]),latex(var->visible->s2[i]),var->visible->s1[i],var->visible->s2[i]);
605  |          }
606  | 
607  |        for(i=0;i<var->used->n;i++)
608  |          {
609  |           if(min(i,var->visible->n+var->used->n-i)%8 == 4)
610  |              fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
611  |           if(i==0) fprintf(of,"Used in:");
612  |           if(var->used->s1[i][0]=='$')
613  |              fprintf(of,"\\ & %s & \\ & \\cxreffile{%s}\\\\\n",latex(var->used->s2[i]),var->used->s2[i]);
614  |           else
615  |              if(var->scope&LOCAL)
616  |                 fprintf(of,"\\ & %s() & \\ & \\cxreffunc{%s}{%s}\\\\\n",latex(var->used->s1[i]),var->used->s1[i],var->used->s2[i]);
617  |              else
618  |                 fprintf(of,"\\ & %s() & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(var->used->s1[i]),latex(var->used->s2[i]),var->used->s1[i],var->used->s2[i]);
619  |          }
620  | 
621  |        fprintf(of,"\\end{cxreftabiii}\n\n");
622  |       }
623  |    }
624  |  else
625  |     if(var->scope&(EXTERNAL|EXTERN_F) && var->defined)
626  |       {
627  |        fprintf(of,"\\smallskip\n");
628  |        fprintf(of,"\\begin{cxreftabiii}\n");
629  |        fprintf(of,"Defined in:& %s & \\ & \\cxrefvar{%s}{%s}\\\\\n",latex(var->defined),var->name,var->defined);
630  |        fprintf(of,"\\end{cxreftabiii}\n\n");
631  |       }
632  | }
633  | 
634  | 
635  | /*++++++++++++++++++++++++++++++++++++++
636  |   Write a Function structure out.
637  | 
638  |   Function func The Function structure to output.
639  | 
640  |   char* filename The name of the file that is being processed (required for the cross reference label).
641  |   ++++++++++++++++++++++++++++++++++++++*/
642  | 
643  | static void WriteLatexFunction(Function func,char* filename)
644  | {
645  |  int i,pret,pargs;
646  |  char* comment2=NULL,*type;
647  | 
648  |  if(func->scope&GLOBAL)
649  |     fprintf(of,"\n\\subsubsection{Global Function %s()}\n",latex(func->name));
650  |  else
651  |     fprintf(of,"\n\\subsubsection{Local Function %s()}\n",latex(func->name));
652  |  fprintf(of,"\\label{func_%s_%s}\n\n",func->name,filename);
653  | 
654  |  if(func->comment)
655  |     if(option_verbatim_comments)
656  |        fprintf(of,"\\begin{verbatim}\n%s\n\\end{verbatim}\n\n",latex(func->comment));
657  |     else
658  |       {
659  |        comment2=strstr(func->comment,"\n\n");
660  |        if(comment2)
661  |           comment2[0]=0;
662  |        fprintf(of,"%s\n\n",latex(func->comment));
663  |        fprintf(of,"\\smallskip\n");
664  |       }
665  | 
666  |  fprintf(of,"{\\stt ");
667  | 
668  |  if(func->scope&LOCAL)
669  |     fprintf(of,"static ");
670  |  if(func->scope&INLINED)
671  |    fprintf(of,"inline ");
672  | 
673  |  if((type=strstr(func->type,"()")))
674  |     type[0]=0;
675  |  fprintf(of,"%s ( ",latex(func->type));
676  | 
677  |  for(i=0;i<func->args->n;i++)
678  |     fprintf(of,i?", %s":"%s",latex(func->args->s1[i]));
679  | 
680  |  if(type)
681  |    {fprintf(of," %s}\n\n",&type[1]);type[0]='(';}
682  |  else
683  |     fprintf(of," )}\n\n");
684  | 
685  |  pret =strncmp("void ",func->type,5) && func->cret;
686  |  for(pargs=0,i=0;i<func->args->n;i++)
687  |     pargs = pargs || ( strcmp("void",func->args->s1[i]) && func->args->s2[i] );
688  | 
689  |  if(pret || pargs)
690  |    {
691  |     fprintf(of,"\\smallskip\n");
692  |     fprintf(of,"\\begin{cxrefarglist}\n");
693  |     if(pret)
694  |        fprintf(of,"\\cxrefargitem{%s} %s\n",latex(func->type),func->cret?latex(func->cret):"\\ ");
695  |     if(pargs)
696  |        for(i=0;i<func->args->n;i++)
697  |           fprintf(of,"\\cxrefargitem{%s} %s\n",latex(func->args->s1[i]),func->args->s2[i]?latex(func->args->s2[i]):"\\ ");
698  |     fprintf(of,"\\end{cxrefarglist}\n\n");
699  |    }
700  | 
701  |  if(comment2)
702  |    {
703  |     fprintf(of,"\\smallskip\n");
704  |     fprintf(of,"%s\n\n",latex(&comment2[2]));
705  |     comment2[0]='\n';
706  |    }
707  | 
708  |  if(func->protofile || func->incfrom || func->calls->n || func->called->n || func->used->n || func->f_refs->n || func->v_refs->n)
709  |    {
710  |     int tabcount=func->protofile?1:0;
711  |     fprintf(of,"\\smallskip\n");
712  |     fprintf(of,"\\begin{cxreftabiii}\n");
713  | 
714  |     if(func->protofile)
715  |        fprintf(of,"Prototype:& %s & \\ & \\cxreffile{%s}\\\\\n",latex(func->protofile),func->protofile);
716  | 
717  |     if(func->incfrom)
718  |        fprintf(of,"Inc. from:& %s & \\ & \\cxreffunc{%s}{%s}\\\\\n",latex(func->incfrom),func->name,func->incfrom);
719  | 
720  |     if(func->calls->n)
721  |       {
722  |        int others=0;
723  | 
724  |        fprintf(of,"Calls:");
725  | 
726  |        for(i=0;i<func->calls->n;i++)
727  |           if(func->calls->s2[i])
728  |             {
729  |              fprintf(of,"\\ & %s() & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(func->calls->s1[i]),latex(func->calls->s2[i]),func->calls->s1[i],func->calls->s2[i]);
730  |              if(++tabcount%8 == 4)
731  |                 fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
732  |             }
733  |           else
734  |              others++;
735  | 
736  |        if(others)
737  |          {
738  |           fprintf(of,"\\ & \\cxreftabiiispan{");
739  |           for(i=0;i<func->calls->n;i++)
740  |              if(!func->calls->s2[i])
741  |                 fprintf(of,--others?" %s(),":" %s()",latex(func->calls->s1[i]));
742  |           fprintf(of,"} &\\\\\n");
743  |          }
744  |       }
745  | 
746  |     if(func->called->n)
747  |       {
748  |        fprintf(of,"Called by:");
749  | 
750  |        for(i=0;i<func->called->n;i++)
751  |          {
752  |           fprintf(of,"\\ & %s() & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(func->called->s1[i]),latex(func->called->s2[i]),func->called->s1[i],func->called->s2[i]);
753  |           if(++tabcount%8 == 4)
754  |              fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
755  |          }
756  |       }
757  | 
758  |     if(func->used->n)
759  |       {
760  |        fprintf(of,"Used in:");
761  | 
762  |        for(i=0;i<func->used->n;i++)
763  |          {
764  |           if(func->used->s1[i][0]=='$')
765  |              fprintf(of,"\\ & %s & \\ & \\cxreffile{%s}\\\\\n",latex(func->used->s2[i]),func->used->s2[i]);
766  |           else
767  |              fprintf(of,"\\ & %s() & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(func->used->s1[i]),latex(func->used->s2[i]),func->used->s1[i],func->used->s2[i]);
768  |           if(++tabcount%8 == 4)
769  |              fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
770  |          }
771  |       }
772  | 
773  |     if(func->f_refs->n)
774  |       {
775  |        int others=0;
776  | 
777  |        fprintf(of,"Refs Func:");
778  | 
779  |        for(i=0;i<func->f_refs->n;i++)
780  |           if(func->f_refs->s2[i])
781  |             {
782  |              fprintf(of,"\\ & %s() & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(func->f_refs->s1[i]),latex(func->f_refs->s2[i]),func->f_refs->s1[i],func->f_refs->s2[i]);
783  |              if(++tabcount%8 == 4)
784  |                 fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
785  |             }
786  |           else
787  |              others++;
788  | 
789  |        if(others)
790  |          {
791  |           fprintf(of,"\\ & \\cxreftabiiispan{");
792  |           for(i=0;i<func->f_refs->n;i++)
793  |              if(!func->f_refs->s2[i])
794  |                 fprintf(of,--others?" %s(),":" %s()",latex(func->f_refs->s1[i]));
795  |           fprintf(of,"} &\\\\\n");
796  |          }
797  |       }
798  | 
799  |     if(func->v_refs->n)
800  |       {
801  |        int others=0;
802  | 
803  |        fprintf(of,"Refs Var:");
804  | 
805  |        for(i=0;i<func->v_refs->n;i++)
806  |           if(func->v_refs->s2[i])
807  |             {
808  |              fprintf(of,"\\ & %s & %s & \\cxrefvar{%s}{%s}\\\\\n",latex(func->v_refs->s1[i]),latex(func->v_refs->s2[i]),func->v_refs->s1[i],func->v_refs->s2[i]);
809  |              if(++tabcount%8 == 4)
810  |                 fprintf(of,"\\cxreftabbreak{cxreftabiii}\n");
811  |             }
812  |           else
813  |              others++;
814  | 
815  |        if(others)
816  |          {
817  |           fprintf(of,"\\ & \\cxreftabiiispan{");
818  |           for(i=0;i<func->v_refs->n;i++)
819  |              if(!func->v_refs->s2[i])
820  |                 fprintf(of,--others?" %s,":" %s",latex(func->v_refs->s1[i]));
821  |           fprintf(of,"} &\\\\\n");
822  |          }
823  |       }
824  | 
825  |     fprintf(of,"\\end{cxreftabiii}\n\n");
826  |    }
827  | }
828  | 
829  | 
830  | /*++++++++++++++++++++++++++++++++++++++
831  |   Write out a file that will include the current information.
832  | 
833  |   char* name The name of the file (without the LaTeX extension).
834  | 
835  |   int appendix set to non-zero if the appendix file is to be added, else a normal source file.  
836  |   ++++++++++++++++++++++++++++++++++++++*/
837  | 
838  | static void WriteLatexDocument(char* name,int appendix)
839  | {
840  |  FILE *in,*out;
841  |  char line[256];
842  |  int seen=0;
843  |  char *inc_file,*ofile,*ifile;
844  | 
845  |  inc_file=ConcatStrings(4,"\\input{",name,LATEX_FILE,"}\n");
846  |  ifile=ConcatStrings(4,option_odir,"/",option_name,LATEX_FILE);
847  |  ofile=ConcatStrings(4,option_odir,"/",option_name,LATEX_FILE_BACKUP);
848  | 
849  |  in =fopen(ifile,"r");
850  |  if(!in)
851  |    {
852  |     WriteLatexTemplate(ifile);
853  |     in =fopen(ifile,"r");
854  |    }
855  | 
856  |  out=fopen(ofile,"w");
857  | 
858  |  if(!out)
859  |    {fprintf(stderr,"cxref: Failed to open the main LaTeX output file '%s'\n",ofile);exit(1);}
860  | 
861  |  while(fgets(line,256,in))
862  |    {
863  |     if(!strcmp(inc_file,line) ||
864  |        (line[0]=='%' && !strcmp(inc_file,line+1)) ||
865  |        (line[0]=='%' && line[1]==' ' && !strcmp(inc_file,line+2)))
866  |        {seen=1;break;}
867  |     if(line[0]=='%' && !strcmp("% End-Of-Source-Files\n",line))
868  |       {
869  |        if(appendix)
870  |          {
871  |           fputs(line,out);
872  |           fputs("\n",out);
873  |           fputs("% Appendix\n",out);
874  |           fputs("\n",out);
875  |           fputs("\\appendix\n",out);
876  |           fputs("\\markboth{Appendix}{Appendix}\n",out);
877  |           fputs(inc_file,out);
878  |          }
879  |        else
880  |          {
881  |           fputs(inc_file,out);
882  |           fputs("\n",out);
883  |           fputs(line,out);
884  |          }
885  |       }
886  |     else
887  |        fputs(line,out);
888  |    }
889  | 
890  |  fclose(in);
891  |  fclose(out);
892  | 
893  |  if(!seen)
894  |    {
895  |     unlink(ifile);
896  |     rename(ofile,ifile);
897  |    }
898  |  else
899  |     unlink(ofile);
900  | }
901  | 
902  | 
903  | /*++++++++++++++++++++++++++++++++++++++
904  |   Write out the standard template for the main LaTeX file.
905  |   This sets up the page styles, and includes markers for the start and end of included source code.
906  | 
907  |   char* name The name of the file to write the template to.
908  |   ++++++++++++++++++++++++++++++++++++++*/
909  | 
910  | static void WriteLatexTemplate(char* name)
911  | {
912  |  FILE *template;
913  |  struct stat stat_buf;
914  |  char* fname;
915  |  
916  |  template=fopen(name,"w");
917  | 
918  |  if(!template)
919  |    {fprintf(stderr,"cxref: Failed to open the main LaTeX output file '%s'\n",name);exit(1);}
920  | 
921  |  fputs("% This LaTeX file generated by cxref\n",template);
922  |  fputs("% cxref program (c) Andrew M. Bishop 1995,96,97,98.\n",template);
923  |  fputs("\n",template);
924  |  if(option_latex==1)
925  |     fputs("\\documentstyle[fonts,page,cxref]{report}\n",template);
926  |  else
927  |    {
928  |     fputs("\\documentclass{report}\n",template);
929  |     fputs("\\usepackage{fonts,page,cxref}\n",template);
930  |    }
931  |  fputs("\\pagestyle{myheadings}\n",template);
932  |  fputs("\n",template);
933  |  fputs("\\begin{document}\n",template);
934  |  fputs("\n",template);
935  |  fputs("% Contents (Optional, either here or at end)\n",template);
936  |  fputs("\n",template);
937  |  fputs("%\\markboth{Contents}{Contents}\n",template);
938  |  fputs("%\\tableofcontents\n",template);
939  |  fputs("\n",template);
940  |  fputs("\\chapter{Source Files}\n",template);
941  |  fputs("\n",template);
942  |  fputs("% Begin-Of-Source-Files\n",template);
943  |  fputs("\n",template);
944  |  fputs("% End-Of-Source-Files\n",template);
945  |  fputs("\n",template);
946  |  fputs("% Contents (Optional, either here or at beginning)\n",template);
947  |  fputs("\n",template);
948  |  fputs("\\markboth{Contents}{Contents}\n",template);
949  |  fputs("\\tableofcontents\n",template);
950  |  fputs("\n",template);
951  |  fputs("\\end{document}\n",template);
952  | 
953  |  fclose(template);
954  | 
955  |  fname=ConcatStrings(2,option_odir,"/fonts.sty");
956  |  if(stat(fname,&stat_buf))
957  |    {
958  |     FILE* file=fopen(fname,"w");
959  |     if(!file)
960  |       {fprintf(stderr,"cxref: Cannot write the LaTeX style file '%s'\n",fname);exit(1);}
961  |     fputs(latex_fonts_style,file);
962  |     fclose(file);
963  |    }
964  | 
965  |  fname=ConcatStrings(2,option_odir,"/page.sty");
966  |  if(stat(fname,&stat_buf))
967  |    {
968  |     FILE* file=fopen(fname,"w");
969  |     if(!file)
970  |       {fprintf(stderr,"cxref: Cannot write the LaTeX style file '%s'\n",fname);exit(1);}
971  |     fputs(latex_page_style,file);
972  |     fclose(file);
973  |    }
974  | 
975  |  fname=ConcatStrings(2,option_odir,"/cxref.sty");
976  |  if(stat(fname,&stat_buf))
977  |    {
978  |     FILE* file=fopen(fname,"w");
979  |     if(!file)
980  |       {fprintf(stderr,"cxref: Cannot write the LaTeX style file '%s'\n",fname);exit(1);}
981  |     fputs(latex_cxref_style,file);
982  |     fclose(file);
983  |    }
984  | }
985  | 
986  | 
987  | /*++++++++++++++++++++++++++++++++++++++
988  |   Write out the appendix information.
989  | 
990  |   StringList files The list of files to write.
991  | 
992  |   StringList2 funcs The list of functions to write.
993  | 
994  |   StringList2 vars The list of variables to write.
995  | 
996  |   StringList2 types The list of types to write.
997  |   ++++++++++++++++++++++++++++++++++++++*/
998  | 
999  | void WriteLatexAppendix(StringList files,StringList2 funcs,StringList2 vars,StringList2 types)
1000 | {
1001 |  char* ofile;
1002 |  int i;
1003 | 
1004 |  /* Write the bits to the including file. */
1005 | 
1006 |  WriteLatexDocument(ConcatStrings(2,option_name,LATEX_APDX),1);
1007 | 
1008 |  /* Open the file */
1009 | 
1010 |  ofile=ConcatStrings(5,option_odir,"/",option_name,LATEX_APDX,LATEX_FILE);
1011 | 
1012 |  of=fopen(ofile,"w");
1013 | 
1014 |  if(!of)
1015 |    {fprintf(stderr,"cxref: Failed to open the LaTeX appendix file '%s'\n",ofile);exit(1);}
1016 | 
1017 |  /* Write the file structure out */
1018 | 
1019 |  fprintf(of,"\\chapter{Cross References}\n");
1020 | 
1021 |  /* Write out the appendix of files. */
1022 | 
1023 |  if(files->n)
1024 |    {
1025 |     fprintf(of,"\n\\section{Files}\n");
1026 |     fprintf(of,"\\label{appendix_file}\n\n");
1027 |     fprintf(of,"\\begin{cxreftabiib}\n");
1028 |     for(i=0;i<files->n;i++)
1029 |       {
1030 |        if(min(i,files->n-i)%8 == 4)
1031 |           fprintf(of,"\\cxreftabbreak{cxreftabiib}\n");
1032 |        fprintf(of,"%s & \\ & \\cxreffile{%s}\\\\\n",latex(files->s[i]),files->s[i]);
1033 |       }
1034 |     fprintf(of,"\\end{cxreftabiib}\n\n");
1035 |    }
1036 | 
1037 |  /* Write out the appendix of functions. */
1038 | 
1039 |  if(funcs->n)
1040 |    {
1041 |     fprintf(of,"\n\\section{Global Functions}\n");
1042 |     fprintf(of,"\\label{appendix_func}\n\n");
1043 |     fprintf(of,"\\begin{cxreftabiib}\n");
1044 |     for(i=0;i<funcs->n;i++)
1045 |       {
1046 |        if(min(i,funcs->n-i)%8 == 4)
1047 |           fprintf(of,"\\cxreftabbreak{cxreftabiib}\n");
1048 |        fprintf(of,"%s & %s & \\cxreffunc{%s}{%s}\\\\\n",latex(funcs->s1[i]),latex(funcs->s2[i]),funcs->s1[i],funcs->s2[i]);
1049 |       }
1050 |     fprintf(of,"\\end{cxreftabiib}\n\n");
1051 |    }
1052 | 
1053 |  /* Write out the appendix of variables. */
1054 | 
1055 |  if(vars->n)
1056 |    {
1057 |     fprintf(of,"\n\\section{Global Variables}\n");
1058 |     fprintf(of,"\\label{appendix_var}\n\n");
1059 |     fprintf(of,"\\begin{cxreftabiib}\n");
1060 |     for(i=0;i<vars->n;i++)
1061 |       {
1062 |        if(min(i,vars->n-i)%8 == 4)
1063 |           fprintf(of,"\\cxreftabbreak{cxreftabiib}\n");
1064 |        fprintf(of,"%s & %s & \\cxrefvar{%s}{%s}\\\\\n",latex(vars->s1[i]),latex(vars->s2[i]),vars->s1[i],vars->s2[i]);
1065 |       }
1066 |     fprintf(of,"\\end{cxreftabiib}\n\n");
1067 |    }
1068 | 
1069 |  /* Write out the appendix of types. */
1070 | 
1071 |  if(types->n)
1072 |    {
1073 |     fprintf(of,"\n\\section{Defined Types}\n");
1074 |     fprintf(of,"\\label{appendix_type}\n\n");
1075 |     fprintf(of,"\\begin{cxreftabiib}\n");
1076 |     for(i=0;i<types->n;i++)
1077 |       {
1078 |        if(min(i,types->n-i)%8 == 4)
1079 |           fprintf(of,"\\cxreftabbreak{cxreftabiib}\n");
1080 |        if(!strncmp("enum",types->s1[i],4))
1081 |           fprintf(of,"%s & %s & \\cxreftype{enum_%s}{%s}\\\\\n",latex(types->s1[i]),latex(types->s2[i]),&types->s1[i][5],types->s2[i]);
1082 |        else
1083 |           if(!strncmp("union",types->s1[i],5))
1084 |              fprintf(of,"%s & %s & \\cxreftype{union_%s}{%s}\\\\\n",latex(types->s1[i]),latex(types->s2[i]),&types->s1[i][6],types->s2[i]);
1085 |           else
1086 |              if(!strncmp("struct",types->s1[i],6))
1087 |                 fprintf(of,"%s & %s & \\cxreftype{struct_%s}{%s}\\\\\n",latex(types->s1[i]),latex(types->s2[i]),&types->s1[i][7],types->s2[i]);
1088 |              else
1089 |                 fprintf(of,"%s & %s & \\cxreftype{%s}{%s}\\\\\n",latex(types->s1[i]),latex(types->s2[i]),types->s1[i],types->s2[i]);
1090 |       }
1091 |     fprintf(of,"\\end{cxreftabiib}\n\n");
1092 |    }
1093 | 
1094 |  fclose(of);
1095 | 
1096 |  /* Clear the memory in latex() */
1097 | 
1098 |  latex(NULL); latex(NULL); latex(NULL); latex(NULL);
1099 | }
1100 | 
1101 | 
1102 | /*++++++++++++++++++++++++++++++++++++++
1103 |   Delete the latex file and main file reference that belong to the named file.
1104 | 
1105 |   char *name The name of the file to delete.
1106 |   ++++++++++++++++++++++++++++++++++++++*/
1107 | 
1108 | void WriteLatexFileDelete(char *name)
1109 | {
1110 |  FILE *in,*out;
1111 |  char line[256];
1112 |  int seen=0;
1113 |  char *inc_file,*ofile,*ifile;
1114 | 
1115 |  ofile=ConcatStrings(4,option_odir,"/",name,LATEX_FILE);
1116 |  unlink(ofile);
1117 | 
1118 |  inc_file=ConcatStrings(4,"\\input{",name,LATEX_FILE,"}\n");
1119 |  ifile=ConcatStrings(4,option_odir,"/",option_name,LATEX_FILE);
1120 |  ofile=ConcatStrings(4,option_odir,"/",option_name,LATEX_FILE_BACKUP);
1121 | 
1122 |  in =fopen(ifile,"r");
1123 |  out=fopen(ofile,"w");
1124 | 
1125 |  if(in && !out)
1126 |    {fprintf(stderr,"cxref: Failed to open the main LaTeX output file '%s'\n",ofile);fclose(in);}
1127 |  else if(in)
1128 |    {
1129 |     while(fgets(line,256,in))
1130 |       {
1131 |        if(!strcmp(inc_file,line) ||
1132 |           (line[0]=='%' && !strcmp(inc_file,line+1)) ||
1133 |           (line[0]=='%' && line[1]==' ' && !strcmp(inc_file,line+2)))
1134 |           seen=1;
1135 |        else
1136 |           fputs(line,out);
1137 |       }
1138 | 
1139 |     fclose(in);
1140 |     fclose(out);
1141 | 
1142 |     if(seen)
1143 |       {
1144 |        unlink(ifile);
1145 |        rename(ofile,ifile);
1146 |       }
1147 |     else
1148 |        unlink(ofile);
1149 |    }
1150 |  else if(out)
1151 |    {
1152 |     fclose(out);
1153 |     unlink(ofile);
1154 |    }
1155 | }
1156 | 
1157 | 
1158 | /*++++++++++++++++++++++++++++++++++++++
1159 |   Make the input string safe to output as LaTeX ( not #, $, %, &, \, ^, _, {, }, <, > or ~ ).
1160 | 
1161 |   char* latex Returns a safe LaTeX string.
1162 | 
1163 |   char* c A non-safe LaTeX string.
1164 | 
1165 |   The function can only be called four times in each fprintf() since it returns one of only four static strings.
1166 |   ++++++++++++++++++++++++++++++++++++++*/
1167 | 
1168 | static char* latex(char* c)
1169 | {
1170 |  static char safe[4][256],*malloced[4]={NULL,NULL,NULL,NULL};
1171 |  static int which=0;
1172 |  int copy=0,skip=0;
1173 |  int i=0,j=0,delta=13,len=256-delta;
1174 |  char* ret;
1175 | 
1176 |  which=(which+1)%4;
1177 |  ret=safe[which];
1178 | 
1179 |  safe[which][0]=0;
1180 | 
1181 |  if(malloced[which])
1182 |    {Free(malloced[which]);malloced[which]=NULL;}
1183 | 
1184 |  if(c)
1185 |     while(1)
1186 |        {
1187 |        for(;j<len && c[i];i++)
1188 |          {
1189 |           if(copy)
1190 |             {ret[j++]=c[i]; if(c[i]=='\n') copy=0;}
1191 |           else if(skip)
1192 |             {               if(c[i]=='\n') skip=0;}
1193 |           else
1194 |              switch(c[i])
1195 |                {
1196 |                case '<':
1197 |                case '>':
1198 |                 ret[j++]='$';
1199 |                 ret[j++]=c[i];
1200 |                 ret[j++]='$';
1201 |                 break;
1202 |                case '\\':
1203 |                 strcpy(&ret[j],"$\\backslash$");j+=12;
1204 |                 break;
1205 |                case '~':
1206 |                 strcpy(&ret[j],"$\\sim$");j+=6;
1207 |                 break;
1208 |                case '^':
1209 |                 strcpy(&ret[j],"$\\wedge$");j+=8;
1210 |                 break;
1211 |                case '#':
1212 |                case '$':
1213 |                case '%':
1214 |                case '&':
1215 |                case '_':
1216 |                case '{':
1217 |                case '}':
1218 |                 ret[j++]='\\';
1219 |                 ret[j++]=c[i];
1220 |                 break;
1221 |                default:
1222 |                 ret[j++]=c[i];
1223 |                }
1224 |           if(c[i]=='\n')
1225 |              i+=CopyOrSkip(c+i,"latex",&copy,&skip);
1226 |          }
1227 | 
1228 |        if(c[i])                 /* Not finished */
1229 |          {
1230 |           if(malloced[which])
1231 |              malloced[which]=Realloc(malloced[which],len+delta+256);
1232 |           else
1233 |             {malloced[which]=Malloc(len+delta+256); strncpy(malloced[which],ret,(unsigned)j);}
1234 |           ret=malloced[which];
1235 |           len+=256;
1236 |          }
1237 |        else
1238 |          {ret[j]=0; break;}
1239 |       }
1240 | 
1241 |  return(ret);
1242 | }