]> git.saurik.com Git - wxWidgets.git/blame - utils/tex2rtf/src/texutils.cpp
Patch [ 1314868 ] [wxMSW] Show MDI child menubars when ShowFullScreen(false)
[wxWidgets.git] / utils / tex2rtf / src / texutils.cpp
CommitLineData
9a29912f
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: texutils.cpp
3// Purpose: Miscellaneous utilities
4// Author: Julian Smart
b63b07a8
RL
5// Modified by: Wlodzimiez ABX Skiba 2003/2004 Unicode support
6// Ron Lee
9a29912f
JS
7// Created: 7.9.93
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
ea172e69 21 #include "wx/log.h"
9a29912f
JS
22#endif
23
ddc4f3b5 24#include "wx/app.h"
5aa5c1e4 25#include "wx/hash.h"
9a29912f 26
1a464ed9
JS
27#ifdef new
28#undef new
29#endif
30
9a29912f
JS
31#if wxUSE_IOSTREAMH
32#include <iostream.h>
33#include <fstream.h>
34#else
35#include <iostream>
36#include <fstream>
2b5f62a0 37using namespace std;
9a29912f
JS
38#endif
39
40#include <ctype.h>
41#include "tex2any.h"
42
ea172e69
MB
43#if !WXWIN_COMPATIBILITY_2_4
44static inline wxChar* copystring(const wxChar* s)
45 { return wxStrcpy(new wxChar[wxStrlen(s) + 1], s); }
ea172e69
MB
46#endif
47
9a29912f
JS
48wxHashTable TexReferences(wxKEY_STRING);
49wxList BibList(wxKEY_STRING);
50wxStringList CitationList;
51wxList ColourTable(wxKEY_STRING);
52wxHashTable BibStringTable(wxKEY_STRING);
53wxList CustomMacroList(wxKEY_STRING);
54TexChunk *currentSection = NULL;
6c155d33 55wxChar *fakeCurrentSection = NULL;
9a29912f
JS
56
57static long BibLine = 1;
58
59void OutputCurrentSection(void)
60{
61 if (fakeCurrentSection)
62 TexOutput(fakeCurrentSection);
63 else if (currentSection)
64 TraverseChildrenFromChunk(currentSection);
65}
66
67// Nasty but the way things are done now, necessary,
68// in order to output a chunk properly to a string (macros and all).
6c155d33 69void OutputCurrentSectionToString(wxChar *buf)
9a29912f
JS
70{
71 if (fakeCurrentSection)
6c155d33 72 wxStrcpy(buf, fakeCurrentSection);
9a29912f
JS
73 else
74 OutputChunkToString(currentSection, buf);
75}
76
6c155d33 77void OutputChunkToString(TexChunk *chunk, wxChar *buf)
9a29912f 78{
6c155d33 79 FILE *tempfd = wxFopen(_T("tmp.tmp"), _T("w"));
9a29912f
JS
80 if (!tempfd)
81 return;
254a2129 82
9a29912f
JS
83 FILE *old1 = CurrentOutput1;
84 FILE *old2 = CurrentOutput2;
254a2129 85
9a29912f
JS
86 CurrentOutput1 = tempfd;
87 CurrentOutput2 = NULL;
254a2129 88
9a29912f 89 TraverseChildrenFromChunk(chunk);
254a2129 90
9a29912f
JS
91 CurrentOutput1 = old1;
92 CurrentOutput2 = old2;
254a2129 93
9a29912f 94 fclose(tempfd);
254a2129 95
9a29912f 96 // Read from file into string
6c155d33 97 tempfd = wxFopen(_T("tmp.tmp"), _T("r"));
9a29912f
JS
98 if (!tempfd)
99 return;
100
101 buf[0] = 0;
102 int ch = -2;
103 int i = 0;
104 while (ch != EOF)
105 {
106 ch = getc(tempfd);
107 if (ch == EOF)
108 buf[i] = 0;
109 else
110 {
5b7ab938 111 buf[i] = (wxChar)ch;
9a29912f
JS
112 i ++;
113 }
114 }
115 fclose(tempfd);
6c155d33 116 wxRemoveFile(_T("tmp.tmp"));
9a29912f
JS
117}
118
119// Called by Tex2Any to simulate a section
6c155d33 120void FakeCurrentSection(wxChar *fakeSection, bool addToContents)
9a29912f
JS
121{
122 currentSection = NULL;
123 if (fakeCurrentSection) delete[] fakeCurrentSection;
124 fakeCurrentSection = copystring(fakeSection);
125
126 if (DocumentStyle == LATEX_ARTICLE)
127 {
128 int mac = ltSECTIONHEADING;
129 if (!addToContents)
130 mac = ltSECTIONHEADINGSTAR;
b63b07a8
RL
131 OnMacro(mac, 0, true);
132 OnMacro(mac, 0, false);
9a29912f
JS
133 }
134 else
135 {
136 int mac = ltCHAPTERHEADING;
137 if (!addToContents)
138 mac = ltCHAPTERHEADINGSTAR;
b63b07a8
RL
139 OnMacro(mac, 0, true);
140 OnMacro(mac, 0, false);
9a29912f
JS
141 }
142 if (fakeCurrentSection) delete[] fakeCurrentSection;
143 fakeCurrentSection = NULL;
144}
145
146// Look for \label macro, use this ref name if found or
147// make up a topic name otherwise.
148static long topicCounter = 0;
149
150void ResetTopicCounter(void)
151{
152 topicCounter = 0;
153}
154
6c155d33 155static wxChar *forceTopicName = NULL;
9a29912f 156
6c155d33 157void ForceTopicName(const wxChar *name)
9a29912f
JS
158{
159 if (forceTopicName)
160 delete[] forceTopicName;
161 if (name)
162 forceTopicName = copystring(name);
163 else
164 forceTopicName = NULL;
165}
166
6c155d33 167wxChar *FindTopicName(TexChunk *chunk)
9a29912f
JS
168{
169 if (forceTopicName)
170 return forceTopicName;
254a2129 171
6c155d33
JS
172 wxChar *topicName = NULL;
173 static wxChar topicBuf[100];
9a29912f
JS
174
175 if (chunk && (chunk->type == CHUNK_TYPE_MACRO) &&
176 (chunk->macroId == ltLABEL))
177 {
ddc4f3b5 178 wxNode *node = chunk->children.GetFirst();
9a29912f
JS
179 if (node)
180 {
ddc4f3b5 181 TexChunk *child = (TexChunk *)node->GetData();
9a29912f
JS
182 if (child->type == CHUNK_TYPE_ARG)
183 {
ddc4f3b5 184 wxNode *snode = child->children.GetFirst();
9a29912f
JS
185 if (snode)
186 {
ddc4f3b5 187 TexChunk *schunk = (TexChunk *)snode->GetData();
9a29912f
JS
188 if (schunk->type == CHUNK_TYPE_STRING)
189 topicName = schunk->value;
190 }
191 }
192 }
193 }
194 if (topicName)
195 return topicName;
196 else
197 {
b63b07a8 198 wxSnprintf(topicBuf, sizeof(topicBuf), _T("topic%ld"), topicCounter);
9a29912f
JS
199 topicCounter ++;
200 return topicBuf;
201 }
202}
203
204/*
205 * Simulate argument data, so we can 'drive' clients which implement
206 * certain basic formatting behaviour.
207 * Snag is that some save a TexChunk, so don't use yet...
208 *
209 */
254a2129 210
6c155d33 211void StartSimulateArgument(wxChar *data)
9a29912f 212{
6c155d33 213 wxStrcpy(currentArgData, data);
b63b07a8 214 haveArgData = true;
9a29912f
JS
215}
216
217void EndSimulateArgument(void)
218{
b63b07a8 219 haveArgData = false;
9a29912f
JS
220}
221
222/*
223 * Parse and convert unit arguments to points
224 *
225 */
226
6c155d33 227int ParseUnitArgument(wxChar *unitArg)
9a29912f
JS
228{
229 float conversionFactor = 1.0;
230 float unitValue = 0.0;
6c155d33 231 int len = wxStrlen(unitArg);
9a29912f
JS
232 // Get rid of any accidentally embedded commands
233 for (int i = 0; i < len; i++)
234 if (unitArg[i] == '\\')
235 unitArg[i] = 0;
6c155d33 236 len = wxStrlen(unitArg);
254a2129 237
9a29912f
JS
238 if (unitArg && (len > 0) && (isdigit(unitArg[0]) || unitArg[0] == '-'))
239 {
6c155d33 240 wxSscanf(unitArg, _T("%f"), &unitValue);
9a29912f
JS
241 if (len > 1)
242 {
254a2129 243 wxChar units[3];
9a29912f
JS
244 units[0] = unitArg[len-2];
245 units[1] = unitArg[len-1];
246 units[2] = 0;
6c155d33 247 if (wxStrcmp(units, _T("in")) == 0)
9a29912f 248 conversionFactor = 72.0;
6c155d33 249 else if (wxStrcmp(units, _T("cm")) == 0)
f90e5ed2 250 conversionFactor = (float)72.0/(float)2.51;
6c155d33 251 else if (wxStrcmp(units, _T("mm")) == 0)
f90e5ed2 252 conversionFactor = (float)72.0/(float)25.1;
6c155d33 253 else if (wxStrcmp(units, _T("pt")) == 0)
9a29912f
JS
254 conversionFactor = 1;
255 }
256 return (int)(unitValue*conversionFactor);
257 }
258 else return 0;
259}
260
261/*
262 * Strip off any extension (dot something) from end of file,
263 * IF one exists. Inserts zero into buffer.
264 *
265 */
254a2129 266
6c155d33 267void StripExtension(wxChar *buffer)
9a29912f 268{
6c155d33 269 int len = wxStrlen(buffer);
9a29912f
JS
270 int i = len-1;
271 while (i > 0)
272 {
273 if (buffer[i] == '.')
274 {
275 buffer[i] = 0;
276 break;
277 }
278 i --;
279 }
280}
281
282/*
283 * Latex font setting
284 *
285 */
286
287void SetFontSizes(int pointSize)
288{
289 switch (pointSize)
290 {
291 case 12:
292 {
293 normalFont = 12;
294 smallFont = 10;
295 tinyFont = 8;
296 largeFont1 = 14;
297 LargeFont2 = 16;
298 LARGEFont3 = 20;
299 hugeFont1 = 24;
300 HugeFont2 = 28;
301 HUGEFont3 = 32;
302 break;
303 }
304 case 11:
305 {
306 normalFont = 11;
307 smallFont = 9;
308 tinyFont = 7;
309 largeFont1 = 13;
310 LargeFont2 = 16;
311 LARGEFont3 = 19;
312 hugeFont1 = 22;
313 HugeFont2 = 26;
314 HUGEFont3 = 30;
315 break;
316 }
317 case 10:
318 {
319 normalFont = 10;
320 smallFont = 8;
321 tinyFont = 6;
322 largeFont1 = 12;
323 LargeFont2 = 14;
324 LARGEFont3 = 18;
325 hugeFont1 = 20;
326 HugeFont2 = 24;
327 HUGEFont3 = 28;
328 break;
329 }
330 }
331}
332
254a2129 333
9a29912f
JS
334/*
335 * Latex references
336 *
337 */
254a2129 338
6c155d33 339void AddTexRef(wxChar *name, wxChar *file, wxChar *sectionName,
9a29912f
JS
340 int chapter, int section, int subsection, int subsubsection)
341{
342 TexRef *texRef = (TexRef *)TexReferences.Get(name);
343 if (texRef) TexReferences.Delete(name);
254a2129 344
6c155d33 345 wxChar buf[100];
9a29912f
JS
346 buf[0] = 0;
347/*
348 if (sectionName)
349 {
6c155d33
JS
350 wxStrcat(buf, sectionName);
351 wxStrcat(buf, " ");
9a29912f
JS
352 }
353*/
354 if (chapter)
355 {
6c155d33 356 wxChar buf2[10];
b63b07a8 357 wxSnprintf(buf2, sizeof(buf2), _T("%d"), chapter);
6c155d33 358 wxStrcat(buf, buf2);
9a29912f
JS
359 }
360 if (section)
361 {
6c155d33 362 wxChar buf2[10];
9a29912f 363 if (chapter)
6c155d33 364 wxStrcat(buf, _T("."));
9a29912f 365
b63b07a8 366 wxSnprintf(buf2, sizeof(buf2), _T("%d"), section);
6c155d33 367 wxStrcat(buf, buf2);
9a29912f
JS
368 }
369 if (subsection)
370 {
6c155d33
JS
371 wxChar buf2[10];
372 wxStrcat(buf, _T("."));
b63b07a8 373 wxSnprintf(buf2, sizeof(buf2), _T("%d"), subsection);
6c155d33 374 wxStrcat(buf, buf2);
9a29912f
JS
375 }
376 if (subsubsection)
377 {
6c155d33
JS
378 wxChar buf2[10];
379 wxStrcat(buf, _T("."));
b63b07a8 380 wxSnprintf(buf2, sizeof(buf2), _T("%d"), subsubsection);
6c155d33 381 wxStrcat(buf, buf2);
9a29912f 382 }
6c155d33 383 wxChar *tmp = ((wxStrlen(buf) > 0) ? buf : (wxChar *)NULL);
9a29912f
JS
384 TexReferences.Put(name, new TexRef(name, file, tmp, sectionName));
385}
386
6c155d33 387void WriteTexReferences(wxChar *filename)
9a29912f 388{
b63b07a8
RL
389 wxString converter;
390 wxString name = filename;
391 wxSTD ofstream ostr((char const *)name.fn_str());
9a29912f 392 if (ostr.bad()) return;
254a2129 393
9a29912f 394 TexReferences.BeginFind();
f6fe5318 395 wxHashTable::Node *node = TexReferences.Next();
9a29912f
JS
396 while (node)
397 {
398 Tex2RTFYield();
ddc4f3b5 399 TexRef *ref = (TexRef *)node->GetData();
b63b07a8
RL
400 converter = ref->refLabel;
401 ostr << converter.mb_str();
402 ostr << " ";
403 converter = (ref->refFile ? ref->refFile : _T("??"));
404 ostr << converter.mb_str();
405 ostr << " ";
406 converter = (ref->sectionName ? ref->sectionName : _T("??")) ;
407 ostr << converter.mb_str();
408 ostr << " ";
409 converter = (ref->sectionNumber ? ref->sectionNumber : _T("??")) ;
410 ostr << converter.mb_str();
411 ostr << "\n";
6c155d33 412 if (!ref->sectionNumber || (wxStrcmp(ref->sectionNumber, _T("??")) == 0 && wxStrcmp(ref->sectionName, _T("??")) == 0))
9a29912f 413 {
b63b07a8
RL
414 wxChar buf[200];
415 wxSnprintf(buf, sizeof(buf), _T("Warning: reference %s not resolved."), ref->refLabel);
9a29912f
JS
416 OnInform(buf);
417 }
418 node = TexReferences.Next();
419 }
420}
421
6c155d33 422void ReadTexReferences(wxChar *filename)
9a29912f 423{
dbda9e86
JS
424 if (!wxFileExists(filename))
425 return;
426
b63b07a8
RL
427 wxString name = filename;
428 wxSTD ifstream istr((char const *)name.fn_str(), wxSTD ios::in);
dbda9e86 429
9a29912f
JS
430 if (istr.bad()) return;
431
b63b07a8
RL
432 char label[100];
433 char file[400];
434 char section[100];
435 char sectionName[100];
9a29912f
JS
436
437 while (!istr.eof())
438 {
439 istr >> label;
440 if (!istr.eof())
441 {
442 istr >> file;
4fe30bce 443 istr >> sectionName;
9a29912f
JS
444 char ch;
445 istr.get(ch); // Read past space
446 istr.get(ch);
447 int i = 0;
448 while (ch != '\n' && !istr.eof())
449 {
450 section[i] = ch;
451 i ++;
452 istr.get(ch);
453 }
454 section[i] = 0;
3924dd22 455
b63b07a8
RL
456 wxString label_string = wxString::FromAscii(label);
457 wxString file_string = wxString::FromAscii(file);
458 wxString sectionName_string = wxString::FromAscii(sectionName);
459 wxString section_string = wxString::FromAscii(section);
460
254a2129 461 // gt - needed to trick the hash table "TexReferences" into deleting the key
3924dd22
GT
462 // strings it creates in the Put() function, but not the item that is
463 // created here, as that is destroyed elsewhere. Without doing this, there
464 // were massive memory leaks
b63b07a8
RL
465 TexReferences.DeleteContents(true);
466 TexReferences.Put(
254a2129 467 label_string.c_str(),
b63b07a8 468 new TexRef(
254a2129
WS
469 label_string.c_str(),
470 file_string.c_str(),
471 section_string.c_str(),
b63b07a8
RL
472 sectionName_string.c_str()
473 )
474 );
475 TexReferences.DeleteContents(false);
9a29912f
JS
476 }
477 }
478}
479
480
481/*
482 * Bibliography-handling code
483 *
484 */
485
dd107c50 486void BibEatWhiteSpace(wxSTD istream& str)
9a29912f 487{
5b7ab938 488 char ch = (char)str.peek();
254a2129
WS
489
490 while (!str.eof() && (ch == ' ' || ch == '\t' || ch == 13 || ch == 10 || ch == (char)EOF))
9a29912f
JS
491 {
492 if (ch == 10)
493 BibLine ++;
494 str.get(ch);
254a2129 495 if ((ch == (char)EOF) || str.eof()) return;
5b7ab938 496 ch = (char)str.peek();
9a29912f
JS
497 }
498
499 // Ignore end-of-line comments
500 if (ch == '%' || ch == ';' || ch == '#')
501 {
502 str.get(ch);
5b7ab938 503 ch = (char)str.peek();
9a29912f
JS
504 while (ch != 10 && ch != 13 && !str.eof())
505 {
506 str.get(ch);
5b7ab938 507 ch = (char)str.peek();
9a29912f
JS
508 }
509 BibEatWhiteSpace(str);
510 }
511}
512
513// Read word up to { or , or space
6c155d33 514void BibReadWord(wxSTD istream& istr, wxChar *buffer)
9a29912f
JS
515{
516 int i = 0;
517 buffer[i] = 0;
5b7ab938 518 char ch = (char)istr.peek();
9a29912f
JS
519 while (!istr.eof() && ch != ' ' && ch != '{' && ch != '(' && ch != 13 && ch != 10 && ch != '\t' &&
520 ch != ',' && ch != '=')
521 {
522 istr.get(ch);
523 buffer[i] = ch;
524 i ++;
5b7ab938 525 ch = (char)istr.peek();
9a29912f
JS
526 }
527 buffer[i] = 0;
528}
529
530// Read string (double-quoted or not) to end quote or EOL
6c155d33 531void BibReadToEOL(wxSTD istream& istr, wxChar *buffer)
9a29912f
JS
532{
533 int i = 0;
534 buffer[i] = 0;
5b7ab938 535 char ch = (char)istr.peek();
b63b07a8
RL
536 bool inQuotes = false;
537 if (ch == '"')
9a29912f
JS
538 {
539 istr.get(ch);
5b7ab938 540 ch = (char)istr.peek();
b63b07a8 541 inQuotes = true;
9a29912f
JS
542 }
543 // If in quotes, read white space too. If not,
544 // stop at white space or comment.
6c155d33
JS
545 while (!istr.eof() && ch != 13 && ch != 10 && ch != _T('"') &&
546 (inQuotes || ((ch != _T(' ')) && (ch != 9) &&
547 (ch != _T(';')) && (ch != _T('%')) && (ch != _T('#')))))
9a29912f
JS
548 {
549 istr.get(ch);
550 buffer[i] = ch;
551 i ++;
5b7ab938 552 ch = (char)istr.peek();
9a29912f
JS
553 }
554 if (ch == '"')
555 istr.get(ch);
556 buffer[i] = 0;
557}
558
559// Read }-terminated value, taking nested braces into account.
b63b07a8
RL
560void BibReadValue(wxSTD istream& istr, wxChar *buffer, bool ignoreBraces = true,
561 bool quotesMayTerminate = true)
9a29912f
JS
562{
563 int braceCount = 1;
564 int i = 0;
565 buffer[i] = 0;
5b7ab938 566 char ch = (char)istr.peek();
b63b07a8 567 bool stopping = false;
9a29912f
JS
568 while (!istr.eof() && !stopping)
569 {
570// i ++;
08c6402a 571 if (i >= 4000)
9a29912f 572 {
6c155d33 573 wxChar buf[100];
b63b07a8 574 wxSnprintf(buf, sizeof(buf), _T("Sorry, value > 4000 chars in bib file at line %ld."), BibLine);
11611a62
JS
575 wxLogError(buf, "Tex2RTF Fatal Error");
576 return;
9a29912f
JS
577 }
578 istr.get(ch);
254a2129 579
9a29912f
JS
580 if (ch == '{')
581 braceCount ++;
582
583 if (ch == '}')
584 {
585 braceCount --;
586 if (braceCount == 0)
587 {
b63b07a8 588 stopping = true;
9a29912f
JS
589 break;
590 }
591 }
592 else if (quotesMayTerminate && ch == '"')
593 {
b63b07a8 594 stopping = true;
9a29912f
JS
595 break;
596 }
597 if (!stopping)
598 {
599 if (!ignoreBraces || (ch != '{' && ch != '}'))
600 {
601 buffer[i] = ch;
602 i ++;
603 }
604 }
605 if (ch == 10)
606 BibLine ++;
607 }
608 buffer[i] = 0;
6c155d33 609 wxUnusedVar(stopping);
9a29912f 610}
254a2129 611
6c155d33 612bool ReadBib(wxChar *filename)
9a29912f 613{
dbda9e86 614 if (!wxFileExists(filename))
b63b07a8 615 return false;
dbda9e86 616
b63b07a8 617 wxString name = filename;
6c155d33 618 wxChar buf[300];
b63b07a8
RL
619 wxSTD ifstream istr((char const *)name.fn_str(), wxSTD ios::in);
620 if (istr.bad()) return false;
9a29912f
JS
621
622 BibLine = 1;
623
6c155d33 624 OnInform(_T("Reading .bib file..."));
9a29912f
JS
625
626 char ch;
6c155d33
JS
627 wxChar fieldValue[4000];
628 wxChar recordType[100];
629 wxChar recordKey[100];
630 wxChar recordField[100];
9a29912f
JS
631 while (!istr.eof())
632 {
633 Tex2RTFYield();
634
635 BibEatWhiteSpace(istr);
636 istr.get(ch);
637 if (ch != '@')
638 {
b63b07a8 639 wxSnprintf(buf, sizeof(buf), _T("Expected @: malformed bib file at line %ld (%s)"), BibLine, filename);
9a29912f 640 OnError(buf);
b63b07a8 641 return false;
9a29912f
JS
642 }
643 BibReadWord(istr, recordType);
644 BibEatWhiteSpace(istr);
645 istr.get(ch);
646 if (ch != '{' && ch != '(')
647 {
b63b07a8 648 wxSnprintf(buf, sizeof(buf), _T("Expected { or ( after record type: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 649 OnError(buf);
b63b07a8 650 return false;
9a29912f
JS
651 }
652 BibEatWhiteSpace(istr);
b63b07a8 653 if (StringMatch(recordType, _T("string"), false, true))
9a29912f
JS
654 {
655 BibReadWord(istr, recordType);
656 BibEatWhiteSpace(istr);
657 istr.get(ch);
658 if (ch != '=')
659 {
b63b07a8 660 wxSnprintf(buf, sizeof(buf), _T("Expected = after string key: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 661 OnError(buf);
b63b07a8 662 return false;
9a29912f
JS
663 }
664 BibEatWhiteSpace(istr);
665 istr.get(ch);
666 if (ch != '"' && ch != '{')
667 {
b63b07a8 668 wxSnprintf(buf, sizeof(buf), _T("Expected = after string key: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 669 OnError(buf);
b63b07a8 670 return false;
9a29912f
JS
671 }
672 BibReadValue(istr, fieldValue);
673
674 // Now put in hash table if necesary
675 if (!BibStringTable.Get(recordType))
676 BibStringTable.Put(recordType, (wxObject *)copystring(fieldValue));
677
678 // Read closing ) or }
679 BibEatWhiteSpace(istr);
680 istr.get(ch);
681 BibEatWhiteSpace(istr);
682 }
683 else
684 {
685 BibReadWord(istr, recordKey);
686
687 BibEntry *bibEntry = new BibEntry;
688 bibEntry->key = copystring(recordKey);
689 bibEntry->type = copystring(recordType);
690
b63b07a8 691 bool moreRecords = true;
9a29912f
JS
692 while (moreRecords && !istr.eof())
693 {
694 BibEatWhiteSpace(istr);
695 istr.get(ch);
696 if (ch == '}' || ch == ')')
697 {
b63b07a8 698 moreRecords = false;
9a29912f
JS
699 }
700 else if (ch == ',')
701 {
702 BibEatWhiteSpace(istr);
703 BibReadWord(istr, recordField);
704 BibEatWhiteSpace(istr);
705 istr.get(ch);
706 if (ch != '=')
707 {
b63b07a8 708 wxSnprintf(buf, sizeof(buf), _T("Expected = after field type: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 709 OnError(buf);
b63b07a8 710 return false;
9a29912f
JS
711 }
712 BibEatWhiteSpace(istr);
713 istr.get(ch);
714 if (ch != '{' && ch != '"')
715 {
716 fieldValue[0] = ch;
717 BibReadWord(istr, fieldValue+1);
718
719 // If in the table of strings, replace with string from table.
6c155d33 720 wxChar *s = (wxChar *)BibStringTable.Get(fieldValue);
9a29912f
JS
721 if (s)
722 {
6c155d33 723 wxStrcpy(fieldValue, s);
9a29912f
JS
724 }
725 }
726 else
b63b07a8 727 BibReadValue(istr, fieldValue, true, (ch == _T('"') ? true : false));
9a29912f
JS
728
729 // Now we can add a field
b63b07a8 730 if (StringMatch(recordField, _T("author"), false, true))
9a29912f 731 bibEntry->author = copystring(fieldValue);
b63b07a8 732 else if (StringMatch(recordField, _T("key"), false, true))
9a29912f 733 {}
b63b07a8 734 else if (StringMatch(recordField, _T("annotate"), false, true))
9a29912f 735 {}
b63b07a8 736 else if (StringMatch(recordField, _T("abstract"), false, true))
9a29912f 737 {}
b63b07a8 738 else if (StringMatch(recordField, _T("edition"), false, true))
9a29912f 739 {}
b63b07a8 740 else if (StringMatch(recordField, _T("howpublished"), false, true))
9a29912f 741 {}
b63b07a8 742 else if (StringMatch(recordField, _T("note"), false, true) || StringMatch(recordField, _T("notes"), false, true))
9a29912f 743 {}
b63b07a8 744 else if (StringMatch(recordField, _T("series"), false, true))
9a29912f 745 {}
b63b07a8 746 else if (StringMatch(recordField, _T("type"), false, true))
9a29912f 747 {}
b63b07a8 748 else if (StringMatch(recordField, _T("keywords"), false, true))
9a29912f 749 {}
b63b07a8 750 else if (StringMatch(recordField, _T("editor"), false, true) || StringMatch(recordField, _T("editors"), false, true))
9a29912f 751 bibEntry->editor= copystring(fieldValue);
b63b07a8 752 else if (StringMatch(recordField, _T("title"), false, true))
9a29912f 753 bibEntry->title= copystring(fieldValue);
b63b07a8 754 else if (StringMatch(recordField, _T("booktitle"), false, true))
9a29912f 755 bibEntry->booktitle= copystring(fieldValue);
b63b07a8 756 else if (StringMatch(recordField, _T("journal"), false, true))
9a29912f 757 bibEntry->journal= copystring(fieldValue);
b63b07a8 758 else if (StringMatch(recordField, _T("volume"), false, true))
9a29912f 759 bibEntry->volume= copystring(fieldValue);
b63b07a8 760 else if (StringMatch(recordField, _T("number"), false, true))
9a29912f 761 bibEntry->number= copystring(fieldValue);
b63b07a8 762 else if (StringMatch(recordField, _T("year"), false, true))
9a29912f 763 bibEntry->year= copystring(fieldValue);
b63b07a8 764 else if (StringMatch(recordField, _T("month"), false, true))
9a29912f 765 bibEntry->month= copystring(fieldValue);
b63b07a8 766 else if (StringMatch(recordField, _T("pages"), false, true))
9a29912f 767 bibEntry->pages= copystring(fieldValue);
b63b07a8 768 else if (StringMatch(recordField, _T("publisher"), false, true))
9a29912f 769 bibEntry->publisher= copystring(fieldValue);
b63b07a8 770 else if (StringMatch(recordField, _T("address"), false, true))
9a29912f 771 bibEntry->address= copystring(fieldValue);
b63b07a8 772 else if (StringMatch(recordField, _T("institution"), false, true) || StringMatch(recordField, _T("school"), false, true))
9a29912f 773 bibEntry->institution= copystring(fieldValue);
b63b07a8 774 else if (StringMatch(recordField, _T("organization"), false, true) || StringMatch(recordField, _T("organisation"), false, true))
9a29912f 775 bibEntry->organization= copystring(fieldValue);
b63b07a8 776 else if (StringMatch(recordField, _T("comment"), false, true) || StringMatch(recordField, _T("comments"), false, true))
9a29912f 777 bibEntry->comment= copystring(fieldValue);
b63b07a8 778 else if (StringMatch(recordField, _T("annote"), false, true))
9a29912f 779 bibEntry->comment= copystring(fieldValue);
b63b07a8 780 else if (StringMatch(recordField, _T("chapter"), false, true))
9a29912f
JS
781 bibEntry->chapter= copystring(fieldValue);
782 else
783 {
b63b07a8 784 wxSnprintf(buf, sizeof(buf), _T("Unrecognised bib field type %s at line %ld (%s)"), recordField, BibLine, filename);
9a29912f
JS
785 OnError(buf);
786 }
787 }
788 }
789 BibList.Append(recordKey, bibEntry);
790 BibEatWhiteSpace(istr);
791 }
792 }
b63b07a8 793 return true;
9a29912f
JS
794}
795
796void OutputBibItem(TexRef *ref, BibEntry *bib)
797{
798 Tex2RTFYield();
799
b63b07a8
RL
800 OnMacro(ltNUMBEREDBIBITEM, 2, true);
801 OnArgument(ltNUMBEREDBIBITEM, 1, true);
9a29912f 802 TexOutput(ref->sectionNumber);
b63b07a8
RL
803 OnArgument(ltNUMBEREDBIBITEM, 1, false);
804 OnArgument(ltNUMBEREDBIBITEM, 2, true);
9a29912f 805
6c155d33 806 TexOutput(_T(" "));
b63b07a8
RL
807 OnMacro(ltBF, 1, true);
808 OnArgument(ltBF, 1, true);
9a29912f
JS
809 if (bib->author)
810 TexOutput(bib->author);
b63b07a8
RL
811 OnArgument(ltBF, 1, false);
812 OnMacro(ltBF, 1, false);
6c155d33
JS
813 if (bib->author && (wxStrlen(bib->author) > 0) && (bib->author[wxStrlen(bib->author) - 1] != '.'))
814 TexOutput(_T(". "));
9a29912f 815 else
6c155d33 816 TexOutput(_T(" "));
9a29912f
JS
817
818 if (bib->year)
819 {
820 TexOutput(bib->year);
821 }
822 if (bib->month)
823 {
6c155d33 824 TexOutput(_T(" ("));
9a29912f 825 TexOutput(bib->month);
6c155d33 826 TexOutput(_T(")"));
9a29912f
JS
827 }
828 if (bib->year || bib->month)
6c155d33 829 TexOutput(_T(". "));
9a29912f 830
b63b07a8 831 if (StringMatch(bib->type, _T("article"), false, true))
9a29912f
JS
832 {
833 if (bib->title)
834 {
835 TexOutput(bib->title);
6c155d33 836 TexOutput(_T(". "));
9a29912f
JS
837 }
838 if (bib->journal)
839 {
b63b07a8
RL
840 OnMacro(ltIT, 1, true);
841 OnArgument(ltIT, 1, true);
9a29912f 842 TexOutput(bib->journal);
b63b07a8
RL
843 OnArgument(ltIT, 1, false);
844 OnMacro(ltIT, 1, false);
9a29912f
JS
845 }
846 if (bib->volume)
847 {
6c155d33 848 TexOutput(_T(", "));
b63b07a8
RL
849 OnMacro(ltBF, 1, true);
850 OnArgument(ltBF, 1, true);
9a29912f 851 TexOutput(bib->volume);
b63b07a8
RL
852 OnArgument(ltBF, 1, false);
853 OnMacro(ltBF, 1, false);
9a29912f
JS
854 }
855 if (bib->number)
856 {
6c155d33 857 TexOutput(_T("("));
9a29912f 858 TexOutput(bib->number);
6c155d33 859 TexOutput(_T(")"));
9a29912f
JS
860 }
861 if (bib->pages)
862 {
6c155d33 863 TexOutput(_T(", pages "));
9a29912f
JS
864 TexOutput(bib->pages);
865 }
6c155d33 866 TexOutput(_T("."));
9a29912f 867 }
b63b07a8
RL
868 else if (StringMatch(bib->type, _T("book"), false, true) ||
869 StringMatch(bib->type, _T("unpublished"), false, true) ||
870 StringMatch(bib->type, _T("manual"), false, true) ||
871 StringMatch(bib->type, _T("phdthesis"), false, true) ||
872 StringMatch(bib->type, _T("mastersthesis"), false, true) ||
873 StringMatch(bib->type, _T("misc"), false, true) ||
874 StringMatch(bib->type, _T("techreport"), false, true) ||
875 StringMatch(bib->type, _T("booklet"), false, true))
9a29912f
JS
876 {
877 if (bib->title || bib->booktitle)
878 {
b63b07a8
RL
879 OnMacro(ltIT, 1, true);
880 OnArgument(ltIT, 1, true);
9a29912f 881 TexOutput(bib->title ? bib->title : bib->booktitle);
6c155d33 882 TexOutput(_T(". "));
b63b07a8
RL
883 OnArgument(ltIT, 1, false);
884 OnMacro(ltIT, 1, false);
9a29912f 885 }
b63b07a8 886 if (StringMatch(bib->type, _T("phdthesis"), false, true))
6c155d33 887 TexOutput(_T("PhD thesis. "));
b63b07a8 888 if (StringMatch(bib->type, _T("techreport"), false, true))
6c155d33 889 TexOutput(_T("Technical report. "));
9a29912f
JS
890 if (bib->editor)
891 {
6c155d33 892 TexOutput(_T("Ed. "));
9a29912f 893 TexOutput(bib->editor);
6c155d33 894 TexOutput(_T(". "));
9a29912f
JS
895 }
896 if (bib->institution)
897 {
898 TexOutput(bib->institution);
6c155d33 899 TexOutput(_T(". "));
9a29912f
JS
900 }
901 if (bib->organization)
902 {
903 TexOutput(bib->organization);
6c155d33 904 TexOutput(_T(". "));
9a29912f
JS
905 }
906 if (bib->publisher)
907 {
908 TexOutput(bib->publisher);
6c155d33 909 TexOutput(_T(". "));
9a29912f
JS
910 }
911 if (bib->address)
912 {
913 TexOutput(bib->address);
6c155d33 914 TexOutput(_T(". "));
9a29912f
JS
915 }
916 }
b63b07a8
RL
917 else if (StringMatch(bib->type, _T("inbook"), false, true) ||
918 StringMatch(bib->type, _T("inproceedings"), false, true) ||
919 StringMatch(bib->type, _T("incollection"), false, true) ||
920 StringMatch(bib->type, _T("conference"), false, true))
9a29912f
JS
921 {
922 if (bib->title)
923 {
924 TexOutput(bib->title);
925 }
926 if (bib->booktitle)
927 {
6c155d33 928 TexOutput(_T(", from "));
b63b07a8
RL
929 OnMacro(ltIT, 1, true);
930 OnArgument(ltIT, 1, true);
9a29912f 931 TexOutput(bib->booktitle);
6c155d33 932 TexOutput(_T("."));
b63b07a8
RL
933 OnArgument(ltIT, 1, false);
934 OnMacro(ltIT, 1, false);
9a29912f
JS
935 }
936 if (bib->editor)
937 {
6c155d33 938 TexOutput(_T(", ed. "));
9a29912f
JS
939 TexOutput(bib->editor);
940 }
941 if (bib->publisher)
942 {
6c155d33 943 TexOutput(_T(" "));
9a29912f
JS
944 TexOutput(bib->publisher);
945 }
946 if (bib->address)
947 {
6c155d33
JS
948 if (bib->publisher) TexOutput(_T(", "));
949 else TexOutput(_T(" "));
9a29912f
JS
950 TexOutput(bib->address);
951 }
952 if (bib->publisher || bib->address)
6c155d33 953 TexOutput(_T("."));
9a29912f
JS
954
955 if (bib->volume)
956 {
6c155d33 957 TexOutput(_T(" "));
b63b07a8
RL
958 OnMacro(ltBF, 1, true);
959 OnArgument(ltBF, 1, true);
9a29912f 960 TexOutput(bib->volume);
b63b07a8
RL
961 OnArgument(ltBF, 1, false);
962 OnMacro(ltBF, 1, false);
9a29912f
JS
963 }
964 if (bib->number)
965 {
966 if (bib->volume)
967 {
6c155d33 968 TexOutput(_T("("));
9a29912f 969 TexOutput(bib->number);
6c155d33 970 TexOutput(_T(")."));
9a29912f
JS
971 }
972 else
973 {
6c155d33 974 TexOutput(_T(" Number "));
9a29912f 975 TexOutput(bib->number);
6c155d33 976 TexOutput(_T("."));
9a29912f
JS
977 }
978 }
979 if (bib->chapter)
980 {
6c155d33
JS
981 TexOutput(_T(" Chap. "));
982 TexOutput(bib->chapter);
9a29912f
JS
983 }
984 if (bib->pages)
985 {
6c155d33
JS
986 if (bib->chapter) TexOutput(_T(", pages "));
987 else TexOutput(_T(" Pages "));
9a29912f 988 TexOutput(bib->pages);
6c155d33 989 TexOutput(_T("."));
9a29912f
JS
990 }
991 }
b63b07a8
RL
992 OnArgument(ltNUMBEREDBIBITEM, 2, false);
993 OnMacro(ltNUMBEREDBIBITEM, 2, false);
9a29912f
JS
994}
995
996void OutputBib(void)
997{
998 // Write the heading
6c155d33 999 ForceTopicName(_T("bibliography"));
9a29912f
JS
1000 FakeCurrentSection(ReferencesNameString);
1001 ForceTopicName(NULL);
1002
b63b07a8
RL
1003 OnMacro(ltPAR, 0, true);
1004 OnMacro(ltPAR, 0, false);
9a29912f
JS
1005
1006 if ((convertMode == TEX_RTF) && !winHelp)
1007 {
b63b07a8
RL
1008 OnMacro(ltPAR, 0, true);
1009 OnMacro(ltPAR, 0, false);
9a29912f
JS
1010 }
1011
ddc4f3b5 1012 wxStringListNode *node = CitationList.GetFirst();
9a29912f
JS
1013 while (node)
1014 {
6c155d33 1015 wxChar *citeKey = (wxChar *)node->GetData();
9a29912f
JS
1016// wxNode *texNode = TexReferences.Find(citeKey);
1017 TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
1018 wxNode *bibNode = BibList.Find(citeKey);
1019 if (bibNode && ref)
1020 {
ddc4f3b5 1021 BibEntry *entry = (BibEntry *)bibNode->GetData();
9a29912f
JS
1022 OutputBibItem(ref, entry);
1023 }
ddc4f3b5 1024 node = node->GetNext();
9a29912f
JS
1025 }
1026}
1027
1028static int citeCount = 1;
1029
1030void ResolveBibReferences(void)
1031{
ddc4f3b5 1032 if (CitationList.GetCount() > 0)
6c155d33 1033 OnInform(_T("Resolving bibliographic references..."));
9a29912f
JS
1034
1035 citeCount = 1;
6c155d33 1036 wxChar buf[200];
ddc4f3b5 1037 wxStringListNode *node = CitationList.GetFirst();
9a29912f
JS
1038 while (node)
1039 {
1040 Tex2RTFYield();
6c155d33 1041 wxChar *citeKey = (wxChar *)node->GetData();
9a29912f
JS
1042// wxNode *texNode = TexReferences.Find(citeKey);
1043 TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
1044 wxNode *bibNode = BibList.Find(citeKey);
1045 if (bibNode && ref)
1046 {
1047 // Unused Variable
ddc4f3b5 1048 //BibEntry *entry = (BibEntry *)bibNode->GetData();
9a29912f 1049 if (ref->sectionNumber) delete[] ref->sectionNumber;
b63b07a8 1050 wxSnprintf(buf, sizeof(buf), _T("[%d]"), citeCount);
9a29912f
JS
1051 ref->sectionNumber = copystring(buf);
1052 citeCount ++;
1053 }
1054 else
1055 {
b63b07a8 1056 wxSnprintf(buf, sizeof(buf), _T("Warning: bib ref %s not resolved."), citeKey);
9a29912f
JS
1057 OnInform(buf);
1058 }
ddc4f3b5 1059 node = node->GetNext();
9a29912f
JS
1060 }
1061}
1062
1063// Remember we need to resolve this citation
6c155d33 1064void AddCitation(wxChar *citeKey)
9a29912f
JS
1065{
1066 if (!CitationList.Member(citeKey))
1067 CitationList.Add(citeKey);
1068
1069 if (!TexReferences.Get(citeKey))
1070 {
6c155d33 1071 TexReferences.Put(citeKey, new TexRef(citeKey, _T("??"), NULL));
9a29912f
JS
1072 }
1073}
1074
6c155d33 1075TexRef *FindReference(wxChar *key)
9a29912f
JS
1076{
1077 return (TexRef *)TexReferences.Get(key);
1078}
1079
1080/*
1081 * Custom macro stuff
1082 *
1083 */
1084
6c155d33 1085bool StringTobool(wxChar *val)
9a29912f 1086{
6c155d33
JS
1087 if (wxStrncmp(val, _T("yes"), 3) == 0 || wxStrncmp(val, _T("YES"), 3) == 0 ||
1088 wxStrncmp(val, _T("on"), 2) == 0 || wxStrncmp(val, _T("ON"), 2) == 0 ||
b63b07a8 1089 wxStrncmp(val, _T("true"), 4) == 0 || wxStrncmp(val, _T("true"), 4) == 0 ||
6c155d33
JS
1090 wxStrncmp(val, _T("ok"), 2) == 0 || wxStrncmp(val, _T("OK"), 2) == 0 ||
1091 wxStrncmp(val, _T("1"), 1) == 0)
b63b07a8 1092 return true;
9a29912f 1093 else
b63b07a8 1094 return false;
9a29912f
JS
1095}
1096
eecb33b0
WS
1097void RegisterIntSetting (const wxString& s, int *number)
1098{
1099 if (number)
1100 {
1101 long val;
1102 s.ToLong(&val);
1103 *number = (int)val;
1104 }
1105}
1106
9a29912f 1107// Define a variable value from the .ini file
6c155d33 1108wxChar *RegisterSetting(wxChar *settingName, wxChar *settingValue, bool interactive)
9a29912f 1109{
eecb33b0
WS
1110 wxString settingValueStr( settingValue );
1111
1112 static wxChar errorCode[100];
1113 wxStrcpy(errorCode, _T("OK"));
1114 if (StringMatch(settingName, _T("chapterName"), false, true))
9a29912f 1115 {
eecb33b0
WS
1116 delete[] ChapterNameString;
1117 ChapterNameString = copystring(settingValue);
9a29912f 1118 }
eecb33b0 1119 else if (StringMatch(settingName, _T("sectionName"), false, true))
9a29912f 1120 {
eecb33b0
WS
1121 delete[] SectionNameString;
1122 SectionNameString = copystring(settingValue);
9a29912f 1123 }
eecb33b0 1124 else if (StringMatch(settingName, _T("subsectionName"), false, true))
9a29912f 1125 {
eecb33b0
WS
1126 delete[] SubsectionNameString;
1127 SubsectionNameString = copystring(settingValue);
9a29912f 1128 }
eecb33b0 1129 else if (StringMatch(settingName, _T("subsubsectionName"), false, true))
9a29912f 1130 {
eecb33b0
WS
1131 delete[] SubsubsectionNameString;
1132 SubsubsectionNameString = copystring(settingValue);
9a29912f 1133 }
eecb33b0 1134 else if (StringMatch(settingName, _T("indexName"), false, true))
9a29912f 1135 {
eecb33b0
WS
1136 delete[] IndexNameString;
1137 IndexNameString = copystring(settingValue);
9a29912f 1138 }
eecb33b0 1139 else if (StringMatch(settingName, _T("contentsName"), false, true))
9a29912f 1140 {
eecb33b0
WS
1141 delete[] ContentsNameString;
1142 ContentsNameString = copystring(settingValue);
9a29912f 1143 }
eecb33b0 1144 else if (StringMatch(settingName, _T("glossaryName"), false, true))
9a29912f 1145 {
eecb33b0
WS
1146 delete[] GlossaryNameString;
1147 GlossaryNameString = copystring(settingValue);
9a29912f 1148 }
eecb33b0 1149 else if (StringMatch(settingName, _T("referencesName"), false, true))
9a29912f 1150 {
eecb33b0
WS
1151 delete[] ReferencesNameString;
1152 ReferencesNameString = copystring(settingValue);
1153 }
1154 else if (StringMatch(settingName, _T("tablesName"), false, true))
1155 {
1156 delete[] TablesNameString;
1157 TablesNameString = copystring(settingValue);
1158 }
1159 else if (StringMatch(settingName, _T("figuresName"), false, true))
1160 {
1161 delete[] FiguresNameString;
1162 FiguresNameString = copystring(settingValue);
1163 }
1164 else if (StringMatch(settingName, _T("tableName"), false, true))
1165 {
1166 delete[] TableNameString;
1167 TableNameString = copystring(settingValue);
1168 }
1169 else if (StringMatch(settingName, _T("figureName"), false, true))
1170 {
1171 delete[] FigureNameString;
1172 FigureNameString = copystring(settingValue);
1173 }
1174 else if (StringMatch(settingName, _T("abstractName"), false, true))
1175 {
1176 delete[] AbstractNameString;
1177 AbstractNameString = copystring(settingValue);
1178 }
1179 else if (StringMatch(settingName, _T("chapterFontSize"), false, true))
1180 RegisterIntSetting(settingValueStr, &chapterFont);
1181 else if (StringMatch(settingName, _T("sectionFontSize"), false, true))
1182 RegisterIntSetting(settingValueStr, &sectionFont);
1183 else if (StringMatch(settingName, _T("subsectionFontSize"), false, true))
1184 RegisterIntSetting(settingValueStr, &subsectionFont);
1185 else if (StringMatch(settingName, _T("titleFontSize"), false, true))
1186 RegisterIntSetting(settingValueStr, &titleFont);
1187 else if (StringMatch(settingName, _T("authorFontSize"), false, true))
1188 RegisterIntSetting(settingValueStr, &authorFont);
1189 else if (StringMatch(settingName, _T("ignoreInput"), false, true))
1190 IgnorableInputFiles.Add(wxFileNameFromPath(settingValue));
1191 else if (StringMatch(settingName, _T("mirrorMargins"), false, true))
1192 mirrorMargins = StringTobool(settingValue);
1193 else if (StringMatch(settingName, _T("runTwice"), false, true))
1194 runTwice = StringTobool(settingValue);
1195 else if (StringMatch(settingName, _T("isInteractive"), false, true))
1196 isInteractive = StringTobool(settingValue);
1197 else if (StringMatch(settingName, _T("headerRule"), false, true))
1198 headerRule = StringTobool(settingValue);
1199 else if (StringMatch(settingName, _T("footerRule"), false, true))
1200 footerRule = StringTobool(settingValue);
1201 else if (StringMatch(settingName, _T("combineSubSections"), false, true))
1202 combineSubSections = StringTobool(settingValue);
1203 else if (StringMatch(settingName, _T("listLabelIndent"), false, true))
1204 RegisterIntSetting(settingValueStr, &labelIndentTab);
1205 else if (StringMatch(settingName, _T("listItemIndent"), false, true))
1206 RegisterIntSetting(settingValueStr, &itemIndentTab);
1207 else if (StringMatch(settingName, _T("useUpButton"), false, true))
1208 useUpButton = StringTobool(settingValue);
1209 else if (StringMatch(settingName, _T("useHeadingStyles"), false, true))
1210 useHeadingStyles = StringTobool(settingValue);
1211 else if (StringMatch(settingName, _T("useWord"), false, true))
1212 useWord = StringTobool(settingValue);
1213 else if (StringMatch(settingName, _T("contentsDepth"), false, true))
1214 RegisterIntSetting(settingValueStr, &contentsDepth);
1215 else if (StringMatch(settingName, _T("generateHPJ"), false, true))
1216 generateHPJ = StringTobool(settingValue);
1217 else if (StringMatch(settingName, _T("truncateFilenames"), false, true))
1218 truncateFilenames = StringTobool(settingValue);
1219 else if (StringMatch(settingName, _T("winHelpVersion"), false, true))
1220 RegisterIntSetting(settingValueStr, &winHelpVersion);
1221 else if (StringMatch(settingName, _T("winHelpContents"), false, true))
1222 winHelpContents = StringTobool(settingValue);
1223 else if (StringMatch(settingName, _T("htmlIndex"), false, true))
1224 htmlIndex = StringTobool(settingValue);
1225 else if (StringMatch(settingName, _T("htmlWorkshopFiles"), false, true))
1226 htmlWorkshopFiles = StringTobool(settingValue);
1227 else if (StringMatch(settingName, _T("htmlFrameContents"), false, true))
1228 htmlFrameContents = StringTobool(settingValue);
1229 else if (StringMatch(settingName, _T("htmlStylesheet"), false, true))
1230 {
1231 if (htmlStylesheet)
1232 delete[] htmlStylesheet;
1233 htmlStylesheet = copystring(settingValue);
1234 }
1235 else if (StringMatch(settingName, _T("upperCaseNames"), false, true))
1236 upperCaseNames = StringTobool(settingValue);
1237 else if (StringMatch(settingName, _T("ignoreBadRefs"), false, true))
1238 ignoreBadRefs = StringTobool(settingValue);
1239 else if (StringMatch(settingName, _T("htmlFaceName"), false, true))
1240 {
1241 delete[] htmlFaceName;
1242 htmlFaceName = copystring(settingValue);
1243 }
1244 else if (StringMatch(settingName, _T("winHelpTitle"), false, true))
1245 {
1246 if (winHelpTitle)
1247 delete[] winHelpTitle;
1248 winHelpTitle = copystring(settingValue);
1249 }
1250 else if (StringMatch(settingName, _T("indexSubsections"), false, true))
1251 indexSubsections = StringTobool(settingValue);
1252 else if (StringMatch(settingName, _T("compatibility"), false, true))
1253 compatibilityMode = StringTobool(settingValue);
1254 else if (StringMatch(settingName, _T("defaultColumnWidth"), false, true))
1255 {
1256 RegisterIntSetting(settingValueStr, &defaultTableColumnWidth);
1257 defaultTableColumnWidth = 20*defaultTableColumnWidth;
1258 }
1259 else if (StringMatch(settingName, _T("bitmapMethod"), false, true))
1260 {
1261 if ((wxStrcmp(settingValue, _T("includepicture")) != 0) && (wxStrcmp(settingValue, _T("hex")) != 0) &&
1262 (wxStrcmp(settingValue, _T("import")) != 0))
1263 {
1264 if (interactive)
1265 OnError(_T("Unknown bitmapMethod"));
1266 wxStrcpy(errorCode, _T("Unknown bitmapMethod"));
1267 }
1268 else
1269 {
1270 delete[] bitmapMethod;
1271 bitmapMethod = copystring(settingValue);
1272 }
1273 }
1274 else if (StringMatch(settingName, _T("htmlBrowseButtons"), false, true))
1275 {
1276 if (wxStrcmp(settingValue, _T("none")) == 0)
1277 htmlBrowseButtons = HTML_BUTTONS_NONE;
1278 else if (wxStrcmp(settingValue, _T("bitmap")) == 0)
1279 htmlBrowseButtons = HTML_BUTTONS_BITMAP;
1280 else if (wxStrcmp(settingValue, _T("text")) == 0)
1281 htmlBrowseButtons = HTML_BUTTONS_TEXT;
1282 else
1283 {
1284 if (interactive)
1285 OnInform(_T("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text."));
1286 wxStrcpy(errorCode, _T("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text."));
1287 }
1288 }
1289 else if (StringMatch(settingName, _T("backgroundImage"), false, true))
1290 {
1291 backgroundImageString = copystring(settingValue);
1292 }
1293 else if (StringMatch(settingName, _T("backgroundColour"), false, true))
1294 {
1295 delete[] backgroundColourString;
1296 backgroundColourString = copystring(settingValue);
1297 }
1298 else if (StringMatch(settingName, _T("textColour"), false, true))
1299 {
1300 textColourString = copystring(settingValue);
1301 }
1302 else if (StringMatch(settingName, _T("linkColour"), false, true))
1303 {
1304 linkColourString = copystring(settingValue);
1305 }
1306 else if (StringMatch(settingName, _T("followedLinkColour"), false, true))
1307 {
1308 followedLinkColourString = copystring(settingValue);
1309 }
1310 else if (StringMatch(settingName, _T("conversionMode"), false, true))
1311 {
1312 if (StringMatch(settingValue, _T("RTF"), false, true))
1313 {
1314 winHelp = false; convertMode = TEX_RTF;
1315 }
1316 else if (StringMatch(settingValue, _T("WinHelp"), false, true))
1317 {
1318 winHelp = true; convertMode = TEX_RTF;
1319 }
1320 else if (StringMatch(settingValue, _T("XLP"), false, true) ||
1321 StringMatch(settingValue, _T("wxHelp"), false, true))
1322 {
1323 convertMode = TEX_XLP;
1324 }
1325 else if (StringMatch(settingValue, _T("HTML"), false, true))
1326 {
1327 convertMode = TEX_HTML;
1328 }
1329 else
1330 {
1331 if (interactive)
1332 OnInform(_T("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML."));
1333 wxStrcpy(errorCode, _T("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML."));
1334 }
1335 }
1336 else if (StringMatch(settingName, _T("documentFontSize"), false, true))
1337 {
1338 int n;
1339 RegisterIntSetting(settingValueStr, &n);
1340 if (n == 10 || n == 11 || n == 12)
1341 SetFontSizes(n);
1342 else
1343 {
1344 wxChar buf[200];
1345 wxSnprintf(buf, sizeof(buf), _T("Initialisation file error: nonstandard document font size %d."), n);
1346 if (interactive)
1347 OnInform(buf);
1348 wxStrcpy(errorCode, buf);
1349 }
9a29912f 1350 }
9a29912f
JS
1351 else
1352 {
eecb33b0
WS
1353 wxChar buf[200];
1354 wxSnprintf(buf, sizeof(buf), _T("Initialisation file error: unrecognised setting %s."), settingName);
1355 if (interactive)
1356 OnInform(buf);
1357 wxStrcpy(errorCode, buf);
9a29912f 1358 }
eecb33b0 1359 return errorCode;
9a29912f
JS
1360}
1361
6c155d33 1362bool ReadCustomMacros(wxChar *filename)
9a29912f 1363{
dbda9e86 1364 if (!wxFileExists(filename))
b63b07a8 1365 return false;
dbda9e86 1366
b63b07a8
RL
1367 wxString name = filename;
1368 wxSTD ifstream istr((char const *)name.fn_str(), wxSTD ios::in);
dbda9e86 1369
b63b07a8 1370 if (istr.bad()) return false;
9a29912f
JS
1371
1372 CustomMacroList.Clear();
1373 char ch;
6c155d33
JS
1374 wxChar macroName[100];
1375 wxChar macroBody[1000];
9a29912f
JS
1376 int noArgs;
1377
1378 while (!istr.eof())
1379 {
1380 BibEatWhiteSpace(istr);
1381 istr.get(ch);
1382 if (istr.eof())
1383 break;
254a2129 1384
9a29912f
JS
1385 if (ch != '\\') // Not a macro definition, so must be NAME=VALUE
1386 {
6c155d33 1387 wxChar settingName[100];
9a29912f
JS
1388 settingName[0] = ch;
1389 BibReadWord(istr, (settingName+1));
1390 BibEatWhiteSpace(istr);
1391 istr.get(ch);
1392 if (ch != '=')
1393 {
6c155d33 1394 OnError(_T("Expected = following name: malformed tex2rtf.ini file."));
b63b07a8 1395 return false;
9a29912f
JS
1396 }
1397 else
1398 {
6c155d33 1399 wxChar settingValue[200];
9a29912f
JS
1400 BibEatWhiteSpace(istr);
1401 BibReadToEOL(istr, settingValue);
1402 RegisterSetting(settingName, settingValue);
1403 }
1404 }
1405 else
1406 {
1407 BibReadWord(istr, macroName);
1408 BibEatWhiteSpace(istr);
1409 istr.get(ch);
1410 if (ch != '[')
1411 {
6c155d33 1412 OnError(_T("Expected [ followed by number of arguments: malformed tex2rtf.ini file."));
b63b07a8 1413 return false;
9a29912f
JS
1414 }
1415 istr >> noArgs;
1416 istr.get(ch);
1417 if (ch != ']')
1418 {
6c155d33 1419 OnError(_T("Expected ] following number of arguments: malformed tex2rtf.ini file."));
b63b07a8 1420 return false;
9a29912f
JS
1421 }
1422 BibEatWhiteSpace(istr);
1423 istr.get(ch);
1424 if (ch != '{')
1425 {
6c155d33 1426 OnError(_T("Expected { followed by macro body: malformed tex2rtf.ini file."));
b63b07a8 1427 return false;
9a29912f
JS
1428 }
1429 CustomMacro *macro = new CustomMacro(macroName, noArgs, NULL);
b63b07a8 1430 BibReadValue(istr, macroBody, false, false); // Don't ignore extra braces
6c155d33 1431 if (wxStrlen(macroBody) > 0)
9a29912f 1432 macro->macroBody = copystring(macroBody);
254a2129 1433
9a29912f
JS
1434 BibEatWhiteSpace(istr);
1435 CustomMacroList.Append(macroName, macro);
1436 AddMacroDef(ltCUSTOM_MACRO, macroName, noArgs);
1437 }
1438 }
6c155d33 1439 wxChar mbuf[200];
b63b07a8 1440 wxSnprintf(mbuf, sizeof(mbuf), _T("Read initialization file %s."), filename);
9a29912f 1441 OnInform(mbuf);
b63b07a8 1442 return true;
9a29912f 1443}
254a2129 1444
6c155d33 1445CustomMacro *FindCustomMacro(wxChar *name)
9a29912f
JS
1446{
1447 wxNode *node = CustomMacroList.Find(name);
1448 if (node)
1449 {
ddc4f3b5 1450 CustomMacro *macro = (CustomMacro *)node->GetData();
9a29912f
JS
1451 return macro;
1452 }
1453 return NULL;
1454}
1455
1456// Display custom macros
1457void ShowCustomMacros(void)
1458{
ddc4f3b5 1459 wxNode *node = CustomMacroList.GetFirst();
9a29912f
JS
1460 if (!node)
1461 {
6c155d33 1462 OnInform(_T("No custom macros loaded.\n"));
9a29912f
JS
1463 return;
1464 }
254a2129 1465
6c155d33 1466 wxChar buf[400];
9a29912f
JS
1467 while (node)
1468 {
ddc4f3b5 1469 CustomMacro *macro = (CustomMacro *)node->GetData();
b63b07a8 1470 wxSnprintf(buf, sizeof(buf), _T("\\%s[%d]\n {%s}"), macro->macroName, macro->noArgs,
6c155d33 1471 macro->macroBody ? macro->macroBody : _T(""));
9a29912f 1472 OnInform(buf);
ddc4f3b5 1473 node = node->GetNext();
9a29912f
JS
1474 }
1475}
1476
1477// Parse a string into several comma-separated fields
6c155d33 1478wxChar *ParseMultifieldString(wxChar *allFields, int *pos)
9a29912f 1479{
6c155d33 1480 static wxChar buffer[300];
9a29912f
JS
1481 int i = 0;
1482 int fieldIndex = *pos;
6c155d33 1483 int len = wxStrlen(allFields);
9a29912f 1484 int oldPos = *pos;
b63b07a8 1485 bool keepGoing = true;
9a29912f
JS
1486 while ((fieldIndex <= len) && keepGoing)
1487 {
6c155d33 1488 if (allFields[fieldIndex] == _T(' '))
9a29912f
JS
1489 {
1490 // Skip
1491 fieldIndex ++;
1492 }
6c155d33 1493 else if (allFields[fieldIndex] == _T(','))
9a29912f
JS
1494 {
1495 *pos = fieldIndex + 1;
b63b07a8 1496 keepGoing = false;
9a29912f
JS
1497 }
1498 else if (allFields[fieldIndex] == 0)
1499 {
1500 *pos = fieldIndex + 1;
b63b07a8 1501 keepGoing = false;
9a29912f
JS
1502 }
1503 else
1504 {
1505 buffer[i] = allFields[fieldIndex];
1506 fieldIndex ++;
1507 i++;
1508 }
1509 }
1510 buffer[i] = 0;
1511 if (oldPos == (*pos))
1512 *pos = len + 1;
254a2129 1513
9a29912f
JS
1514 if (i == 0)
1515 return NULL;
1516 else
1517 return buffer;
1518}
1519
1520/*
1521 * Colour tables
1522 *
1523 */
254a2129 1524
6c155d33 1525ColourTableEntry::ColourTableEntry(const wxChar *theName, unsigned int r, unsigned int g, unsigned int b)
9a29912f
JS
1526{
1527 name = copystring(theName);
1528 red = r;
1529 green = g;
1530 blue = b;
1531}
1532
1533ColourTableEntry::~ColourTableEntry(void)
1534{
1535 delete[] name;
1536}
1537
6c155d33 1538void AddColour(const wxChar *theName, unsigned int r, unsigned int g, unsigned int b)
9a29912f
JS
1539{
1540 wxNode *node = ColourTable.Find(theName);
1541 if (node)
1542 {
ddc4f3b5 1543 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
9a29912f
JS
1544 if (entry->red == r || entry->green == g || entry->blue == b)
1545 return;
1546 else
1547 {
1548 delete entry;
1549 delete node;
1550 }
1551 }
1552 ColourTableEntry *entry = new ColourTableEntry(theName, r, g, b);
1553 ColourTable.Append(theName, entry);
1554}
1555
6c155d33 1556int FindColourPosition(wxChar *theName)
9a29912f
JS
1557{
1558 int i = 0;
ddc4f3b5 1559 wxNode *node = ColourTable.GetFirst();
9a29912f
JS
1560 while (node)
1561 {
ddc4f3b5 1562 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
6c155d33 1563 if (wxStrcmp(theName, entry->name) == 0)
9a29912f
JS
1564 return i;
1565 i ++;
ddc4f3b5 1566 node = node->GetNext();
9a29912f
JS
1567 }
1568 return -1;
1569}
1570
1571// Converts e.g. "red" -> "#FF0000"
6c155d33
JS
1572extern void DecToHex(int, wxChar *);
1573bool FindColourHTMLString(wxChar *theName, wxChar *buf)
9a29912f 1574{
ddc4f3b5 1575 wxNode *node = ColourTable.GetFirst();
9a29912f
JS
1576 while (node)
1577 {
ddc4f3b5 1578 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
6c155d33 1579 if (wxStrcmp(theName, entry->name) == 0)
9a29912f 1580 {
6c155d33 1581 wxStrcpy(buf, _T("#"));
254a2129 1582
6c155d33 1583 wxChar buf2[3];
9a29912f 1584 DecToHex(entry->red, buf2);
6c155d33 1585 wxStrcat(buf, buf2);
9a29912f 1586 DecToHex(entry->green, buf2);
6c155d33 1587 wxStrcat(buf, buf2);
9a29912f 1588 DecToHex(entry->blue, buf2);
6c155d33 1589 wxStrcat(buf, buf2);
9a29912f 1590
b63b07a8 1591 return true;
9a29912f 1592 }
ddc4f3b5 1593 node = node->GetNext();
9a29912f 1594 }
b63b07a8 1595 return false;
9a29912f
JS
1596}
1597
254a2129 1598
9a29912f
JS
1599void InitialiseColourTable(void)
1600{
1601 // \\red0\\green0\\blue0;
6c155d33 1602 AddColour(_T("black"), 0,0,0);
9a29912f
JS
1603
1604 // \\red0\\green0\\blue255;\\red0\\green255\\blue255;\n");
6c155d33 1605 AddColour(_T("cyan"), 0,255,255);
9a29912f
JS
1606
1607 // \\red0\\green255\\blue0;
6c155d33 1608 AddColour(_T("green"), 0,255,0);
254a2129 1609
9a29912f 1610 // \\red255\\green0\\blue255;
6c155d33 1611 AddColour(_T("magenta"), 255,0,255);
9a29912f
JS
1612
1613 // \\red255\\green0\\blue0;
6c155d33 1614 AddColour(_T("red"), 255,0,0);
254a2129 1615
9a29912f 1616 // \\red255\\green255\\blue0;
6c155d33 1617 AddColour(_T("yellow"), 255,255,0);
254a2129 1618
9a29912f 1619 // \\red255\\green255\\blue255;}");
6c155d33 1620 AddColour(_T("white"), 255,255,255);
9a29912f
JS
1621}
1622
1623/*
1624 * The purpose of this is to reduce the number of times wxYield is
1625 * called, since under Windows this can slow things down.
1626 */
9a29912f
JS
1627
1628void Tex2RTFYield(bool force)
1629{
532d575b 1630#ifdef __WINDOWS__
dda2e4fd 1631 static int yieldCount = 0;
254a2129 1632
dda2e4fd 1633 if (isSync)
4fe30bce 1634 return;
254a2129 1635
dda2e4fd 1636 if (force)
4fe30bce 1637 yieldCount = 0;
dda2e4fd
GD
1638 if (yieldCount == 0)
1639 {
4fe30bce
WS
1640 if (wxTheApp)
1641 wxYield();
1642 yieldCount = 10;
dda2e4fd
GD
1643 }
1644 yieldCount --;
532d575b
WS
1645#else
1646 wxUnusedVar(force);
9a29912f
JS
1647#endif
1648}
1649
1650// In both RTF generation and HTML generation for wxHelp version 2,
1651// we need to associate \indexed keywords with the current filename/topics.
1652
1653// Hash table for lists of keywords for topics (WinHelp).
1654wxHashTable TopicTable(wxKEY_STRING);
6c155d33 1655void AddKeyWordForTopic(wxChar *topic, wxChar *entry, wxChar *filename)
9a29912f
JS
1656{
1657 TexTopic *texTopic = (TexTopic *)TopicTable.Get(topic);
1658 if (!texTopic)
1659 {
1660 texTopic = new TexTopic(filename);
1661 texTopic->keywords = new wxStringList;
1662 TopicTable.Put(topic, texTopic);
1663 }
254a2129 1664
9a29912f
JS
1665 if (!texTopic->keywords->Member(entry))
1666 texTopic->keywords->Add(entry);
1667}
1668
1669void ClearKeyWordTable(void)
1670{
1671 TopicTable.BeginFind();
f6fe5318 1672 wxHashTable::Node *node = TopicTable.Next();
9a29912f
JS
1673 while (node)
1674 {
ddc4f3b5 1675 TexTopic *texTopic = (TexTopic *)node->GetData();
9a29912f
JS
1676 delete texTopic;
1677 node = TopicTable.Next();
1678 }
1679 TopicTable.Clear();
1680}
1681
1682
1683/*
1684 * TexTopic structure
1685 */
254a2129 1686
6c155d33 1687TexTopic::TexTopic(wxChar *f)
9a29912f
JS
1688{
1689 if (f)
1690 filename = copystring(f);
1691 else
1692 filename = NULL;
b63b07a8 1693 hasChildren = false;
9a29912f
JS
1694 keywords = NULL;
1695}
1696
1697TexTopic::~TexTopic(void)
1698{
1699 if (keywords)
1700 delete keywords;
1701 if (filename)
1702 delete[] filename;
1703}
1704
1705// Convert case, according to upperCaseNames setting.
6c155d33 1706wxChar *ConvertCase(wxChar *s)
9a29912f 1707{
6c155d33
JS
1708 static wxChar buf[256];
1709 int len = wxStrlen(s);
9a29912f
JS
1710 int i;
1711 if (upperCaseNames)
1712 for (i = 0; i < len; i ++)
254a2129 1713 buf[i] = (wxChar)wxToupper(s[i]);
9a29912f
JS
1714 else
1715 for (i = 0; i < len; i ++)
254a2129 1716 buf[i] = (wxChar)wxTolower(s[i]);
9a29912f 1717 buf[i] = 0;
254a2129 1718 return buf;
9a29912f 1719}
2b5f62a0 1720
4fe30bce 1721// if substring is true, search for str1 in str2
254a2129 1722bool StringMatch(const wxChar *str1, const wxChar *str2, bool subString,
2b5f62a0
VZ
1723 bool exact)
1724{
1725 if (subString)
1726 {
1727 wxString Sstr1(str1);
1728 wxString Sstr2(str2);
1729 if (!exact)
1730 {
1731 Sstr1.MakeUpper();
1732 Sstr2.MakeUpper();
1733 }
6a205442 1734 return Sstr2.Index(Sstr1) != (size_t)wxNOT_FOUND;
2b5f62a0
VZ
1735 }
1736 else
254a2129 1737 return exact ? wxString(str2).Cmp(str1) == 0 :
2b5f62a0
VZ
1738 wxString(str2).CmpNoCase(str1) == 0;
1739}