1 /* main.c - LaTeX to RTF conversion program
2
3 Copyright (C) 1995-2017 The Free Software Foundation
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19 This file is available from http://sourceforge.net/projects/latex2rtf/
20
21 Authors:
22 1995 Fernando Dorner, Andreas Granzer, Freidrich Polzer, Gerhard Trisko
23 1995-1997 Ralf Schlatterbeck
24 1998-2000 Georg Lehner
25 2001-2007 Scott Prahl
26 */
27 #if defined(NOSTDERR)
28 #define ERROUT stdout
29 #else
30 #define ERROUT stderr
31 #endif
32
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <errno.h>
39 #include "main.h"
40 #include "mygetopt.h"
41 #include "convert.h"
42 #include "commands.h"
43 #include "chars.h"
44 #include "fonts.h"
45 #include "stack.h"
46 #include "direct.h"
47 #include "ignore.h"
48 #include "version.h"
49 #include "funct1.h"
50 #include "cfg.h"
51 #include "encodings.h"
52 #include "utils.h"
53 #include "parser.h"
54 #include "lengths.h"
55 #include "counters.h"
56 #include "preamble.h"
57 #include "xrefs.h"
58 #include "preparse.h"
59 #include "vertical.h"
60 #include "fields.h"
61
62 FILE *fRtf = NULL; /* file pointer to RTF file */
63 char *g_tex_name = NULL;
64 char *g_rtf_name = NULL;
65 char *g_aux_name = NULL;
66 char *g_toc_name = NULL;
67 char *g_lof_name = NULL;
68 char *g_lot_name = NULL;
69 char *g_fff_name = NULL;
70 char *g_ttt_name = NULL;
71 char *g_bbl_name = NULL;
72 char *g_home_dir = NULL;
73
74 char *progname; /* name of the executable file */
75 int SpanishMode = FALSE; /* support spanishstyle */
76 int GermanMode = FALSE; /* support germanstyle */
77 int FrenchMode = FALSE; /* support frenchstyle */
78 int RussianMode = FALSE; /* support russianstyle */
79 int CzechMode = FALSE; /* support czech */
80
81 int twoside = FALSE;
82 int g_verbosity_level = WARNING;
83 int g_little_endian = FALSE; /* set properly in main() */
84 uint16_t g_dots_per_inch = 300;
85
86 int pagenumbering = TRUE; /* by default use plain style */
87 int headings = FALSE;
88
89 int g_processing_preamble = TRUE; /* flag set until \begin{document} */
90 int g_processing_figure = FALSE; /* flag, set for figures and not tables */
91 int g_processing_eqnarray = FALSE; /* flag set when in an eqnarry */
92 int g_processing_arrays = 0;
93
94 int g_show_equation_number = FALSE;
95 int g_enumerate_depth = 0;
96 int g_suppress_equation_number = FALSE;
97 int g_aux_file_missing = FALSE; /* assume that it exists */
98 int g_bbl_file_missing = FALSE; /* assume that it exists */
99
100 int g_document_type = FORMAT_ARTICLE;
101 int g_document_bibstyle = BIBSTYLE_STANDARD;
102
103 int g_safety_braces = 0;
104 int g_processing_equation = FALSE;
105 int g_RTF_warnings = FALSE;
106 char *g_config_path = NULL;
107 char *g_script_dir = NULL;
108 char *g_tmp_dir = NULL;
109 char *g_preamble = NULL;
110 int g_escape_parens = FALSE;
111 char *g_package_babel = NULL;
112
113 int g_equation_display_rtf = TRUE;
114 int g_equation_inline_rtf = TRUE;
115 int g_equation_inline_bitmap = FALSE;
116 int g_equation_display_bitmap = FALSE;
117 int g_equation_comment = FALSE;
118 int g_equation_raw_latex = FALSE;
119 int g_equation_inline_eps = FALSE;
120 int g_equation_display_eps = FALSE;
121 int g_equation_mtef = FALSE;
122
123 int g_figure_include_direct = TRUE;
124 int g_figure_include_converted = TRUE;
125 int g_figure_comment_direct = FALSE;
126 int g_figure_comment_converted = FALSE;
127
128 int g_tableofcontents = FALSE;
129
130 int g_tabular_display_rtf = TRUE;
131 int g_tabular_display_bitmap = FALSE;
132 int g_tab_counter = 0;
133 int g_processing_table = FALSE;
134 int g_processing_tabbing = FALSE;
135 int g_processing_tabular = FALSE;
136
137 double g_png_equation_scale = 1.00;
138 double g_png_figure_scale = 1.00;
139 int g_latex_figures = FALSE;
140 int g_endfloat_figures = FALSE;
141 int g_endfloat_tables = FALSE;
142 int g_endfloat_markers = TRUE;
143 int g_graphics_package = GRAPHICS_NONE;
144
145 int indent = 0;
146 char alignment = JUSTIFIED; /* default for justified: */
147
148 int RecursionLevel = 0;
149 int twocolumn = FALSE;
150 int titlepage = FALSE;
151
152 static void OpenRtfFile(char *filename, FILE ** f);
153 static void CloseRtf(FILE ** f);
154 static void ConvertLatexPreamble(void);
155 static void InitializeLatexLengths(void);
156
157 static void SetEndianness(void);
158 static void ConvertWholeDocument(void);
159 static void print_usage(void);
160 static void print_version(void);
161
162 extern char *optarg;
163 extern int optind;
164
main(int argc,char ** argv)165 int main(int argc, char **argv)
166 {
167 int c, x;
168 char *p;
169 char *basename = NULL;
170 double xx;
171
172 SetEndianness();
173 progname = argv[0];
174
175 InitializeStack();
176 InitializeLatexLengths();
177 InitializeBibliography();
178
179 while ((c = my_getopt(argc, argv, "lhpuvFSVWZ:o:a:b:d:f:i:s:u:C:D:E:M:P:T:t:")) != EOF) {
180 switch (c) {
181 case 'a':
182 g_aux_name = optarg;
183 break;
184 case 'b':
185 g_bbl_name = optarg;
186 break;
187 case 'd':
188 g_verbosity_level = *optarg - '0';
189 if (g_verbosity_level < 0 || g_verbosity_level > 7) {
190 diagnostics(WARNING, "debug level (-d# option) must be 0-7");
191 print_usage();
192 }
193 break;
194 case 'f':
195 sscanf(optarg, "%d", &x);
196 set_fields_use_EQ(x & 1);
197 set_fields_use_REF(x & 2);
198 break;
199 case 'i':
200 g_package_babel = strdup(optarg);
201 break;
202 case 'l':
203 g_package_babel = strdup("latin");
204 break;
205 case 'o':
206 g_rtf_name = strdup(optarg);
207 break;
208 case 'p':
209 g_escape_parens = TRUE;
210 break;
211 case 'v':
212 print_version();
213 return (0);
214 case 'C':
215 setPackageInputenc(optarg);
216 break;
217 case 'D':
218 sscanf(optarg, "%d", &x);
219 g_dots_per_inch = (uint16_t) x;
220 if (g_dots_per_inch < 25 || g_dots_per_inch > 600)
221 diagnostics(WARNING, "Dots per inch must be between 25 and 600 dpi\n");
222 break;
223 case 'E':
224 sscanf(optarg, "%d", &x);
225 diagnostics(3, "Figure option = %s x=%d", optarg, x);
226 g_figure_include_direct = (x & 1) ? TRUE : FALSE;
227 g_figure_include_converted = (x & 2) ? TRUE : FALSE;
228 g_figure_comment_direct = (x & 4) ? TRUE : FALSE;
229 g_figure_comment_converted = (x & 8) ? TRUE : FALSE;
230 diagnostics(3, "Option g_figure_include_direct = %d", g_figure_include_direct);
231 diagnostics(3, "Option g_figure_include_converted = %d", g_figure_include_converted);
232 diagnostics(3, "Option g_figure_comment_direct = %d", g_figure_comment_direct);
233 diagnostics(3, "Option g_figure_comment_converted = %d", g_figure_comment_converted);
234 break;
235 case 'F':
236 g_latex_figures = TRUE;
237 break;
238 case 'M':
239 sscanf(optarg, "%d", &x);
240 diagnostics(3, "Math option = %s x=%d", optarg, x);
241 g_equation_display_rtf = (x & 1) ? TRUE : FALSE;
242 g_equation_inline_rtf = (x & 2) ? TRUE : FALSE;
243 g_equation_display_bitmap= (x & 4) ? TRUE : FALSE;
244 g_equation_inline_bitmap = (x & 8) ? TRUE : FALSE;
245 g_equation_comment = (x & 16) ? TRUE : FALSE;
246 g_equation_raw_latex = (x & 32) ? TRUE : FALSE;
247 g_equation_display_eps = (x & 64) ? TRUE : FALSE;
248 g_equation_inline_eps = (x & 128)? TRUE : FALSE;
249 g_equation_mtef = (x & 256)? TRUE : FALSE;
250 if (!g_equation_comment && !g_equation_inline_rtf && !g_equation_inline_bitmap && !g_equation_raw_latex && !g_equation_inline_eps)
251 g_equation_inline_rtf = TRUE;
252 if (!g_equation_comment && !g_equation_display_rtf && !g_equation_display_bitmap && !g_equation_raw_latex && !g_equation_display_eps)
253 g_equation_display_rtf = TRUE;
254 diagnostics(3, "Math option g_equation_display_rtf = %d", g_equation_display_rtf);
255 diagnostics(3, "Math option g_equation_inline_rtf = %d", g_equation_inline_rtf);
256 diagnostics(3, "Math option g_equation_display_bitmap = %d", g_equation_display_bitmap);
257 diagnostics(3, "Math option g_equation_inline_bitmap = %d", g_equation_inline_bitmap);
258 diagnostics(3, "Math option g_equation_comment = %d", g_equation_comment);
259 diagnostics(3, "Math option g_equation_raw_latex = %d", g_equation_raw_latex);
260 diagnostics(3, "Math option g_equation_display_eps = %d", g_equation_display_eps);
261 diagnostics(3, "Math option g_equation_inline_eps = %d", g_equation_inline_eps);
262 break;
263
264 case 't':
265 sscanf(optarg, "%d", &x);
266 diagnostics(3, "Table option = %s x=%d", optarg, x);
267 g_tabular_display_rtf = (x & 1) ? TRUE : FALSE;
268 g_tabular_display_bitmap = (x & 2) ? TRUE : FALSE;
269 diagnostics(3, "Table option g_tabular_display_rtf = %d", g_tabular_display_rtf);
270 diagnostics(3, "Table option g_tabular_display_bitmap = %d", g_tabular_display_bitmap);
271 break;
272
273 case 'P': /* -P path/to/cfg:path/to/script or -P path/to/cfg or -P :path/to/script */
274 p = strchr(optarg, ENVSEP);
275 if (p) {
276 *p = '\0';
277 g_script_dir = strdup(p + 1);
278 }
279 if (p != optarg)
280 g_config_path = strdup(optarg);
281 diagnostics(2, "cfg=%s, script=%s", g_config_path, g_script_dir);
282 break;
283
284 case 's':
285 if (optarg && optarg[0] == 'e') {
286 if (sscanf(optarg, "e%lf", &xx) == 1 && xx > 0) {
287 g_png_equation_scale = xx;
288 } else {
289 diagnostics(WARNING, "Mistake in command line number for scaling equations");
290 diagnostics(WARNING, "Either use no spaces: '-se1.22' or write as '-s e1.22'");
291 }
292
293 } else if (optarg && optarg[0] == 'f') {
294
295 if (sscanf(optarg, "f%lf", &xx) == 1 && xx > 0) {
296 g_png_figure_scale = xx;
297 } else {
298 diagnostics(WARNING, "Mistake in command line number for scaling figures");
299 diagnostics(WARNING, "Either use no spaces: '-sf1.35' or write as '-s f1.35'");
300 }
301 } else {
302 diagnostics(WARNING, "Unknown option '-s' use '-se#' or '-sf#'");
303 }
304 break;
305
306 case 'S':
307 g_field_separator = ';';
308 break;
309 case 'T':
310 g_tmp_dir = strdup(optarg);
311 break;
312 case 'V':
313 print_version();
314 return (0);
315 case 'W':
316 g_RTF_warnings = TRUE;
317 break;
318 case 'Z':
319 g_safety_braces = FALSE;
320 g_safety_braces = *optarg - '0';
321 if (g_safety_braces < 0 || g_safety_braces > 9) {
322 diagnostics(WARNING, "Number of safety braces (-Z#) must be 0-9");
323 print_usage();
324 }
325 break;
326
327 case 'h':
328 case '?':
329 default:
330 print_usage();
331 }
332 }
333
334 argc -= optind;
335 argv += optind;
336
337 if (argc > 1) {
338 diagnostics(WARNING, "Only a single file can be processed at a time");
339 diagnostics(ERROR, " Type \"latex2rtf -h\" for help");
340 }
341
342 /* Parse filename. Extract directory if possible. Beware of stdin cases */
343
344 if (argc == 1 && strcmp(*argv, "-") != 0) { /* filename exists and != "-" */
345 char *s, *t, *ext;
346
347 basename = strdup(*argv); /* parse filename */
348 s = strrchr(basename, PATHSEP);
349 if (s != NULL) {
350 g_home_dir = strdup(basename); /* parse /tmp/file.tex */
351 t = strdup(s + 1);
352 free(basename);
353 basename = t; /* basename = file.tex */
354 s = strrchr(g_home_dir, PATHSEP);
355 *(s + 1) = '\0'; /* g_home_dir = /tmp/ */
356 }
357
358 /* remove .tex or .ltx if present */
359 ext = basename + strlen(basename) - 4;
360 if (strcmp(ext, ".tex") == 0 || strcmp(ext, ".ltx") == 0) {
361 g_tex_name = strdup(basename);
362 *ext = '\0';
363 } else
364 g_tex_name = strdup_together(basename, ".tex");
365
366 if (g_rtf_name == NULL) {
367 g_rtf_name = strdup_together3(g_home_dir,basename,".rtf");
368 } else if (strcmp(g_rtf_name, g_tex_name) == 0) {
369 diagnostics(ERROR, "rtf file must be different from tex file");
370 }
371 }
372
373
374 if (g_aux_name == NULL && basename != NULL)
375 g_aux_name = strdup_together(basename, ".aux");
376
377 if (g_bbl_name == NULL && basename != NULL)
378 g_bbl_name = strdup_together(basename, ".bbl");
379
380 if (g_toc_name == NULL && basename != NULL)
381 g_toc_name = strdup_together(basename, ".toc");
382
383 if (g_lof_name == NULL && basename != NULL)
384 g_lof_name = strdup_together(basename, ".lof");
385
386 if (g_lot_name == NULL && basename != NULL)
387 g_lot_name = strdup_together(basename, ".lot");
388
389 if (g_fff_name == NULL && basename != NULL)
390 g_fff_name = strdup_together(basename, ".fff");
391
392 if (g_ttt_name == NULL && basename != NULL)
393 g_ttt_name = strdup_together(basename, ".ttt");
394
395 if (basename) {
396 diagnostics(2, "latex filename is <%s>", g_tex_name);
397 diagnostics(2, " rtf filename is <%s>", g_rtf_name);
398 diagnostics(2, " aux filename is <%s>", g_aux_name);
399 diagnostics(2, " bbl filename is <%s>", g_bbl_name);
400 diagnostics(2, "home directory is <%s>", (g_home_dir) ? g_home_dir : "");
401 }
402
403 ReadCfg();
404
405 if (PushSource(g_tex_name, NULL) == 0) {
406 OpenRtfFile(g_rtf_name, &fRtf);
407
408 InitializeDocumentFont(TexFontNumber("Roman"), 20, F_SHAPE_UPRIGHT, F_SERIES_MEDIUM, ENCODING_1252);
409 PushTrackLineNumber(TRUE);
410
411 ConvertWholeDocument();
412 PopSource();
413 CloseRtf(&fRtf);
414 printf("\n");
415
416 if (0) debug_malloc();
417
418 return 0;
419 } else {
420 printf("\n");
421 return 1;
422 }
423 }
424
SetEndianness(void)425 static void SetEndianness(void)
426
427 /*
428 purpose : Figure out endianness of machine. Needed for graphics support
429 */
430 {
431 unsigned int endian_test = (unsigned int) 0xaabbccdd;
432 unsigned char endian_test_char = *(unsigned char *) &endian_test;
433
434 if (endian_test_char == 0xdd)
435 g_little_endian = TRUE;
436 }
437
438
ConvertWholeDocument(void)439 static void ConvertWholeDocument(void)
440 {
441 char *body, *sec_head, *sec_head2, *label;
442 char t[] = "\\begin{document}";
443
444 PushEnvironment(DOCUMENT_MODE); /* because we use ConvertString in preamble.c */
445 PushEnvironment(PREAMBLE_MODE);
446 setTexMode(MODE_VERTICAL);
447 ConvertLatexPreamble();
448 setPackageBabel(g_package_babel);
449
450 WriteRtfHeader();
451 ConvertString(t);
452
453 g_processing_preamble = FALSE;
454 preParse(&body, &sec_head, &label);
455
456 diagnostics(2, "\\begin{document}");
457 diagnostics(5,"label for this section is'%s'", label);
458 diagnostics(5, "next section '%s'", sec_head);
459 show_string(2, body, "body ");
460
461 ConvertString(body);
462 free(body);
463 if (label)
464 free(label);
465
466 while (strcmp(sec_head,"\\end{document}")!=0) {
467 preParse(&body, &sec_head2, &g_section_label);
468 label = ExtractLabelTag(sec_head);
469 if (label) {
470 if (g_section_label)
471 free(g_section_label);
472 g_section_label = label;
473 }
474
475 diagnostics(2, "processing '%s'", sec_head);
476 diagnostics(5, "label is '%s'", g_section_label);
477 diagnostics(5, "next is '%s'", sec_head2);
478 show_string(2, body, "body ");
479
480 ConvertString(sec_head);
481 ConvertString(body);
482 free(body);
483 free(sec_head);
484 sec_head = sec_head2;
485 }
486
487 if (g_endfloat_figures && g_fff_name) {
488 g_endfloat_figures = FALSE;
489 if (PushSource(g_fff_name, NULL) == 0) {
490 CmdNewPage(NewPage);
491 CmdListOf(LIST_OF_FIGURES);
492 Convert();
493 }
494 }
495
496 if (g_endfloat_tables && g_ttt_name) {
497 g_endfloat_tables = FALSE;
498 if (PushSource(g_ttt_name, NULL) == 0) {
499 CmdNewPage(NewPage);
500 CmdListOf(LIST_OF_TABLES);
501 Convert();
502 }
503 }
504
505 if (strcmp(sec_head,"\\end{document}")==0) {
506 diagnostics(2, "\\end{document}");
507 ConvertString(sec_head);
508 }
509 }
510
print_version(void)511 static void print_version(void)
512 {
513 fprintf(stdout, "latex2rtf %s\n\n", Version);
514 fprintf(stdout, "Copyright (C) 2012 Free Software Foundation, Inc.\n");
515 fprintf(stdout, "This is free software; see the source for copying conditions. There is NO\n");
516 fprintf(stdout, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
517 fprintf(stdout, "Written by Prahl, Lehner, Granzer, Dorner, Polzer, Trisko, Schlatterbeck.\n");
518
519 /* fprintf(stdout, "RTFPATH = '%s'\n", getenv("RTFPATH"));*/
520 }
521
print_usage(void)522 static void print_usage(void)
523 {
524 char *s;
525
526 fprintf(stdout, "`%s' converts text files in LaTeX format to rich text format (RTF).\n\n", progname);
527 fprintf(stdout, "Usage: %s [options] input[.tex]\n\n", progname);
528 fprintf(stdout, "Options:\n");
529 fprintf(stdout, " -a auxfile use LaTeX auxfile rather than input.aux\n");
530 fprintf(stdout, " -b bblfile use BibTex bblfile rather than input.bbl\n");
531 fprintf(stdout, " -C codepage charset used by the latex document (latin1, cp850, raw, etc.)\n");
532 fprintf(stdout, " -d level debugging output (level is 0-6)\n");
533 fprintf(stdout, " -D dpi number of dots per inch for bitmaps\n");
534 fprintf(stdout, " -E# figure handling\n");
535 fprintf(stdout, " -E0 do not include any figures in RTF\n");
536 fprintf(stdout, " -E1 include figures that need no conversion\n");
537 fprintf(stdout, " -E2 include figures that need conversion\n");
538 fprintf(stdout, " -E3 include all figures (default)\n");
539 fprintf(stdout, " -E4 insert filenames for figures that do not need conversion\n");
540 fprintf(stdout, " -E8 insert filenames for figures that need conversion\n");
541 fprintf(stdout, " -f# field handling\n");
542 fprintf(stdout, " -f0 do not use fields\n");
543 fprintf(stdout, " -f1 use fields for equations but not \\ref{} & \\cite{}\n");
544 fprintf(stdout, " -f2 use fields for \\cite{} & \\ref{}, but not equations\n");
545 fprintf(stdout, " -f3 use fields when possible (default)\n");
546 fprintf(stdout, " -F use LaTeX to convert all figures to bitmaps\n");
547 fprintf(stdout, " -h display help\n");
548 fprintf(stdout, " -i language idiom or language (e.g., german, french)\n");
549 fprintf(stdout, " -l use latin1 encoding (default)\n");
550 fprintf(stdout, " -M# math equation handling\n");
551 fprintf(stdout, " -M1 displayed equations to RTF\n");
552 fprintf(stdout, " -M2 inline equations to RTF\n");
553 fprintf(stdout, " -M3 inline and displayed equations to RTF (default)\n");
554 fprintf(stdout, " -M4 displayed equations to bitmap\n");
555 fprintf(stdout, " -M6 inline equations to RTF and displayed equations to bitmaps\n");
556 fprintf(stdout, " -M8 inline equations to bitmap\n");
557 fprintf(stdout, " -M12 inline and displayed equations to bitmaps\n");
558 fprintf(stdout, " -M16 insert Word comment field containing the raw LaTeX equation\n");
559 fprintf(stdout, " -M32 insert raw LaTeX equation delimited by $...$ and \\[...\\]\n");
560 fprintf(stdout, " -M64 displayed equations to EPS files with filenames in RTF\n");
561 fprintf(stdout, " -M128 inline equations to EPS files with filenames in RTF\n");
562 fprintf(stdout, " -o outputfile file for RTF output\n");
563 fprintf(stdout, " -p option to avoid bug in Word for some equations\n");
564 fprintf(stdout, " -P path paths to *.cfg & latex2png\n");
565 fprintf(stdout, " -S use ';' to separate args in RTF fields\n");
566 fprintf(stdout, " -se# scale factor for bitmap equations\n");
567 fprintf(stdout, " -sf# scale factor for bitmap figures\n");
568 fprintf(stdout, " -t# table handling\n");
569 fprintf(stdout, " -t1 tabular and tabbing environments as RTF\n");
570 fprintf(stdout, " -t2 tabular and tabbing environments as bitmaps\n");
571 fprintf(stdout, " -T /path/to/tmp temporary directory\n");
572 fprintf(stdout, " -v version information\n");
573 fprintf(stdout, " -V version information\n");
574 fprintf(stdout, " -W include warnings in RTF\n");
575 fprintf(stdout, " -Z# add # of '}'s at end of rtf file (# is 0-9)\n\n");
576 fprintf(stdout, "Examples:\n");
577 fprintf(stdout, " latex2rtf foo convert foo.tex to foo.rtf\n");
578 fprintf(stdout, " latex2rtf <foo >foo.RTF convert foo to foo.RTF\n");
579 fprintf(stdout, " latex2rtf -P ./cfg/:./scripts/ foo use alternate cfg and latex2png files\n");
580 fprintf(stdout, " latex2rtf -M12 foo replace equations with bitmaps\n");
581 fprintf(stdout, " latex2rtf -t3 foo tables as RTF *and* bitmaps\n");
582 fprintf(stdout, " latex2rtf -i russian foo assume russian tex conventions\n");
583 fprintf(stdout, " latex2rtf -C raw foo retain font encoding in rtf file\n");
584 fprintf(stdout, " latex2rtf -f0 foo create foo.rtf without fields\n");
585 fprintf(stdout, " latex2rtf -d4 foo lots of debugging information\n\n");
586 fprintf(stdout, "Report bugs to <latex2rtf-developers@lists.sourceforge.net>\n\n");
587 fprintf(stdout, "$RTFPATH designates the directory for configuration files (*.cfg)\n");
588 s = getenv("RTFPATH");
589 fprintf(stdout, "$RTFPATH = '%s'\n\n", (s) ? s : "not defined");
590 s = CFGDIR;
591 fprintf(stdout, "CFGDIR compiled-in directory for configuration files (*.cfg)\n");
592 fprintf(stdout, "CFGDIR = '%s'\n\n", (s) ? s : "not defined");
593 fprintf(stdout, "latex2rtf %s\n", Version);
594 exit(1);
595 }
596
diagnostics(int level,char * format,...)597 void diagnostics(int level, char *format, ...)
598
599 /****************************************************************************
600 purpose: Writes the message to stderr depending on debugging level
601 ****************************************************************************/
602 {
603 static int first = TRUE;
604
605 char buffer[512], *buff_ptr;
606 va_list apf;
607 int i;
608
609 buff_ptr = buffer;
610
611 va_start(apf, format);
612
613 if (level <= g_verbosity_level) {
614
615 CurrentEnvironmentCount();
616
617 if (!first) fprintf(ERROUT,"\n");
618
619 fprintf(ERROUT, "%s:%-3d ",CurrentFileName(),CurrentLineNumber());
620 switch (level) {
621 case 0:
622 fprintf(ERROUT, "Error! ");
623 break;
624 case 1:
625 if (g_RTF_warnings) {
626 vsnprintf(buffer, 512, format, apf);
627 fprintRTF("{\\plain\\cf2 [latex2rtf:");
628 while (*buff_ptr) {
629 putRtfCharEscaped(*buff_ptr);
630 buff_ptr++;
631 }
632 fprintRTF("]}");
633 }
634 break;
635 case 5:
636 case 6:
637 fprintf(ERROUT, " rec=%d ", RecursionLevel);
638 /*fall through */
639 case 2:
640 case 3:
641 case 4:
642 for (i = 0; i < BraceLevel; i++)
643 fprintf(ERROUT, "{");
644 for (i = 8; i > BraceLevel; i--)
645 fprintf(ERROUT, " ");
646
647 for (i = 0; i < RecursionLevel; i++)
648 fprintf(ERROUT, " ");
649 break;
650 default:
651 break;
652 }
653 vfprintf(ERROUT, format, apf);
654 first = FALSE;
655 }
656 va_end(apf);
657
658 if (level == 0) {
659 fprintf(ERROUT, "\n");
660 fflush(ERROUT);
661 if (fRtf)
662 fflush(fRtf);
663
664 exit(EXIT_FAILURE);
665 }
666 }
667
InitializeLatexLengths(void)668 static void InitializeLatexLengths(void)
669 {
670 /* Default Page Sizes */
671 setLength("pageheight", 795 * 20);
672 setLength("hoffset", 0 * 20);
673 setLength("oddsidemargin", 62 * 20);
674 setLength("headheight", 12 * 20);
675 setLength("textheight", 550 * 20);
676 setLength("footskip", 30 * 20);
677 setLength("marginparpush", 5 * 20);
678
679 setLength("pagewidth", 614 * 20);
680 setLength("voffset", 0 * 20);
681 setLength("topmargin", 18 * 20);
682 setLength("headsep", 25 * 20);
683 setLength("textwidth", 345 * 20);
684 setLength("columnwidth", 345 * 20);
685 setLength("linewidth", 345 * 20);
686 setLength("columnsep", 10 * 20);
687 setLength("evensidemargin", 11 * 20);
688
689 /* Default Paragraph Sizes */
690 setLength("baselineskip", 12 * 20);
691 setLength("parindent", 15 * 20);
692 setLength("parskip", 0 * 20);
693
694 setCounter("page", 0);
695 setCounter("part", 0);
696 setCounter("chapter", 0);
697 setCounter("section", 0);
698 setCounter("subsection", 0);
699 setCounter("subsubsection", 0);
700 setCounter("paragraph", 0);
701 setCounter("subparagraph", 0);
702 setCounter("figure", 0);
703 setCounter("table", 0);
704 setCounter("equation", 0);
705 setCounter("footnote", 0);
706 setCounter("mpfootnote", 0);
707 setCounter("secnumdepth", 2);
708 setCounter("endfloatfigure", 0);
709 setCounter("endfloattable", 0);
710
711 /* vertical separation lengths */
712 setLength("topsep", 3 * 20);
713 setLength("partopsep", 2 * 20);
714 setLength("parsep", (int) (2.5 * 20));
715 setLength("itemsep", 0 * 20);
716 setLength("labelwidth", 0 * 20);
717 setLength("labelsep", 0 * 20);
718 setLength("itemindent", 0 * 20);
719 setLength("listparindent", 0 * 20);
720 setLength("leftmargin", 0 * 20);
721 setLength("floatsep", 0 * 20);
722 setLength("intextsep", 0 * 20);
723 setLength("textfloatsep", 0 * 20);
724 setLength("abovedisplayskip", 0 * 20);
725 setLength("belowdisplayskip", 0 * 20);
726 setLength("abovecaptionskip", 0 * 20);
727 setLength("belowcaptionskip", 0 * 20);
728 setLength("intextsep", 0 * 20);
729
730 setLength("smallskipamount", 3 * 20);
731 setLength("medskipamount", 6 * 20);
732 setLength("bigskipamount", 12 * 20);
733
734 setLength("marginparsep", 10 * 20);
735 }
736
ConvertLatexPreamble(void)737 static void ConvertLatexPreamble(void)
738
739 /****************************************************************************
740 purpose: reads the LaTeX preamble (to \begin{document} ) for the file
741 ****************************************************************************/
742 {
743 char *raw_latex;
744 char t[] = "\\begin|{|document|}";
745 FILE *rtf_file;
746
747 /* Here we switch the file pointers ... it is important that nothing
748 get printed to fRtf until the entire preamble has been processed.
749 This is really hard to track down, so the processed RTF get sent
750 directly to stderr instead.
751 */
752 rtf_file = fRtf;
753 fRtf = ERROUT;
754
755 raw_latex = getSpacedTexUntil(t, 1);
756
757 diagnostics(2, "Read LaTeX Preamble");
758 diagnostics(5, "Entering ConvertString() from ConvertLatexPreamble");
759
760 g_preamble = strdup_nocomments(raw_latex);
761 free(raw_latex);
762
763 show_string(2, g_preamble, "preamble");
764
765 ConvertString(g_preamble);
766 diagnostics(5, "Exiting ConvertString() from ConvertLatexPreamble");
767 fRtf = rtf_file;
768 }
769
770
OpenRtfFile(char * filename,FILE ** f)771 void OpenRtfFile(char *filename, FILE ** f)
772
773 /****************************************************************************
774 purpose: creates output file and writes RTF-header.
775 params: filename - name of outputfile, possibly NULL for already open file
776 f - pointer to filepointer to store file ID
777 ****************************************************************************/
778 {
779 if (filename == NULL) {
780 diagnostics(4, "Writing RTF to stdout");
781 *f = stdout;
782
783 } else {
784
785 *f = fopen(filename, "w");
786
787 if (*f == NULL)
788 diagnostics(ERROR, "Error opening RTF file <%s>\n", filename);
789
790 diagnostics(2, "Opened RTF file <%s>", filename);
791 }
792 }
793
CloseRtf(FILE ** f)794 void CloseRtf(FILE ** f)
795
796 /****************************************************************************
797 purpose: closes output file.
798 params: f - pointer to filepointer to invalidate
799 globals: g_tex_name;
800 ****************************************************************************/
801 {
802 int i;
803
804 CmdEndParagraph(0);
805 if (BraceLevel > 1) {
806 diagnostics(WARNING, "Mismatched '{' in RTF file, Conversion may cause problems.");
807 diagnostics(WARNING, "This is often caused by having environments that span ");
808 diagnostics(WARNING, "\\section{}s. For example ");
809 diagnostics(WARNING, " \\begin{small} ... \\section{A} ... \\section{B} ... \\end{small}");
810 diagnostics(WARNING, "will definitely fail.");
811 }
812
813 if (BraceLevel - 1 > g_safety_braces)
814 diagnostics(WARNING, "Try translating with 'latex2rtf -Z%d %s'", BraceLevel - 1, g_tex_name);
815
816 fprintf(*f, "}\n");
817 for (i = 0; i < g_safety_braces; i++)
818 fprintf(*f, "}");
819 if (*f != stdout) {
820 if (fclose(*f) == EOF) {
821 diagnostics(WARNING, "Error closing RTF-File");
822 }
823 }
824 *f = NULL;
825 diagnostics(4, "Closed RTF file");
826 fprintf(ERROUT,"\n");
827 }
828
putRtfCharEscaped(char cThis)829 void putRtfCharEscaped(char cThis)
830
831 /****************************************************************************
832 purpose: output a single escaped character to the RTF file
833 this is primarily useful for the verbatim-like enviroments
834 ****************************************************************************/
835 {
836 if (getTexMode() == MODE_VERTICAL)
837 changeTexMode(MODE_HORIZONTAL);
838 if (cThis == '\\')
839 fprintRTF("%s","\\\\");
840 else if (cThis == '{')
841 fprintRTF("%s", "\\{");
842 else if (cThis == '}')
843 fprintRTF("%s", "\\}");
844 else if (cThis == '\n')
845 fprintRTF("%s", "\n\\par ");
846 else
847 fprintRTF("%c",cThis);
848 }
849
850 /****************************************************************************
851 purpose: output a string with escaped characters to the RTF file
852 this is primarily useful for the verbatim-like enviroments
853 ****************************************************************************/
putRtfStrEscaped(const char * string)854 void putRtfStrEscaped(const char * string)
855 {
856 char *s = (char *) string;
857 if (string == NULL) return;
858 while (*s) putRtfCharEscaped(*s++);
859 }
860
861
fprintRTF(char * format,...)862 void fprintRTF(char *format, ...)
863
864 /****************************************************************************
865 purpose: output a formatted string to the RTF file. It is assumed that the
866 formatted string has been properly escaped for the RTF file.
867 *ALL* output to the RTF file passes through this routine.
868 ****************************************************************************/
869 {
870 char buffer[1024];
871 unsigned char *text;
872 char last='\0';
873
874 va_list apf;
875
876 va_start(apf, format);
877 vsnprintf(buffer, 1024, format, apf);
878 va_end(apf);
879 text = (unsigned char *) buffer;
880
881 while (*text) {
882
883 WriteEightBitChar(text[0], fRtf);
884
885 if (*text == '{' && last != '\\')
886 PushFontSettings();
887
888 if (*text == '}' && last != '\\')
889 PopFontSettings();
890
891 if (*text == '\\' && last != '\\')
892 MonitorFontChanges(text);
893
894 last= *text;
895 text++;
896 }
897 }
898
getTmpPath(void)899 char *getTmpPath(void)
900
901 /****************************************************************************
902 purpose: return the directory to store temporary files
903 ****************************************************************************/
904 {
905 size_t n;
906 char *t = NULL;
907 char *u = NULL;
908 char pathsep_str[2] = { PATHSEP, 0 };
909
910 #if defined(MSDOS)
911 /* first use any temporary directory specified as an option */
912 if (g_tmp_dir) {
913 t = strdup(g_tmp_dir);
914
915 /* next try the environment variable TMPDIR */
916 } else {
917 u = getenv("TMPDIR");
918 if (u != NULL)
919 t = strdup(u);
920 }
921
922 /* finally just return ".\\" */
923 if (t==NULL)
924 t = strdup(".\\");
925
926 /* append a final '/' if missing */
927
928 n=strlen(t)-1;
929
930 if (n > 1 && t[n] != PATHSEP) {
931 u = strdup_together(t, pathsep_str);
932 free(t);
933 t = u;
934 }
935
936 #else
937 /* first use any temporary directory specified as an option */
938 if (g_tmp_dir) {
939 t = strdup(g_tmp_dir);
940
941 /* next try the environment variable TMPDIR */
942 } else {
943 u = getenv("TMPDIR");
944 if (u != NULL)
945 t = strdup(u);
946 }
947
948 /* finally just return "/tmp/" */
949 if (t==NULL)
950 t = strdup("/tmp/");
951
952 /* append a final '/' if missing */
953
954 n=strlen(t)-1;
955
956 if (n > 1 && t[n] != PATHSEP) {
957 u = strdup_together(t, pathsep_str);
958 free(t);
959 t = u;
960 }
961
962 #endif
963 return t;
964 }
965
my_strdup(const char * str)966 char *my_strdup(const char *str)
967
968 /****************************************************************************
969 purpose: duplicate string --- exists to ease porting
970 ****************************************************************************/
971 {
972 char *s = NULL;
973 unsigned long strsize;
974
975 strsize = strlen(str) + 1;
976 s = (char *) malloc(strsize);
977 *s = '\0';
978 if (s == NULL)
979 diagnostics(ERROR, "Cannot allocate memory to duplicate string");
980 my_strlcpy(s, str, strsize);
981 return s;
982 }
983
my_fopen(char * path,char * mode)984 FILE *my_fopen(char *path, char *mode)
985
986 /****************************************************************************
987 purpose: opens "g_home_dir/path" and
988 ****************************************************************************/
989 {
990 char *name;
991 FILE *p;
992
993 if (path == NULL || mode == NULL)
994 return (NULL);
995
996 if (g_home_dir == NULL)
997 name = strdup(path);
998 else
999 name = strdup_together(g_home_dir, path);
1000
1001 p = fopen(name, mode);
1002
1003 if (p == NULL) {
1004 if (strstr(path, ".tex") != NULL)
1005 p = (FILE *) open_cfg(path, FALSE);
1006 } else
1007 diagnostics(2, "Opened '%s'", name);
1008
1009 if (p == NULL) {
1010 diagnostics(WARNING, "Cannot open '%s'", name);
1011 fflush(NULL);
1012 }
1013
1014 free(name);
1015 return p;
1016 }
1017
debug_malloc(void)1018 void debug_malloc(void)
1019 {
1020 char c;
1021
1022 diagnostics(2, "Malloc Debugging --- press return to continue");
1023 fflush(NULL);
1024 if (2 <= g_verbosity_level) {
1025 fscanf(stdin, "%c", &c);
1026 c++;}
1027 }
1028