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