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