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",©,&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 | }