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