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