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