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