]> git.saurik.com Git - wxWidgets.git/blame - utils/tex2rtf/src/tex2any.cpp
don't lose fonts underlined flag in ReInit() (bug fix for the change in rev. 1.76)
[wxWidgets.git] / utils / tex2rtf / src / tex2any.cpp
CommitLineData
9a29912f
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: tex2any.cpp
3// Purpose: Utilities for Latex conversion.
4// Author: Julian Smart
5// Modified by:
6// Created: 01/01/99
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
23#ifndef WX_PRECOMP
9a29912f
JS
24#endif
25
26#include <ctype.h>
27#include "tex2any.h"
28#include <stdlib.h>
29#include <time.h>
30
ea172e69
MB
31#if !WXWIN_COMPATIBILITY_2_4
32static inline wxChar* copystring(const wxChar* s)
33 { return wxStrcpy(new wxChar[wxStrlen(s) + 1], s); }
34#endif
35
9a29912f
JS
36/*
37 * Variables accessible from clients
38 *
39 */
40
41TexChunk * DocumentTitle = NULL;
42TexChunk * DocumentAuthor = NULL;
43TexChunk * DocumentDate = NULL;
44
45// Header/footers/pagestyle
46TexChunk * LeftHeaderEven = NULL;
47TexChunk * LeftFooterEven = NULL;
48TexChunk * CentreHeaderEven = NULL;
49TexChunk * CentreFooterEven = NULL;
50TexChunk * RightHeaderEven = NULL;
51TexChunk * RightFooterEven = NULL;
52TexChunk * LeftHeaderOdd = NULL;
53TexChunk * LeftFooterOdd = NULL;
54TexChunk * CentreHeaderOdd = NULL;
55TexChunk * CentreFooterOdd = NULL;
56TexChunk * RightHeaderOdd = NULL;
57TexChunk * RightFooterOdd = NULL;
6c155d33 58wxChar * PageStyle = copystring(_T("plain"));
9a29912f
JS
59
60int DocumentStyle = LATEX_REPORT;
61int MinorDocumentStyle = 0;
62wxPathList TexPathList;
6c155d33
JS
63wxChar * BibliographyStyleString = copystring(_T("plain"));
64wxChar * DocumentStyleString = copystring(_T("report"));
65wxChar * MinorDocumentStyleString = NULL;
9a29912f
JS
66int ParSkip = 0;
67int ParIndent = 0;
68
69int normalFont = 10;
70int smallFont = 8;
71int tinyFont = 6;
72int largeFont1 = 12;
73int LargeFont2 = 14;
74int LARGEFont3 = 18;
75int hugeFont1 = 20;
76int HugeFont2 = 24;
77int HUGEFont3 = 28;
78
fad535ee
GT
79// All of these tokens MUST be found on a line by themselves (no other
80// text) and must start at the first character of the line, or tex2rtf
81// will fail to process them correctly (a limitation of tex2rtf, not TeX)
7cbe4e79 82static const wxString syntaxTokens[] =
6c155d33
JS
83{ _T("\\begin{verbatim}"),
84 _T("\\begin{toocomplex}"),
85 _T("\\end{verbatim}"),
86 _T("\\end{toocomplex}"),
87 _T("\\verb"),
88 _T("\\begin{comment}"),
89 _T("\\end{comment}"),
90 _T("\\verbatiminput"),
91// _T("\\par"),
92 _T("\\input"),
93 _T("\\helpinput"),
94 _T("\\include"),
fad535ee
GT
95 wxEmptyString
96};
97
98
9a29912f
JS
99/*
100 * USER-ADJUSTABLE SETTINGS
101 *
102 */
103
104// Section font sizes
105int chapterFont = 12; // LARGEFont3;
106int sectionFont = 12; // LargeFont2;
107int subsectionFont = 12; // largeFont1;
108int titleFont = LARGEFont3;
109int authorFont = LargeFont2;
110int mirrorMargins = TRUE;
111bool winHelp = FALSE; // Output in Windows Help format if TRUE, linear otherwise
112bool isInteractive = FALSE;
113bool runTwice = FALSE;
114int convertMode = TEX_RTF;
fad535ee
GT
115bool checkCurleyBraces = FALSE;
116bool checkSyntax = FALSE;
9a29912f
JS
117bool headerRule = FALSE;
118bool footerRule = FALSE;
119bool compatibilityMode = FALSE; // If TRUE, maximum Latex compatibility
120 // (Quality of RTF generation deteriorate)
121bool generateHPJ; // Generate WinHelp Help Project file
6c155d33 122wxChar *winHelpTitle = NULL; // Windows Help title
9a29912f
JS
123int defaultTableColumnWidth = 2000;
124
125int labelIndentTab = 18; // From left indent to item label (points)
126int itemIndentTab = 40; // From left indent to item (points)
127
128bool useUpButton = TRUE;
129int htmlBrowseButtons = HTML_BUTTONS_TEXT;
130
131bool truncateFilenames = FALSE; // Truncate for DOS
132int winHelpVersion = 3; // WinHelp Version (3 for Windows 3.1, 4 for Win95)
133bool winHelpContents = FALSE; // Generate .cnt file for WinHelp 4
134bool htmlIndex = FALSE; // Generate .htx file for HTML
135bool htmlFrameContents = FALSE; // Use frames for HTML contents page
6c155d33 136wxChar *htmlStylesheet = NULL; // Use this CSS stylesheet for HTML pages
9a29912f
JS
137bool useHeadingStyles = TRUE; // Insert \s1, s2 etc.
138bool useWord = TRUE; // Insert proper Word table of contents, etc etc
139int contentsDepth = 4; // Depth of Word table of contents
140bool indexSubsections = TRUE; // Index subsections in linear RTF
141// Linear RTF method of including bitmaps. Can be "includepicture", "hex"
6c155d33 142wxChar *bitmapMethod = copystring(_T("includepicture"));
9a29912f
JS
143bool upperCaseNames = FALSE;
144// HTML background and text colours
6c155d33
JS
145wxChar *backgroundImageString = NULL;
146wxChar *backgroundColourString = copystring(_T("255;255;255"));
147wxChar *textColourString = NULL;
148wxChar *linkColourString = NULL;
149wxChar *followedLinkColourString = NULL;
9a29912f 150bool combineSubSections = FALSE;
14204c7a 151bool htmlWorkshopFiles = FALSE;
bf16085d 152bool ignoreBadRefs = FALSE;
6c155d33 153wxChar *htmlFaceName = NULL;
9a29912f 154
3924dd22
GT
155extern int passNumber;
156
157extern wxHashTable TexReferences;
158
9a29912f
JS
159/*
160 * International support
161 */
162
163// Names to help with internationalisation
6c155d33
JS
164wxChar *ContentsNameString = copystring(_T("Contents"));
165wxChar *AbstractNameString = copystring(_T("Abstract"));
166wxChar *GlossaryNameString = copystring(_T("Glossary"));
167wxChar *ReferencesNameString = copystring(_T("References"));
168wxChar *FiguresNameString = copystring(_T("List of Figures"));
169wxChar *TablesNameString = copystring(_T("List of Tables"));
170wxChar *FigureNameString = copystring(_T("Figure"));
171wxChar *TableNameString = copystring(_T("Table"));
172wxChar *IndexNameString = copystring(_T("Index"));
173wxChar *ChapterNameString = copystring(_T("chapter"));
174wxChar *SectionNameString = copystring(_T("section"));
175wxChar *SubsectionNameString = copystring(_T("subsection"));
176wxChar *SubsubsectionNameString = copystring(_T("subsubsection"));
177wxChar *UpNameString = copystring(_T("Up"));
9a29912f
JS
178
179/*
180 * Section numbering
181 *
182 */
183
184int chapterNo = 0;
185int sectionNo = 0;
186int subsectionNo = 0;
187int subsubsectionNo = 0;
188int figureNo = 0;
189int tableNo = 0;
190
191/*
192 * Other variables
193 *
194 */
195
196FILE *CurrentOutput1 = NULL;
197FILE *CurrentOutput2 = NULL;
198FILE *Inputs[15];
dda2e4fd 199unsigned long LineNumbers[15];
6c155d33 200wxChar *FileNames[15];
9a29912f
JS
201int CurrentInputIndex = 0;
202
6c155d33
JS
203wxChar *TexFileRoot = NULL;
204wxChar *TexBibName = NULL; // Bibliography output file name
205wxChar *TexTmpBibName = NULL; // Temporary bibliography output file name
9a29912f
JS
206bool isSync = FALSE; // If TRUE, should not yield to other processes.
207bool stopRunning = FALSE; // If TRUE, should abort.
208
209static int currentColumn = 0;
6c155d33 210wxChar *currentArgData = NULL;
9a29912f
JS
211bool haveArgData = FALSE; // If TRUE, we're simulating the data.
212TexChunk *currentArgument = NULL;
213TexChunk *nextChunk = NULL;
214bool isArgOptional = FALSE;
446dd881 215int noArgs = 0;
9a29912f
JS
216
217TexChunk *TopLevel = NULL;
218// wxList MacroDefs(wxKEY_STRING);
219wxHashTable MacroDefs(wxKEY_STRING);
220wxStringList IgnorableInputFiles; // Ignorable \input files, e.g. psbox.tex
6c155d33 221wxChar *BigBuffer = NULL; // For reading in large chunks of text
9a29912f
JS
222TexMacroDef *SoloBlockDef = NULL;
223TexMacroDef *VerbatimMacroDef = NULL;
224
225#define IncrementLineNumber() LineNumbers[CurrentInputIndex] ++
226
3924dd22 227
6c155d33
JS
228TexRef::TexRef(const wxChar *label, const wxChar *file,
229 const wxChar *section, const wxChar *sectionN)
3924dd22
GT
230{
231 refLabel = copystring(label);
6c155d33
JS
232 refFile = file ? copystring(file) : (wxChar*) NULL;
233 sectionNumber = section ? copystring(section) : copystring(_T("??"));
234 sectionName = sectionN ? copystring(sectionN) : copystring(_T("??"));
3924dd22
GT
235}
236
237TexRef::~TexRef(void)
238{
239 delete [] refLabel; refLabel = NULL;
240 delete [] refFile; refFile = NULL;
241 delete [] sectionNumber; sectionNumber = NULL;
242 delete [] sectionName; sectionName = NULL;
243}
244
245
246CustomMacro::~CustomMacro()
247{
248 if (macroName)
249 delete [] macroName;
250 if (macroBody)
251 delete [] macroBody;
252}
253
6c155d33 254void TexOutput(const wxChar *s, bool ordinaryText)
9a29912f 255{
6c155d33 256 int len = wxStrlen(s);
9a29912f
JS
257
258 // Update current column, but only if we're guaranteed to
259 // be ordinary text (not mark-up stuff)
260 int i;
261 if (ordinaryText)
262 for (i = 0; i < len; i++)
263 {
264 if (s[i] == 13 || s[i] == 10)
265 currentColumn = 0;
266 else
267 currentColumn ++;
268 }
269
270 if (CurrentOutput1)
6c155d33 271 wxFprintf(CurrentOutput1, _T("%s"), s);
9a29912f 272 if (CurrentOutput2)
6c155d33 273 wxFprintf(CurrentOutput2, _T("%s"), s);
9a29912f
JS
274}
275
276/*
277 * Try to find a Latex macro, in one of the following forms:
278 * (1) \begin{} ... \end{}
279 * (2) \macroname{arg1}...{argn}
280 * (3) {\bf arg1}
281 */
282
283void ForbidWarning(TexMacroDef *def)
284{
04b9c5bb 285 wxString informBuf;
9a29912f
JS
286 switch (def->forbidden)
287 {
288 case FORBID_WARN:
289 {
6c155d33
JS
290 informBuf.Printf(_T("Warning: it is recommended that command %s is not used."), def->name);
291 OnInform((const wxChar *)informBuf.c_str());
9a29912f
JS
292 break;
293 }
294 case FORBID_ABSOLUTELY:
295 {
6c155d33
JS
296 informBuf.Printf(_T("Error: command %s cannot be used and will lead to errors."), def->name);
297 OnInform((const wxChar *)informBuf.c_str());
9a29912f
JS
298 break;
299 }
300 default:
301 break;
302 }
303}
304
6c155d33 305TexMacroDef *MatchMacro(wxChar *buffer, int *pos, wxChar **env, bool *parseToBrace)
9a29912f
JS
306{
307 *parseToBrace = TRUE;
308 int i = (*pos);
309 TexMacroDef *def = NULL;
6c155d33 310 wxChar macroBuf[40];
9a29912f
JS
311
312 // First, try to find begin{thing}
6c155d33 313 if (wxStrncmp(buffer+i, _T("begin{"), 6) == 0)
9a29912f
JS
314 {
315 i += 6;
316
317 int j = i;
318 while ((isalpha(buffer[j]) || buffer[j] == '*') && ((j - i) < 39))
319 {
320 macroBuf[j-i] = buffer[j];
321 j ++;
322 }
323 macroBuf[j-i] = 0;
324 def = (TexMacroDef *)MacroDefs.Get(macroBuf);
325
326 if (def)
327 {
328 *pos = j + 1; // BUGBUG Should this be + 1???
329 *env = def->name;
330 ForbidWarning(def);
331 return def;
332 }
333 else return NULL;
334 }
335
336 // Failed, so try to find macro from definition list
337 int j = i;
338
339 // First try getting a one-character macro, but ONLY
340 // if these TWO characters are not both alphabetical (could
341 // be a longer macro)
342 if (!(isalpha(buffer[i]) && isalpha(buffer[i+1])))
343 {
344 macroBuf[0] = buffer[i];
345 macroBuf[1] = 0;
346
347 def = (TexMacroDef *)MacroDefs.Get(macroBuf);
348 if (def) j ++;
349 }
350
351 if (!def)
352 {
353 while ((isalpha(buffer[j]) || buffer[j] == '*') && ((j - i) < 39))
354 {
355 macroBuf[j-i] = buffer[j];
356 j ++;
357 }
358 macroBuf[j-i] = 0;
359 def = (TexMacroDef *)MacroDefs.Get(macroBuf);
360 }
361
362 if (def)
363 {
364 i = j;
365
366 // We want to check whether this is a space-consuming macro
367 // (e.g. {\bf word})
368 // No brace, e.g. \input thing.tex instead of \input{thing};
369 // or a numeric argument, such as \parindent0pt
370 if ((def->no_args > 0) && ((buffer[i] == 32) || (buffer[i] == '=') || (isdigit(buffer[i]))))
371 {
372 if ((buffer[i] == 32) || (buffer[i] == '='))
373 i ++;
374
375 *parseToBrace = FALSE;
376 }
377 *pos = i;
378 ForbidWarning(def);
379 return def;
380 }
381 return NULL;
382}
383
6c155d33 384void EatWhiteSpace(wxChar *buffer, int *pos)
9a29912f 385{
6c155d33 386 int len = wxStrlen(buffer);
9a29912f
JS
387 int j = *pos;
388 bool keepGoing = TRUE;
389 bool moreLines = TRUE;
390 while ((j < len) && keepGoing &&
391 (buffer[j] == 10 || buffer[j] == 13 || buffer[j] == ' ' || buffer[j] == 9))
392 {
393 j ++;
394 if (j >= len)
395 {
396 if (moreLines)
397 {
398 moreLines = read_a_line(buffer);
6c155d33 399 len = wxStrlen(buffer);
9a29912f
JS
400 j = 0;
401 }
402 else
403 keepGoing = FALSE;
404 }
405 }
406 *pos = j;
407}
408
6c155d33 409bool FindEndEnvironment(wxChar *buffer, int *pos, wxChar *env)
9a29912f
JS
410{
411 int i = (*pos);
412
413 // Try to find end{thing}
6c155d33
JS
414 if ((wxStrncmp(buffer+i, _T("end{"), 4) == 0) &&
415 (wxStrncmp(buffer+i+4, env, wxStrlen(env)) == 0))
9a29912f 416 {
6c155d33 417 *pos = i + 5 + wxStrlen(env);
9a29912f
JS
418 return TRUE;
419 }
420 else return FALSE;
421}
422
423bool readingVerbatim = FALSE;
424bool readInVerbatim = FALSE; // Within a verbatim, but not nec. verbatiminput
425
f6bcfd97
BP
426// Switched this off because e.g. \verb${$ causes it to fail. There is no
427// detection of \verb yet.
fad535ee 428// #define CHECK_BRACES 1
f6bcfd97 429
341479ff
GT
430unsigned long leftCurley = 0;
431unsigned long rightCurley = 0;
6c155d33 432static wxString currentFileName = _T("");
f6bcfd97 433
6c155d33 434bool read_a_line(wxChar *buf)
9a29912f
JS
435{
436 if (CurrentInputIndex < 0)
437 {
438 buf[0] = 0;
439 return FALSE;
440 }
fad535ee 441
9a29912f 442 int ch = -2;
dda2e4fd 443 unsigned long bufIndex = 0;
9a29912f 444 buf[0] = 0;
f6bcfd97 445
9a29912f
JS
446 while (ch != EOF && ch != 10)
447 {
0e6ca394
GT
448 if (bufIndex >= MAX_LINE_BUFFER_SIZE)
449 {
450 wxString errBuf;
6c155d33
JS
451 errBuf.Printf(_T("Line %lu of file %s is too long. Lines can be no longer than %lu characters. Truncated."),
452 LineNumbers[CurrentInputIndex], (const wxChar*) currentFileName.c_str(), MAX_LINE_BUFFER_SIZE);
453 OnError((wxChar *)errBuf.c_str());
0e6ca394
GT
454 return FALSE;
455 }
456
6c155d33
JS
457 if (((bufIndex == 14) && (wxStrncmp(buf, _T("\\end{verbatim}"), 14) == 0)) ||
458 ((bufIndex == 16) && (wxStrncmp(buf, _T("\\end{toocomplex}"), 16) == 0)))
9a29912f
JS
459 readInVerbatim = FALSE;
460
461 ch = getc(Inputs[CurrentInputIndex]);
f6bcfd97 462
fad535ee 463 if (checkCurleyBraces)
f6bcfd97 464 {
fad535ee 465 if (ch == '{' && !readInVerbatim)
341479ff 466 leftCurley++;
fad535ee
GT
467 if (ch == '}' && !readInVerbatim)
468 {
341479ff
GT
469 rightCurley++;
470 if (rightCurley > leftCurley)
fad535ee
GT
471 {
472 wxString errBuf;
6c155d33
JS
473 errBuf.Printf(_T("An extra right Curley brace ('}') was detected at line %lu inside file %s"), LineNumbers[CurrentInputIndex], (const wxChar*) currentFileName.c_str());
474 OnError((wxChar *)errBuf.c_str());
fad535ee 475
341479ff 476 // Reduce the count of right Curley braces, so the mismatched count
fad535ee 477 // isn't reported on every line that has a '}' after the first mismatch
341479ff 478 rightCurley--;
fad535ee
GT
479 }
480 }
f6bcfd97 481 }
f6bcfd97 482
9a29912f
JS
483 if (ch != EOF)
484 {
485 // Check for 2 consecutive newlines and replace with \par
486 if (ch == 10 && !readInVerbatim)
487 {
488 int ch1 = getc(Inputs[CurrentInputIndex]);
489 if ((ch1 == 10) || (ch1 == 13))
490 {
491 // Eliminate newline (10) following DOS linefeed
0e6ca394 492 if (ch1 == 13)
6c155d33 493 getc(Inputs[CurrentInputIndex]);
0e6ca394 494 buf[bufIndex] = 0;
9a29912f 495 IncrementLineNumber();
6c155d33 496// wxStrcat(buf, "\\par\n");
9a29912f 497// i += 6;
0e6ca394
GT
498 if (bufIndex+5 >= MAX_LINE_BUFFER_SIZE)
499 {
500 wxString errBuf;
6c155d33
JS
501 errBuf.Printf(_T("Line %lu of file %s is too long. Lines can be no longer than %lu characters. Truncated."),
502 LineNumbers[CurrentInputIndex], (const wxChar*) currentFileName.c_str(),MAX_LINE_BUFFER_SIZE);
503 OnError((wxChar *)errBuf.c_str());
0e6ca394
GT
504 return FALSE;
505 }
6c155d33 506 wxStrcat(buf, _T("\\par"));
0e6ca394
GT
507 bufIndex += 5;
508
9a29912f
JS
509 }
510 else
511 {
512 ungetc(ch1, Inputs[CurrentInputIndex]);
0e6ca394
GT
513 if (bufIndex >= MAX_LINE_BUFFER_SIZE)
514 {
515 wxString errBuf;
6c155d33
JS
516 errBuf.Printf(_T("Line %lu of file %s is too long. Lines can be no longer than %lu characters. Truncated."),
517 LineNumbers[CurrentInputIndex], (const wxChar*) currentFileName.c_str(),MAX_LINE_BUFFER_SIZE);
518 OnError((wxChar *)errBuf.c_str());
0e6ca394
GT
519 return FALSE;
520 }
521
522 buf[bufIndex] = ch;
523 bufIndex ++;
9a29912f
JS
524 }
525 }
526 else
527 {
528
529 // Convert embedded characters to RTF equivalents
fad535ee
GT
530 switch(ch)
531 {
532