1 /* $Id: latex-fmt.cc,v 1.15 1997/04/13 13:26:38 dps Exp dps $ */
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif /* HAVE_CONFIG_H */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <time.h>
8 #ifdef HAVE_UNISTD_H
9 #include <unistd.h>
10 #endif /* HAVE_UNISTD_H */
11 #ifdef HAVE_CTYPE_H
12 #include <ctype.h>
13 #endif /* HAVE_CTYPE_H */
14 #ifdef HAVE_SYS_STAT_H
15 #include <sys/stat.h>
16 #endif /* HAVE_SYS_STAT_H */
17 #include "interface.h"
18 #include "lib.h"
19 #include "latex-table.h"
20 #include "fmt-latex.h"
21 
22 static const cmap tex_map[]=
23 {
24     { '\n', "\\\\\n" },		     // Newline
25     { 0x1E, "-" },		     // Unbreakable join
26     { 0x1F, "\\-" },		     // Soft hypen
27     { '#', "{\\#}" },		     // #
28     { '$', "{\\$}" },		     // $
29     { '%', "{\\%}" },		     // %  (5th element)
30     { '&', "{\\&}" },		     // &
31     { '@', "{\\@}" },		     // @
32     { '\\', "$\\backslash$" },	     // backslash
33     { '^', "{\\^}" },		     // ^
34     { '_', "{\\_}" },		     // _  (10th element)
35     { '{', "{\\{}" },		     // {
36     { '}', "{\\}}" },		     // }
37     { '~', "{\\~}" },		     // ~
38     { CH_SUSPECT, "" },		     // Delete suspect data markers
39     { 0x85, "\\unskip\\ldots" },     // Dots
40     { 0x91, "{`}" },		     // 91 = left quote (15th element)
41     { 0x92, "{'}" },		     // 92 = right quote
42     { 0x93, "``" },		     // 93 = opening double quote
43     { 0x94, "''" },		     // 94 = closing double quote
44     { 0x96, "--" },		     // em-dash
45     { 0x97, "---" },		     // en-dash (20th element)
46     { 0x99, "${}^{\\rm TM}$" },	     // Trademark
47     { 0xA0, "~" },		     // Unbreakable space
48     { 0xA3, "$\\leq$" },	     // <= came out as A3, also pounds
49     { 0xA9, "{\\copyright}" },	     // Copyright
50     { 0xAB, "$<\\!\\!<$" },	     // Openning << quotes (25th element)
51     { 0xAE, "{\\reg}" },	     // reserved sign
52     { 0xB3, "$\\geq$" },	     // Greater than or = came out as B3
53     { 0xBB, "$>\\!\\!>$" },	     // Closing >> quotes (28th element)
54     { 0xDF, "{\\ss}" },		     // beta
55     { 0xE4, "\\\"a" },		     // a with umlualt
56     { 0xE9, "\\'e" },		     // e grave??
57     { 0xF1, "\\=n" },		     // n bar
58     { 0xF6, "\\\"o" },		     // o with umlualt
59     { 0xFA, "\\.u" },		     // u with dot?
60     { 0xFC, "\\\"u" },		     // u with umlualt.
61 
62 };
63 
__latex_do_map(const char * s)64 tblock *__latex_do_map(const char *s)
65 {
66     tblock *out;
67 
68     out=map_string(s, tex_map);
69     return out;
70 }
71 
72 /* Preamble */
preamble(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)73 static void preamble(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
74 		    void *d)
75 {
76     time_t now;
77 #ifdef HAVE_FSTAT
78     struct stat st;
79 #endif
80     char *tnow, *tdoc;
81 
82     t=t;
83     d=d;
84 
85     now=time(NULL);
86     tnow=(fmt->date)(now);
87 
88 #ifdef HAVE_FSTAT
89     if (fstat(fileno(out), &st)==-1)
90     {
91 	fprintf(stderr, "Warning: fstat failed\n");
92 	st.st_mtime=now;
93     }
94     tdoc=fmt->date(st.st_mtime);
95 #else
96     tdoc="date not known";
97 #endif
98 
99     fprintf(out,
100 	    "%% Generated by word2x on %s\n"
101 	    "%%\n"
102 	    "\\date{%s}\n"
103 	    "\\documentclass{article}\n"
104 	    "\\usepackage{amstext}\n"
105 	    "\\def\\reg{\\setbox0\\hbox{$\\mathchar\"20D$}%%\n"
106 	    "\\hbox to 0pt{\\hbox to \\wd0{\\hfill\\,\\rm R\\hfill}\\hss}%%\n"
107 	    "$\\mathchar\"20D$}\n"
108 	    "\\usepackage[latin1]{inputenc}\n"
109 	    "\\begin{document}\n",
110 	    tnow, tdoc);
111     free(tnow);
112     free(tdoc);
113 }
114 
115 /* Postamble */
postamble(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)116 static void postamble(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
117 		    void *d)
118 {
119     struct latex_data *dp;
120     fmt=fmt;
121     t=t;
122     dp=(struct latex_data *) d;
123 
124     fputs("\\end{document}\n", out);
125 }
126 
127 /* Allocate local data */
allocate_latex(void)128 static void *allocate_latex(void)
129 {
130     struct latex_data *tdata;
131     int i;
132 
133     tdata=new(struct latex_data);
134     tdata->tabl=NULL;
135     tdata->last_tc=NULL;
136     tdata->unit_d.unit_type=1;
137     tdata->list_flg=0;
138     for (i=0; i<4; i++)
139 	tdata->unit_d.unit_number[i]=-1;
140     return tdata;
141 }
142 
143 /* Free local data */
free_latex(void * d)144 static void free_latex(void *d)
145 {
146     struct latex_data *tdata;
147 
148     tdata=(struct latex_data *) d;
149     if (tdata->tabl!=NULL)
150 	delete(tdata->tabl);
151 
152 }
153 
ltx_code(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)154 static void ltx_code(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
155 		     void *d)
156 {
157     d=d;
158     switch(*(t->data.d))
159     {
160     case CH_PAGE:
161 	if (fmt->flags.new_pages)
162 	    fputs("%\n\\newpage%\n", out);
163 	break;
164 
165     default:
166 	break;
167     }
168 }
169 
170 /* item */
ltx_item(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)171 static void ltx_item(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
172 		    void *d)
173 {
174     struct latex_data *dp;
175     fmt=fmt;
176     t=t;
177     out=out;
178     dp=(struct latex_data *) d;
179 
180     dp->list_flg=1;
181 }
182 
183 
184 /* start list */
ltx_list(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)185 static void ltx_list(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
186 		    void *d)
187 {
188     fmt=fmt;
189     d=d;
190 
191     fprintf(out, "\n\\begin{%s}\n", t->data.d);	// Prior argement with reader
192 }
193 
194 /* end list */
ltx_end_list(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)195 static void ltx_end_list(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
196 		    void *d)
197 {
198     fmt=fmt;
199     d=d;
200 
201     fprintf(out, "\n\\end{%s}\n", t->data.d);	// Prior argement with reader
202 }
203 
204 
205 /* Find part number and return it or -1 if no number */
get_part_num(const char * st,const char * fence)206 int get_part_num(const char *st, const char *fence)
207 {
208     int n;
209 
210     while (st<fence)
211     {
212 	if (isspace(*st))
213 	{
214 	    st++;
215 	    continue;
216 	}
217 	if (isdigit(*st))
218 	{
219 	    n=0;
220 	    while (st<fence && isdigit(*st))
221 	    {
222 		n=n*10+(*st)-'0';
223 		st++;
224 	    }
225 	    if (!isspace(*st))
226 		return -1;
227 	    else
228 		return n;
229 
230 	}
231 	if (isupper(*st) && isspace(*(st+1)))
232 	    return (*st)-'A'+1;
233 
234 	/* Nothing else understood at this time */
235 	return -1;
236     }
237     return -1;
238 }
239 
240 
241 
242 
243 
244 /*
245  * Paragraphs are easy, but get complicated due to need to work out
246  * which things are actually chapter headings, etc
247  */
fold_para(const tok_seq::tok * tok,const docfmt * fmt,FILE * out,void * d)248 static void fold_para(const tok_seq::tok *tok, const docfmt *fmt, FILE *out,
249 		      void *d)
250 {
251     tblock *b, *ts, op;
252     const char *s, *t, *pt;
253     struct latex_data *dp;
254     int do_add, has_num, i, j;
255 
256     static const char *const sects[]=
257     {
258 	"chapter", "section", "subsection", "subsubsection"
259     };
260 
261     dp=(struct latex_data *) d;
262     do_add=0;
263     dp->par_flg=1;
264 
265     /* Even this much is under 100%!! */
266     pt=(tok->data.d);
267 
268     if (*pt=='\0')
269 	return;
270 
271     if (dp->last_tc!=NULL)
272     {
273 	if (strcmp(dp->last_tc, pt)==0)
274 	{
275 	    op.add("\\addcontentsline{toc}{");
276 	    op.add(sects[dp->unit_d.unit_type]); op.add("}{");
277 	    op.add(dp->last_tc); op.add("}\n\\");
278 	    op.add(sects[dp->unit_d.unit_type]);
279 	    op.add("*{");
280 	    do_add=1;
281 	}
282 
283 	else
284 	{
285 	    s=dp->last_tc+strlen(dp->last_tc)-strlen(pt);
286 	    if (strcmp(s, pt)==0)
287 	    {
288 		/* Find type */
289 		for (i=0; i< (int) N(sects)-1; i++)
290 		{
291 		    if (strncasecmp(dp->last_tc, sects[i],
292 				    strlen(sects[i]))==0)
293 			break;
294 		}
295 		t=dp->last_tc+strlen(sects[i]);
296 		has_num=get_part_num(t,s);
297 		if (has_num==-1)
298 		{
299 		    op.add("\\addcontentsline{toc}{");
300 		    op.add(sects[i]); op.add("}{");
301 		    op.add(dp->last_tc);
302 		    op.add("}\n");
303 		}
304 		op.add('\\');
305 		op.add(sects[i]);
306 		op.add((has_num!=-1) ? "{" : "*{");
307 		if (dp->unit_d.unit_number[i]==-1)
308 		{
309 		    dp->unit_d.unit_number[i]=(has_num==-1) ? 1 : has_num;
310 		    for (j=i+1; j< (int) N(sects); j++)
311 			dp->unit_d.unit_number[j]=0;
312 		}
313 		if (i< (int) N(sects)-1)
314 		    dp->unit_d.unit_type=i+1;
315 		else
316 		    dp->unit_d.unit_type=i;
317 		do_add=1;
318 	    }
319 	}
320 	free((void *) dp->last_tc);
321 	dp->last_tc=NULL;
322     }
323     else
324     {
325 	if (dp->list_flg)
326 	{
327 	    op.add("\\item ");
328 	}
329 	else
330 	{
331 	    if (strlen(pt)>0 && strlen(pt)<PAR_TRESHOLD_LEN)
332 	    {
333 		if (strcasecmp(pt,"Appendix")==0)
334 		{
335 		    op.add("\\appendix\n\\");
336 		    dp->unit_d.unit_type=(dp->unit_d.unit_number[0]==-1) ? 1:0;
337 		    op.add(sects[dp->unit_d.unit_type]);
338 		    op.add("{");
339 		    do_add=1;
340 		    for (j=dp->unit_d.unit_type+1; j< (int) N(sects); j++)
341 			dp->unit_d.unit_number[j]=0;
342 		}
343 		else if (strcasecmp(pt,"Bibliography")==0)
344 		{
345 		    dp->unit_d.unit_type= (dp->unit_d.unit_number[0]==-1) ? 1:0;
346 		    op.add('\\');
347 		    op.add(sects[dp->unit_d.unit_type]);
348 		    op.add("*{");
349 		    do_add=1;
350 		    for (j=dp->unit_d.unit_type+1; j< (int) N(sects); j++)
351 			dp->unit_d.unit_number[j]=0;
352 		}
353 		else
354 		{
355 		    int i,n,c,l, unit;
356 
357 		    unit=dp->unit_d.unit_type-1;
358 		    l=strlen(pt);
359 		    i=0;
360 		    while(1)
361 		    {
362 			n=0;
363 			for (c=0; i<l && isdigit(pt[i]); i++, c++)
364 			    n=n*10+pt[i]-'0';
365 			if (c==0)
366 			    break;
367 			unit++;
368 			if (unit>= (int) N(sects))
369 			{
370 			    unit=N(sects)-1;
371 			    break;
372 			}
373 			if (dp->unit_d.unit_number[unit]==-1)
374 			{
375 			    if (n>MAX_START_NUM)
376 				goto out_normal;
377 
378 			    dp->unit_d.unit_number[unit]=n;
379 			    for (j=unit+1; j< (int) N(sects); j++)
380 				dp->unit_d.unit_number[j]=0;
381 			}
382 			else if (dp->unit_d.unit_number[unit]+1==n)
383 			{
384 			    dp->unit_d.unit_number[unit]++;
385 			    for (j=unit+1; j< (int) N(sects); j++)
386 				dp->unit_d.unit_number[j]=0;
387 			}
388 			else if (dp->unit_d.unit_number[unit]!=n)
389 			    goto out_normal;
390 
391 			if (pt[i]!='.')
392 			    break;
393 			i++;
394 		    }
395 
396 		    if (unit==dp->unit_d.unit_type-1)
397 			goto out_normal;
398 		    op.add('\\');
399 		    op.add(sects[unit]);
400 		    op.add((i>0) ? "{" : "*{");
401 		    while(isspace(pt[i])) i++;
402 		    pt+=i;
403 		    do_add=1;
404 		}
405 	    }
406 	out_normal: ;
407 	}
408 	dp->list_flg=0;
409     }
410 
411     ts=map_string(pt, tex_map);
412     op.add(*ts);
413     if (do_add)
414 	op.add('}');
415     delete(ts);
416 
417     b=word_wrap(op, "\n", "\n", fmt->maxline, 0);
418     fputs((*b), out);
419     delete(b);
420 }
421 
422 /* End of paragraph */
end_para(const tok_seq::tok * tok,const docfmt * fmt,FILE * out,void * d)423 static void end_para(const tok_seq::tok *tok, const docfmt *fmt, FILE *out,
424 		     void *d)
425 {
426     struct latex_data *dp;
427 
428     tok=tok;
429     fmt=fmt;
430     dp=(struct latex_data *) d;
431     dp->par_flg=0;
432 
433     fputs("\n\n", out);
434 }
435 
436 /* Start a table === allocate table and initialise */
alloc_tbl(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)437 static void alloc_tbl(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
438 		      void *d)
439 {
440     struct latex_data *tdata;
441 
442     out=out;
443     fmt=fmt;
444     tdata=(struct latex_data *) d;
445     tdata->col=0;
446     tdata->row=0;
447     tdata->tabl=new(latex_table)(t->data.table.cols, t->data.table.rows);
448     tdata->par_flg=0;
449 }
450 
451 
452 /* End of a table==print the table */
format_tbl(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)453 static void format_tbl(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
454 		       void *d)
455 {
456     struct latex_data *tdata;
457 
458     t=t;
459     tdata=(struct latex_data *) d;
460     tdata->tabl->print_table(fmt->maxline, out); // Print table
461     delete(tdata->tabl);
462     tdata->tabl=NULL;
463 }
464 
465 /* start row==set column to 0 */
start_row(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)466 static void start_row(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
467 		      void *d)
468 {
469     struct latex_data *tdata;
470 
471     out=out;
472     fmt=fmt;
473     t=t;
474     tdata=(struct latex_data *) d;
475     tdata->col=0;
476 }
477 
478 /* end row==add one to row */
inc_row(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)479 static void inc_row(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
480 		    void *d)
481 {
482     struct latex_data *tdata;
483 
484     fmt=fmt;
485     t=t;
486     out=out;
487     tdata=(struct latex_data *) d;
488     tdata->row++;
489 }
490 
491 
492 /* Start field === set field */
set_field(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)493 static void set_field(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
494 		      void *d)
495 {
496     struct latex_data *tdata;
497 
498     tdata=(struct latex_data *) d;
499     out=out;
500     fmt=fmt;
501     tdata->tabl->set(tdata->col, tdata->row, t->data.d);
502 }
503 
504 /* end field==add one to col */
inc_col(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)505 static void inc_col(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
506 		    void *d)
507 {
508     struct latex_data *tdata;
509 
510     out=out;
511     fmt=fmt;
512     t=t;
513     tdata=(struct latex_data *) d;
514     tdata->col++;
515 }
516 
517 /* pointers to the functions that do the work */
518 docfmt latexfmt=
519 {
520     { 0 },			    // Ignore page breaks
521     76,				    // Width
522     "\n",			    // Use \n as line ends
523     allocate_latex,		    // Allocate space
524     free_latex,			    // Free text
525     {
526 	{ preamble, postamble },    // End and start of document---do nothing
527 	{ fold_para, end_para },    // Paragraph
528 	{ alloc_tbl, format_tbl },  // Start/end table
529 	{ set_field, inc_col },	    // Start/end field
530 	{ start_row, inc_row },	    // Start/end row
531 	{ ltx_embed, null_proc },   // Throw away embed messages
532 	{ ltx_list, ltx_end_list }, // Start/end list
533 	{ ltx_item, null_proc },    // Start/end item
534 	{ ltx_code, null_proc },    // Codes end do not happen
535 	{ null_proc, null_proc }    // Do not understanding anything else
536     }
537 };
538