]> git.saurik.com Git - wxWidgets.git/blame - utils/tex2rtf/src/texutils.cpp
Added GetResourcesDir and GetLocalizedResourcesDir to
[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
9c9691ba
WS
486void BibEatWhiteSpace(wxString& line)
487{
488 while(!line.empty() && (line[0] == _T(' ') || line[0] == _T('\t') || line[0] == (wxChar)EOF))
489 {
490 if (line[0] == 10)
491 BibLine ++;
492 line = line.substr(1);
493 }
494
495 // Ignore end-of-line comments
496 if (line[0] == _T('%') || line[0] == _T(';') || line[0] == _T('#'))
497 {
498 line = wxEmptyString;
499 }
500}
501
dd107c50 502void BibEatWhiteSpace(wxSTD istream& str)
9a29912f 503{
5b7ab938 504 char ch = (char)str.peek();
254a2129
WS
505
506 while (!str.eof() && (ch == ' ' || ch == '\t' || ch == 13 || ch == 10 || ch == (char)EOF))
9a29912f
JS
507 {
508 if (ch == 10)
509 BibLine ++;
510 str.get(ch);
254a2129 511 if ((ch == (char)EOF) || str.eof()) return;
5b7ab938 512 ch = (char)str.peek();
9a29912f
JS
513 }
514
515 // Ignore end-of-line comments
516 if (ch == '%' || ch == ';' || ch == '#')
517 {
518 str.get(ch);
5b7ab938 519 ch = (char)str.peek();
9a29912f
JS
520 while (ch != 10 && ch != 13 && !str.eof())
521 {
522 str.get(ch);
5b7ab938 523 ch = (char)str.peek();
9a29912f
JS
524 }
525 BibEatWhiteSpace(str);
526 }
527}
528
529// Read word up to { or , or space
9c9691ba
WS
530wxString BibReadWord(wxString& line)
531{
532 wxString val;
533
534 while (!line.empty() &&
535 line[0] != _T('\t') &&
536 line[0] != _T(' ') &&
537 line[0] != _T('{') &&
538 line[0] != _T('(') &&
539 line[0] != _T(',') &&
540 line[0] != _T('='))
541 {
542 val << line[0];
543 line = line.substr(1);
544 }
545 return val;
546}
547
6c155d33 548void BibReadWord(wxSTD istream& istr, wxChar *buffer)
9a29912f
JS
549{
550 int i = 0;
551 buffer[i] = 0;
5b7ab938 552 char ch = (char)istr.peek();
9a29912f
JS
553 while (!istr.eof() && ch != ' ' && ch != '{' && ch != '(' && ch != 13 && ch != 10 && ch != '\t' &&
554 ch != ',' && ch != '=')
555 {
556 istr.get(ch);
557 buffer[i] = ch;
558 i ++;
5b7ab938 559 ch = (char)istr.peek();
9a29912f
JS
560 }
561 buffer[i] = 0;
562}
563
564// Read string (double-quoted or not) to end quote or EOL
9c9691ba 565wxString BibReadToEOL(wxString& line)
9a29912f 566{
9c9691ba
WS
567 if(line.empty())
568 return wxEmptyString;
569
570 wxString val;
571 bool inQuotes = false;
572 if (line[0] == _T('"'))
573 {
574 line = line.substr(1);
575 inQuotes = true;
576 }
577 // If in quotes, read white space too. If not,
578 // stop at white space or comment.
579 while (!line.empty() && line[0] != _T('"') &&
580 (inQuotes || ((line[0] != _T(' ')) && (line[0] != 9) &&
581 (line[0] != _T(';')) && (line[0] != _T('%')) && (line[0] != _T('#')))))
582 {
583 val << line[0];
584 line = line.substr(1);
585 }
586 if (line[0] == '"')
587 line = line.substr(1);
588
589 return val;
9a29912f
JS
590}
591
9c9691ba 592void BibReadToEOL(wxSTD istream& istr, wxChar *buffer)
9a29912f 593{
9c9691ba
WS
594 int i = 0;
595 buffer[i] = 0;
596 char ch = (char)istr.peek();
597 bool inQuotes = false;
598 if (ch == '"')
9a29912f 599 {
9c9691ba
WS
600 istr.get(ch);
601 ch = (char)istr.peek();
602 inQuotes = true;
9a29912f 603 }
9c9691ba
WS
604 // If in quotes, read white space too. If not,
605 // stop at white space or comment.
606 while (!istr.eof() && ch != 13 && ch != 10 && ch != _T('"') &&
607 (inQuotes || ((ch != _T(' ')) && (ch != 9) &&
608 (ch != _T(';')) && (ch != _T('%')) && (ch != _T('#')))))
609 {
610 istr.get(ch);
611 buffer[i] = ch;
612 i ++;
613 ch = (char)istr.peek();
614 }
615 if (ch == '"')
616 istr.get(ch);
617 buffer[i] = 0;
618}
254a2129 619
9c9691ba
WS
620// Read }-terminated value, taking nested braces into account.
621wxString BibReadValue(wxString& line,
622 bool ignoreBraces = true,
623 bool quotesMayTerminate = true)
624{
625 wxString val;
626 int braceCount = 1;
627 bool stopping = false;
9a29912f 628
9c9691ba 629 if (line.length() >= 4000)
9a29912f 630 {
9c9691ba
WS
631 wxChar buf[100];
632 wxSnprintf(buf, sizeof(buf), _T("Sorry, value > 4000 chars in bib file at line %ld."), BibLine);
633 wxLogError(buf, "Tex2RTF Fatal Error");
634 return wxEmptyString;
9a29912f 635 }
9c9691ba
WS
636
637 while (!line.empty() && !stopping)
9a29912f 638 {
9c9691ba
WS
639 wxChar ch = line[0];
640 line = line.substr(1);
641
642 if (ch == _T('{'))
643 braceCount ++;
644
645 if (ch == _T('}'))
646 {
647 braceCount --;
648 if (braceCount == 0)
649 {
650 stopping = true;
651 break;
652 }
653 }
654 else if (quotesMayTerminate && ch == _T('"'))
655 {
656 stopping = true;
657 break;
658 }
659
660 if (!stopping)
661 {
662 if (!ignoreBraces || (ch != _T('{') && ch != _T('}')))
663 {
664 val << ch;
665 }
666 }
9a29912f 667 }
9c9691ba
WS
668
669 return val;
670}
671
672void BibReadValue(wxSTD istream& istr, wxChar *buffer, bool ignoreBraces = true,
673 bool quotesMayTerminate = true)
674{
675 int braceCount = 1;
676 int i = 0;
677 buffer[i] = 0;
678 char ch = (char)istr.peek();
679 bool stopping = false;
680 while (!istr.eof() && !stopping)
681 {
682// i ++;
683 if (i >= 4000)
684 {
685 wxChar buf[100];
686 wxSnprintf(buf, sizeof(buf), _T("Sorry, value > 4000 chars in bib file at line %ld."), BibLine);
687 wxLogError(buf, "Tex2RTF Fatal Error");
688 return;
689 }
690 istr.get(ch);
691
692 if (ch == '{')
693 braceCount ++;
694
695 if (ch == '}')
696 {
697 braceCount --;
698 if (braceCount == 0)
699 {
700 stopping = true;
701 break;
702 }
703 }
704 else if (quotesMayTerminate && ch == '"')
705 {
706 stopping = true;
707 break;
708 }
709 if (!stopping)
710 {
711 if (!ignoreBraces || (ch != '{' && ch != '}'))
712 {
713 buffer[i] = ch;
714 i ++;
715 }
716 }
717 if (ch == 10)
718 BibLine ++;
9a29912f 719 }
9c9691ba
WS
720 buffer[i] = 0;
721 wxUnusedVar(stopping);
9a29912f 722}
254a2129 723
6c155d33 724bool ReadBib(wxChar *filename)
9a29912f 725{
dbda9e86 726 if (!wxFileExists(filename))
b63b07a8 727 return false;
dbda9e86 728
b63b07a8 729 wxString name = filename;
6c155d33 730 wxChar buf[300];
b63b07a8
RL
731 wxSTD ifstream istr((char const *)name.fn_str(), wxSTD ios::in);
732 if (istr.bad()) return false;
9a29912f
JS
733
734 BibLine = 1;
735
6c155d33 736 OnInform(_T("Reading .bib file..."));
9a29912f
JS
737
738 char ch;
6c155d33
JS
739 wxChar fieldValue[4000];
740 wxChar recordType[100];
741 wxChar recordKey[100];
742 wxChar recordField[100];
9a29912f
JS
743 while (!istr.eof())
744 {
745 Tex2RTFYield();
746
747 BibEatWhiteSpace(istr);
748 istr.get(ch);
749 if (ch != '@')
750 {
b63b07a8 751 wxSnprintf(buf, sizeof(buf), _T("Expected @: malformed bib file at line %ld (%s)"), BibLine, filename);
9a29912f 752 OnError(buf);
b63b07a8 753 return false;
9a29912f
JS
754 }
755 BibReadWord(istr, recordType);
756 BibEatWhiteSpace(istr);
757 istr.get(ch);
758 if (ch != '{' && ch != '(')
759 {
b63b07a8 760 wxSnprintf(buf, sizeof(buf), _T("Expected { or ( after record type: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 761 OnError(buf);
b63b07a8 762 return false;
9a29912f
JS
763 }
764 BibEatWhiteSpace(istr);
b63b07a8 765 if (StringMatch(recordType, _T("string"), false, true))
9a29912f
JS
766 {
767 BibReadWord(istr, recordType);
768 BibEatWhiteSpace(istr);
769 istr.get(ch);
770 if (ch != '=')
771 {
b63b07a8 772 wxSnprintf(buf, sizeof(buf), _T("Expected = after string key: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 773 OnError(buf);
b63b07a8 774 return false;
9a29912f
JS
775 }
776 BibEatWhiteSpace(istr);
777 istr.get(ch);
778 if (ch != '"' && ch != '{')
779 {
b63b07a8 780 wxSnprintf(buf, sizeof(buf), _T("Expected = after string key: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 781 OnError(buf);
b63b07a8 782 return false;
9a29912f
JS
783 }
784 BibReadValue(istr, fieldValue);
785
786 // Now put in hash table if necesary
787 if (!BibStringTable.Get(recordType))
788 BibStringTable.Put(recordType, (wxObject *)copystring(fieldValue));
789
790 // Read closing ) or }
791 BibEatWhiteSpace(istr);
792 istr.get(ch);
793 BibEatWhiteSpace(istr);
794 }
795 else
796 {
797 BibReadWord(istr, recordKey);
798
799 BibEntry *bibEntry = new BibEntry;
800 bibEntry->key = copystring(recordKey);
801 bibEntry->type = copystring(recordType);
802
b63b07a8 803 bool moreRecords = true;
9a29912f
JS
804 while (moreRecords && !istr.eof())
805 {
806 BibEatWhiteSpace(istr);
807 istr.get(ch);
808 if (ch == '}' || ch == ')')
809 {
b63b07a8 810 moreRecords = false;
9a29912f
JS
811 }
812 else if (ch == ',')
813 {
814 BibEatWhiteSpace(istr);
815 BibReadWord(istr, recordField);
816 BibEatWhiteSpace(istr);
817 istr.get(ch);
818 if (ch != '=')
819 {
b63b07a8 820 wxSnprintf(buf, sizeof(buf), _T("Expected = after field type: malformed .bib file at line %ld (%s)"), BibLine, filename);
9a29912f 821 OnError(buf);
b63b07a8 822 return false;
9a29912f
JS
823 }
824 BibEatWhiteSpace(istr);
825 istr.get(ch);
826 if (ch != '{' && ch != '"')
827 {
828 fieldValue[0] = ch;
829 BibReadWord(istr, fieldValue+1);
830
831 // If in the table of strings, replace with string from table.
6c155d33 832 wxChar *s = (wxChar *)BibStringTable.Get(fieldValue);
9a29912f
JS
833 if (s)
834 {
6c155d33 835 wxStrcpy(fieldValue, s);
9a29912f
JS
836 }
837 }
838 else
b63b07a8 839 BibReadValue(istr, fieldValue, true, (ch == _T('"') ? true : false));
9a29912f
JS
840
841 // Now we can add a field
b63b07a8 842 if (StringMatch(recordField, _T("author"), false, true))
9a29912f 843 bibEntry->author = copystring(fieldValue);
b63b07a8 844 else if (StringMatch(recordField, _T("key"), false, true))
9a29912f 845 {}
b63b07a8 846 else if (StringMatch(recordField, _T("annotate"), false, true))
9a29912f 847 {}
b63b07a8 848 else if (StringMatch(recordField, _T("abstract"), false, true))
9a29912f 849 {}
b63b07a8 850 else if (StringMatch(recordField, _T("edition"), false, true))
9a29912f 851 {}
b63b07a8 852 else if (StringMatch(recordField, _T("howpublished"), false, true))
9a29912f 853 {}
b63b07a8 854 else if (StringMatch(recordField, _T("note"), false, true) || StringMatch(recordField, _T("notes"), false, true))
9a29912f 855 {}
b63b07a8 856 else if (StringMatch(recordField, _T("series"), false, true))
9a29912f 857 {}
b63b07a8 858 else if (StringMatch(recordField, _T("type"), false, true))
9a29912f 859 {}
b63b07a8 860 else if (StringMatch(recordField, _T("keywords"), false, true))
9a29912f 861 {}
b63b07a8 862 else if (StringMatch(recordField, _T("editor"), false, true) || StringMatch(recordField, _T("editors"), false, true))
9a29912f 863 bibEntry->editor= copystring(fieldValue);
b63b07a8 864 else if (StringMatch(recordField, _T("title"), false, true))
9a29912f 865 bibEntry->title= copystring(fieldValue);
b63b07a8 866 else if (StringMatch(recordField, _T("booktitle"), false, true))
9a29912f 867 bibEntry->booktitle= copystring(fieldValue);
b63b07a8 868 else if (StringMatch(recordField, _T("journal"), false, true))
9a29912f 869 bibEntry->journal= copystring(fieldValue);
b63b07a8 870 else if (StringMatch(recordField, _T("volume"), false, true))
9a29912f 871 bibEntry->volume= copystring(fieldValue);
b63b07a8 872 else if (StringMatch(recordField, _T("number"), false, true))
9a29912f 873 bibEntry->number= copystring(fieldValue);
b63b07a8 874 else if (StringMatch(recordField, _T("year"), false, true))
9a29912f 875 bibEntry->year= copystring(fieldValue);
b63b07a8 876 else if (StringMatch(recordField, _T("month"), false, true))
9a29912f 877 bibEntry->month= copystring(fieldValue);
b63b07a8 878 else if (StringMatch(recordField, _T("pages"), false, true))
9a29912f 879 bibEntry->pages= copystring(fieldValue);
b63b07a8 880 else if (StringMatch(recordField, _T("publisher"), false, true))
9a29912f 881 bibEntry->publisher= copystring(fieldValue);
b63b07a8 882 else if (StringMatch(recordField, _T("address"), false, true))
9a29912f 883 bibEntry->address= copystring(fieldValue);
b63b07a8 884 else if (StringMatch(recordField, _T("institution"), false, true) || StringMatch(recordField, _T("school"), false, true))
9a29912f 885 bibEntry->institution= copystring(fieldValue);
b63b07a8 886 else if (StringMatch(recordField, _T("organization"), false, true) || StringMatch(recordField, _T("organisation"), false, true))
9a29912f 887 bibEntry->organization= copystring(fieldValue);
b63b07a8 888 else if (StringMatch(recordField, _T("comment"), false, true) || StringMatch(recordField, _T("comments"), false, true))
9a29912f 889 bibEntry->comment= copystring(fieldValue);
b63b07a8 890 else if (StringMatch(recordField, _T("annote"), false, true))
9a29912f 891 bibEntry->comment= copystring(fieldValue);
b63b07a8 892 else if (StringMatch(recordField, _T("chapter"), false, true))
9a29912f
JS
893 bibEntry->chapter= copystring(fieldValue);
894 else
895 {
b63b07a8 896 wxSnprintf(buf, sizeof(buf), _T("Unrecognised bib field type %s at line %ld (%s)"), recordField, BibLine, filename);
9a29912f
JS
897 OnError(buf);
898 }
899 }
900 }
901 BibList.Append(recordKey, bibEntry);
902 BibEatWhiteSpace(istr);
903 }
904 }
b63b07a8 905 return true;
9a29912f
JS
906}
907
908void OutputBibItem(TexRef *ref, BibEntry *bib)
909{
910 Tex2RTFYield();
911
b63b07a8
RL
912 OnMacro(ltNUMBEREDBIBITEM, 2, true);
913 OnArgument(ltNUMBEREDBIBITEM, 1, true);
9a29912f 914 TexOutput(ref->sectionNumber);
b63b07a8
RL
915 OnArgument(ltNUMBEREDBIBITEM, 1, false);
916 OnArgument(ltNUMBEREDBIBITEM, 2, true);
9a29912f 917
6c155d33 918 TexOutput(_T(" "));
b63b07a8
RL
919 OnMacro(ltBF, 1, true);
920 OnArgument(ltBF, 1, true);
9a29912f
JS
921 if (bib->author)
922 TexOutput(bib->author);
b63b07a8
RL
923 OnArgument(ltBF, 1, false);
924 OnMacro(ltBF, 1, false);
6c155d33
JS
925 if (bib->author && (wxStrlen(bib->author) > 0) && (bib->author[wxStrlen(bib->author) - 1] != '.'))
926 TexOutput(_T(". "));
9a29912f 927 else
6c155d33 928 TexOutput(_T(" "));
9a29912f
JS
929
930 if (bib->year)
931 {
932 TexOutput(bib->year);
933 }
934 if (bib->month)
935 {
6c155d33 936 TexOutput(_T(" ("));
9a29912f 937 TexOutput(bib->month);
6c155d33 938 TexOutput(_T(")"));
9a29912f
JS
939 }
940 if (bib->year || bib->month)
6c155d33 941 TexOutput(_T(". "));
9a29912f 942
b63b07a8 943 if (StringMatch(bib->type, _T("article"), false, true))
9a29912f
JS
944 {
945 if (bib->title)
946 {
947 TexOutput(bib->title);
6c155d33 948 TexOutput(_T(". "));
9a29912f
JS
949 }
950 if (bib->journal)
951 {
b63b07a8
RL
952 OnMacro(ltIT, 1, true);
953 OnArgument(ltIT, 1, true);
9a29912f 954 TexOutput(bib->journal);
b63b07a8
RL
955 OnArgument(ltIT, 1, false);
956 OnMacro(ltIT, 1, false);
9a29912f
JS
957 }
958 if (bib->volume)
959 {
6c155d33 960 TexOutput(_T(", "));
b63b07a8
RL
961 OnMacro(ltBF, 1, true);
962 OnArgument(ltBF, 1, true);
9a29912f 963 TexOutput(bib->volume);
b63b07a8
RL
964 OnArgument(ltBF, 1, false);
965 OnMacro(ltBF, 1, false);
9a29912f
JS
966 }
967 if (bib->number)
968 {
6c155d33 969 TexOutput(_T("("));
9a29912f 970 TexOutput(bib->number);
6c155d33 971 TexOutput(_T(")"));
9a29912f
JS
972 }
973 if (bib->pages)
974 {
6c155d33 975 TexOutput(_T(", pages "));
9a29912f
JS
976 TexOutput(bib->pages);
977 }
6c155d33 978 TexOutput(_T("."));
9a29912f 979 }
b63b07a8
RL
980 else if (StringMatch(bib->type, _T("book"), false, true) ||
981 StringMatch(bib->type, _T("unpublished"), false, true) ||
982 StringMatch(bib->type, _T("manual"), false, true) ||
983 StringMatch(bib->type, _T("phdthesis"), false, true) ||
984 StringMatch(bib->type, _T("mastersthesis"), false, true) ||
985 StringMatch(bib->type, _T("misc"), false, true) ||
986 StringMatch(bib->type, _T("techreport"), false, true) ||
987 StringMatch(bib->type, _T("booklet"), false, true))
9a29912f
JS
988 {
989 if (bib->title || bib->booktitle)
990 {
b63b07a8
RL
991 OnMacro(ltIT, 1, true);
992 OnArgument(ltIT, 1, true);
9a29912f 993 TexOutput(bib->title ? bib->title : bib->booktitle);
6c155d33 994 TexOutput(_T(". "));
b63b07a8
RL
995 OnArgument(ltIT, 1, false);
996 OnMacro(ltIT, 1, false);
9a29912f 997 }
b63b07a8 998 if (StringMatch(bib->type, _T("phdthesis"), false, true))
6c155d33 999 TexOutput(_T("PhD thesis. "));
b63b07a8 1000 if (StringMatch(bib->type, _T("techreport"), false, true))
6c155d33 1001 TexOutput(_T("Technical report. "));
9a29912f
JS
1002 if (bib->editor)
1003 {
6c155d33 1004 TexOutput(_T("Ed. "));
9a29912f 1005 TexOutput(bib->editor);
6c155d33 1006 TexOutput(_T(". "));
9a29912f
JS
1007 }
1008 if (bib->institution)
1009 {
1010 TexOutput(bib->institution);
6c155d33 1011 TexOutput(_T(". "));
9a29912f
JS
1012 }
1013 if (bib->organization)
1014 {
1015 TexOutput(bib->organization);
6c155d33 1016 TexOutput(_T(". "));
9a29912f
JS
1017 }
1018 if (bib->publisher)
1019 {
1020 TexOutput(bib->publisher);
6c155d33 1021 TexOutput(_T(". "));
9a29912f
JS
1022 }
1023 if (bib->address)
1024 {
1025 TexOutput(bib->address);
6c155d33 1026 TexOutput(_T(". "));
9a29912f
JS
1027 }
1028 }
b63b07a8
RL
1029 else if (StringMatch(bib->type, _T("inbook"), false, true) ||
1030 StringMatch(bib->type, _T("inproceedings"), false, true) ||
1031 StringMatch(bib->type, _T("incollection"), false, true) ||
1032 StringMatch(bib->type, _T("conference"), false, true))
9a29912f
JS
1033 {
1034 if (bib->title)
1035 {
1036 TexOutput(bib->title);
1037 }
1038 if (bib->booktitle)
1039 {
6c155d33 1040 TexOutput(_T(", from "));
b63b07a8
RL
1041 OnMacro(ltIT, 1, true);
1042 OnArgument(ltIT, 1, true);
9a29912f 1043 TexOutput(bib->booktitle);
6c155d33 1044 TexOutput(_T("."));
b63b07a8
RL
1045 OnArgument(ltIT, 1, false);
1046 OnMacro(ltIT, 1, false);
9a29912f
JS
1047 }
1048 if (bib->editor)
1049 {
6c155d33 1050 TexOutput(_T(", ed. "));
9a29912f
JS
1051 TexOutput(bib->editor);
1052 }
1053 if (bib->publisher)
1054 {
6c155d33 1055 TexOutput(_T(" "));
9a29912f
JS
1056 TexOutput(bib->publisher);
1057 }
1058 if (bib->address)
1059 {
6c155d33
JS
1060 if (bib->publisher) TexOutput(_T(", "));
1061 else TexOutput(_T(" "));
9a29912f
JS
1062 TexOutput(bib->address);
1063 }
1064 if (bib->publisher || bib->address)
6c155d33 1065 TexOutput(_T("."));
9a29912f
JS
1066
1067 if (bib->volume)
1068 {
6c155d33 1069 TexOutput(_T(" "));
b63b07a8
RL
1070 OnMacro(ltBF, 1, true);
1071 OnArgument(ltBF, 1, true);
9a29912f 1072 TexOutput(bib->volume);
b63b07a8
RL
1073 OnArgument(ltBF, 1, false);
1074 OnMacro(ltBF, 1, false);
9a29912f
JS
1075 }
1076 if (bib->number)
1077 {
1078 if (bib->volume)
1079 {
6c155d33 1080 TexOutput(_T("("));
9a29912f 1081 TexOutput(bib->number);
6c155d33 1082 TexOutput(_T(")."));
9a29912f
JS
1083 }
1084 else
1085 {
6c155d33 1086 TexOutput(_T(" Number "));
9a29912f 1087 TexOutput(bib->number);
6c155d33 1088 TexOutput(_T("."));
9a29912f
JS
1089 }
1090 }
1091 if (bib->chapter)
1092 {
6c155d33
JS
1093 TexOutput(_T(" Chap. "));
1094 TexOutput(bib->chapter);
9a29912f
JS
1095 }
1096 if (bib->pages)
1097 {
6c155d33
JS
1098 if (bib->chapter) TexOutput(_T(", pages "));
1099 else TexOutput(_T(" Pages "));
9a29912f 1100 TexOutput(bib->pages);
6c155d33 1101 TexOutput(_T("."));
9a29912f
JS
1102 }
1103 }
b63b07a8
RL
1104 OnArgument(ltNUMBEREDBIBITEM, 2, false);
1105 OnMacro(ltNUMBEREDBIBITEM, 2, false);
9a29912f
JS
1106}
1107
1108void OutputBib(void)
1109{
1110 // Write the heading
6c155d33 1111 ForceTopicName(_T("bibliography"));
9a29912f
JS
1112 FakeCurrentSection(ReferencesNameString);
1113 ForceTopicName(NULL);
1114
b63b07a8
RL
1115 OnMacro(ltPAR, 0, true);
1116 OnMacro(ltPAR, 0, false);
9a29912f
JS
1117
1118 if ((convertMode == TEX_RTF) && !winHelp)
1119 {
b63b07a8
RL
1120 OnMacro(ltPAR, 0, true);
1121 OnMacro(ltPAR, 0, false);
9a29912f
JS
1122 }
1123
ddc4f3b5 1124 wxStringListNode *node = CitationList.GetFirst();
9a29912f
JS
1125 while (node)
1126 {
6c155d33 1127 wxChar *citeKey = (wxChar *)node->GetData();
9a29912f
JS
1128// wxNode *texNode = TexReferences.Find(citeKey);
1129 TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
1130 wxNode *bibNode = BibList.Find(citeKey);
1131 if (bibNode && ref)
1132 {
ddc4f3b5 1133 BibEntry *entry = (BibEntry *)bibNode->GetData();
9a29912f
JS
1134 OutputBibItem(ref, entry);
1135 }
ddc4f3b5 1136 node = node->GetNext();
9a29912f
JS
1137 }
1138}
1139
1140static int citeCount = 1;
1141
1142void ResolveBibReferences(void)
1143{
ddc4f3b5 1144 if (CitationList.GetCount() > 0)
6c155d33 1145 OnInform(_T("Resolving bibliographic references..."));
9a29912f
JS
1146
1147 citeCount = 1;
6c155d33 1148 wxChar buf[200];
ddc4f3b5 1149 wxStringListNode *node = CitationList.GetFirst();
9a29912f
JS
1150 while (node)
1151 {
1152 Tex2RTFYield();
6c155d33 1153 wxChar *citeKey = (wxChar *)node->GetData();
9a29912f
JS
1154// wxNode *texNode = TexReferences.Find(citeKey);
1155 TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
1156 wxNode *bibNode = BibList.Find(citeKey);
1157 if (bibNode && ref)
1158 {
1159 // Unused Variable
ddc4f3b5 1160 //BibEntry *entry = (BibEntry *)bibNode->GetData();
9a29912f 1161 if (ref->sectionNumber) delete[] ref->sectionNumber;
b63b07a8 1162 wxSnprintf(buf, sizeof(buf), _T("[%d]"), citeCount);
9a29912f
JS
1163 ref->sectionNumber = copystring(buf);
1164 citeCount ++;
1165 }
1166 else
1167 {
b63b07a8 1168 wxSnprintf(buf, sizeof(buf), _T("Warning: bib ref %s not resolved."), citeKey);
9a29912f
JS
1169 OnInform(buf);
1170 }
ddc4f3b5 1171 node = node->GetNext();
9a29912f
JS
1172 }
1173}
1174
1175// Remember we need to resolve this citation
6c155d33 1176void AddCitation(wxChar *citeKey)
9a29912f
JS
1177{
1178 if (!CitationList.Member(citeKey))
1179 CitationList.Add(citeKey);
1180
1181 if (!TexReferences.Get(citeKey))
1182 {
6c155d33 1183 TexReferences.Put(citeKey, new TexRef(citeKey, _T("??"), NULL));
9a29912f
JS
1184 }
1185}
1186
6c155d33 1187TexRef *FindReference(wxChar *key)
9a29912f
JS
1188{
1189 return (TexRef *)TexReferences.Get(key);
1190}
1191
1192/*
1193 * Custom macro stuff
1194 *
1195 */
1196
9c9691ba 1197bool StringTobool(const wxString& val)
9a29912f 1198{
9c9691ba
WS
1199 wxString up(val);
1200 up.MakeUpper();
1201
1202 if (up.IsSameAs(_T("YES")) ||
1203 up.IsSameAs(_T("ON")) ||
1204 up.IsSameAs(_T("OK")) |
1205 up.IsSameAs(_T("1")))
1206 return true;
1207
b63b07a8 1208 return false;
9a29912f
JS
1209}
1210
eecb33b0
WS
1211void RegisterIntSetting (const wxString& s, int *number)
1212{
1213 if (number)
1214 {
1215 long val;
1216 s.ToLong(&val);
1217 *number = (int)val;
1218 }
1219}
1220
9a29912f 1221// Define a variable value from the .ini file
9c9691ba 1222wxChar *RegisterSetting(const wxString& settingName, const wxString& settingValue, bool interactive)
9a29912f 1223{
eecb33b0
WS
1224 wxString settingValueStr( settingValue );
1225
1226 static wxChar errorCode[100];
1227 wxStrcpy(errorCode, _T("OK"));
1228 if (StringMatch(settingName, _T("chapterName"), false, true))
9a29912f 1229 {
eecb33b0
WS
1230 delete[] ChapterNameString;
1231 ChapterNameString = copystring(settingValue);
9a29912f 1232 }
eecb33b0 1233 else if (StringMatch(settingName, _T("sectionName"), false, true))
9a29912f 1234 {
eecb33b0
WS
1235 delete[] SectionNameString;
1236 SectionNameString = copystring(settingValue);
9a29912f 1237 }
eecb33b0 1238 else if (StringMatch(settingName, _T("subsectionName"), false, true))
9a29912f 1239 {
eecb33b0
WS
1240 delete[] SubsectionNameString;
1241 SubsectionNameString = copystring(settingValue);
9a29912f 1242 }
eecb33b0 1243 else if (StringMatch(settingName, _T("subsubsectionName"), false, true))
9a29912f 1244 {
eecb33b0
WS
1245 delete[] SubsubsectionNameString;
1246 SubsubsectionNameString = copystring(settingValue);
9a29912f 1247 }
eecb33b0 1248 else if (StringMatch(settingName, _T("indexName"), false, true))
9a29912f 1249 {
eecb33b0
WS
1250 delete[] IndexNameString;
1251 IndexNameString = copystring(settingValue);
9a29912f 1252 }
eecb33b0 1253 else if (StringMatch(settingName, _T("contentsName"), false, true))
9a29912f 1254 {
eecb33b0
WS
1255 delete[] ContentsNameString;
1256 ContentsNameString = copystring(settingValue);
9a29912f 1257 }
eecb33b0 1258 else if (StringMatch(settingName, _T("glossaryName"), false, true))
9a29912f 1259 {
eecb33b0
WS
1260 delete[] GlossaryNameString;
1261 GlossaryNameString = copystring(settingValue);
9a29912f 1262 }
eecb33b0 1263 else if (StringMatch(settingName, _T("referencesName"), false, true))
9a29912f 1264 {
eecb33b0
WS
1265 delete[] ReferencesNameString;
1266 ReferencesNameString = copystring(settingValue);
1267 }
1268 else if (StringMatch(settingName, _T("tablesName"), false, true))
1269 {
1270 delete[] TablesNameString;
1271 TablesNameString = copystring(settingValue);
1272 }
1273 else if (StringMatch(settingName, _T("figuresName"), false, true))
1274 {
1275 delete[] FiguresNameString;
1276 FiguresNameString = copystring(settingValue);
1277 }
1278 else if (StringMatch(settingName, _T("tableName"), false, true))
1279 {
1280 delete[] TableNameString;
1281 TableNameString = copystring(settingValue);
1282 }
1283 else if (StringMatch(settingName, _T("figureName"), false, true))
1284 {
1285 delete[] FigureNameString;
1286 FigureNameString = copystring(settingValue);
1287 }
1288 else if (StringMatch(settingName, _T("abstractName"), false, true))
1289 {
1290 delete[] AbstractNameString;
1291 AbstractNameString = copystring(settingValue);
1292 }
1293 else if (StringMatch(settingName, _T("chapterFontSize"), false, true))
1294 RegisterIntSetting(settingValueStr, &chapterFont);
1295 else if (StringMatch(settingName, _T("sectionFontSize"), false, true))
1296 RegisterIntSetting(settingValueStr, &sectionFont);
1297 else if (StringMatch(settingName, _T("subsectionFontSize"), false, true))
1298 RegisterIntSetting(settingValueStr, &subsectionFont);
1299 else if (StringMatch(settingName, _T("titleFontSize"), false, true))
1300 RegisterIntSetting(settingValueStr, &titleFont);
1301 else if (StringMatch(settingName, _T("authorFontSize"), false, true))
1302 RegisterIntSetting(settingValueStr, &authorFont);
1303 else if (StringMatch(settingName, _T("ignoreInput"), false, true))
1304 IgnorableInputFiles.Add(wxFileNameFromPath(settingValue));
1305 else if (StringMatch(settingName, _T("mirrorMargins"), false, true))
1306 mirrorMargins = StringTobool(settingValue);
1307 else if (StringMatch(settingName, _T("runTwice"), false, true))
1308 runTwice = StringTobool(settingValue);
1309 else if (StringMatch(settingName, _T("isInteractive"), false, true))
1310 isInteractive = StringTobool(settingValue);
1311 else if (StringMatch(settingName, _T("headerRule"), false, true))
1312 headerRule = StringTobool(settingValue);
1313 else if (StringMatch(settingName, _T("footerRule"), false, true))
1314 footerRule = StringTobool(settingValue);
1315 else if (StringMatch(settingName, _T("combineSubSections"), false, true))
1316 combineSubSections = StringTobool(settingValue);
1317 else if (StringMatch(settingName, _T("listLabelIndent"), false, true))
1318 RegisterIntSetting(settingValueStr, &labelIndentTab);
1319 else if (StringMatch(settingName, _T("listItemIndent"), false, true))
1320 RegisterIntSetting(settingValueStr, &itemIndentTab);
1321 else if (StringMatch(settingName, _T("useUpButton"), false, true))
1322 useUpButton = StringTobool(settingValue);
1323 else if (StringMatch(settingName, _T("useHeadingStyles"), false, true))
1324 useHeadingStyles = StringTobool(settingValue);
1325 else if (StringMatch(settingName, _T("useWord"), false, true))
1326 useWord = StringTobool(settingValue);
1327 else if (StringMatch(settingName, _T("contentsDepth"), false, true))
1328 RegisterIntSetting(settingValueStr, &contentsDepth);
1329 else if (StringMatch(settingName, _T("generateHPJ"), false, true))
1330 generateHPJ = StringTobool(settingValue);
1331 else if (StringMatch(settingName, _T("truncateFilenames"), false, true))
1332 truncateFilenames = StringTobool(settingValue);
1333 else if (StringMatch(settingName, _T("winHelpVersion"), false, true))
1334 RegisterIntSetting(settingValueStr, &winHelpVersion);
1335 else if (StringMatch(settingName, _T("winHelpContents"), false, true))
1336 winHelpContents = StringTobool(settingValue);
1337 else if (StringMatch(settingName, _T("htmlIndex"), false, true))
1338 htmlIndex = StringTobool(settingValue);
1339 else if (StringMatch(settingName, _T("htmlWorkshopFiles"), false, true))
1340 htmlWorkshopFiles = StringTobool(settingValue);
1341 else if (StringMatch(settingName, _T("htmlFrameContents"), false, true))
1342 htmlFrameContents = StringTobool(settingValue);
1343 else if (StringMatch(settingName, _T("htmlStylesheet"), false, true))
1344 {
1345 if (htmlStylesheet)
1346 delete[] htmlStylesheet;
1347 htmlStylesheet = copystring(settingValue);
1348 }
1349 else if (StringMatch(settingName, _T("upperCaseNames"), false, true))
1350 upperCaseNames = StringTobool(settingValue);
1351 else if (StringMatch(settingName, _T("ignoreBadRefs"), false, true))
1352 ignoreBadRefs = StringTobool(settingValue);
1353 else if (StringMatch(settingName, _T("htmlFaceName"), false, true))
1354 {
1355 delete[] htmlFaceName;
1356 htmlFaceName = copystring(settingValue);
1357 }
1358 else if (StringMatch(settingName, _T("winHelpTitle"), false, true))
1359 {
1360 if (winHelpTitle)
1361 delete[] winHelpTitle;
1362 winHelpTitle = copystring(settingValue);
1363 }
1364 else if (StringMatch(settingName, _T("indexSubsections"), false, true))
1365 indexSubsections = StringTobool(settingValue);
1366 else if (StringMatch(settingName, _T("compatibility"), false, true))
1367 compatibilityMode = StringTobool(settingValue);
1368 else if (StringMatch(settingName, _T("defaultColumnWidth"), false, true))
1369 {
1370 RegisterIntSetting(settingValueStr, &defaultTableColumnWidth);
1371 defaultTableColumnWidth = 20*defaultTableColumnWidth;
1372 }
1373 else if (StringMatch(settingName, _T("bitmapMethod"), false, true))
1374 {
1375 if ((wxStrcmp(settingValue, _T("includepicture")) != 0) && (wxStrcmp(settingValue, _T("hex")) != 0) &&
1376 (wxStrcmp(settingValue, _T("import")) != 0))
1377 {
1378 if (interactive)
1379 OnError(_T("Unknown bitmapMethod"));
1380 wxStrcpy(errorCode, _T("Unknown bitmapMethod"));
1381 }
1382 else
1383 {
1384 delete[] bitmapMethod;
1385 bitmapMethod = copystring(settingValue);
1386 }
1387 }
1388 else if (StringMatch(settingName, _T("htmlBrowseButtons"), false, true))
1389 {
1390 if (wxStrcmp(settingValue, _T("none")) == 0)
1391 htmlBrowseButtons = HTML_BUTTONS_NONE;
1392 else if (wxStrcmp(settingValue, _T("bitmap")) == 0)
1393 htmlBrowseButtons = HTML_BUTTONS_BITMAP;
1394 else if (wxStrcmp(settingValue, _T("text")) == 0)
1395 htmlBrowseButtons = HTML_BUTTONS_TEXT;
1396 else
1397 {
1398 if (interactive)
1399 OnInform(_T("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text."));
1400 wxStrcpy(errorCode, _T("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text."));
1401 }
1402 }
1403 else if (StringMatch(settingName, _T("backgroundImage"), false, true))
1404 {
1405 backgroundImageString = copystring(settingValue);
1406 }
1407 else if (StringMatch(settingName, _T("backgroundColour"), false, true))
1408 {
1409 delete[] backgroundColourString;
1410 backgroundColourString = copystring(settingValue);
1411 }
1412 else if (StringMatch(settingName, _T("textColour"), false, true))
1413 {
1414 textColourString = copystring(settingValue);
1415 }
1416 else if (StringMatch(settingName, _T("linkColour"), false, true))
1417 {
1418 linkColourString = copystring(settingValue);
1419 }
1420 else if (StringMatch(settingName, _T("followedLinkColour"), false, true))
1421 {
1422 followedLinkColourString = copystring(settingValue);
1423 }
1424 else if (StringMatch(settingName, _T("conversionMode"), false, true))
1425 {
1426 if (StringMatch(settingValue, _T("RTF"), false, true))
1427 {
1428 winHelp = false; convertMode = TEX_RTF;
1429 }
1430 else if (StringMatch(settingValue, _T("WinHelp"), false, true))
1431 {
1432 winHelp = true; convertMode = TEX_RTF;
1433 }
1434 else if (StringMatch(settingValue, _T("XLP"), false, true) ||
1435 StringMatch(settingValue, _T("wxHelp"), false, true))
1436 {
1437 convertMode = TEX_XLP;
1438 }
1439 else if (StringMatch(settingValue, _T("HTML"), false, true))
1440 {
1441 convertMode = TEX_HTML;
1442 }
1443 else
1444 {
1445 if (interactive)
1446 OnInform(_T("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML."));
1447 wxStrcpy(errorCode, _T("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML."));
1448 }
1449 }
1450 else if (StringMatch(settingName, _T("documentFontSize"), false, true))
1451 {
1452 int n;
1453 RegisterIntSetting(settingValueStr, &n);
1454 if (n == 10 || n == 11 || n == 12)
1455 SetFontSizes(n);
1456 else
1457 {
1458 wxChar buf[200];
1459 wxSnprintf(buf, sizeof(buf), _T("Initialisation file error: nonstandard document font size %d."), n);
1460 if (interactive)
1461 OnInform(buf);
1462 wxStrcpy(errorCode, buf);
1463 }
9a29912f 1464 }
9a29912f
JS
1465 else
1466 {
eecb33b0 1467 wxChar buf[200];
9c9691ba 1468 wxSnprintf(buf, sizeof(buf), _T("Initialisation file error: unrecognised setting %s."), settingName.c_str());
eecb33b0
WS
1469 if (interactive)
1470 OnInform(buf);
1471 wxStrcpy(errorCode, buf);
9a29912f 1472 }
eecb33b0 1473 return errorCode;
9a29912f
JS
1474}
1475
9c9691ba 1476bool ReadCustomMacros(const wxString& filename)
9a29912f 1477{
9c9691ba
WS
1478 if (!wxFileExists(filename))
1479 return false;
dbda9e86 1480
9c9691ba
WS
1481 wxFileInputStream input( filename );
1482 if(!input.Ok()) return false;
1483 wxTextInputStream ini( input );
dbda9e86 1484
9c9691ba 1485 CustomMacroList.Clear();
9a29912f 1486
9c9691ba
WS
1487 while (!input.Eof())
1488 {
1489 wxString line = ini.ReadLine();
1490 BibEatWhiteSpace(line);
1491 if (line.empty()) continue;
9a29912f 1492
9c9691ba
WS
1493 if (line[0] != _T('\\')) // Not a macro definition, so must be NAME=VALUE
1494 {
1495 wxString settingName = BibReadWord(line);
1496 BibEatWhiteSpace(line);
1497 if (line.empty() || line[0] != _T('='))
1498 {
1499 OnError(_T("Expected = following name: malformed tex2rtf.ini file."));
1500 return false;
1501 }
1502 else
1503 {
1504 line = line.substr(1);
1505 BibEatWhiteSpace(line);
1506 wxString settingValue = BibReadToEOL(line);
1507 RegisterSetting(settingName, settingValue);
1508 }
1509 }
1510 else
1511 {
1512 line = line.substr(1);
1513 wxString macroName = BibReadWord(line);
1514 BibEatWhiteSpace(line);
1515 if (line[0] != _T('['))
1516 {
1517 OnError(_T("Expected [ followed by number of arguments: malformed tex2rtf.ini file."));
1518 return false;
1519 }
1520 line = line.substr(1);
1521 wxString noAargStr = line.BeforeFirst(_T(']'));
1522 line = line.AfterFirst(_T(']'));
1523 long noArgs;
1524 if (!noAargStr.ToLong(&noArgs) || line.empty())
1525 {
1526 OnError(_T("Expected ] following number of arguments: malformed tex2rtf.ini file."));
1527 return false;
1528 }
1529 BibEatWhiteSpace(line);
1530 if (line[0] != _T('{'))
1531 {
1532 OnError(_T("Expected { followed by macro body: malformed tex2rtf.ini file."));
1533 return false;
1534 }
254a2129 1535
9c9691ba
WS
1536 CustomMacro *macro = new CustomMacro(macroName.c_str(), noArgs, NULL);
1537 wxString macroBody = BibReadValue(line, false, false); // Don't ignore extra braces
1538 if (!macroBody.empty())
1539 macro->macroBody = copystring(macroBody.c_str());
1540
1541 BibEatWhiteSpace(line);
1542 CustomMacroList.Append(macroName.c_str(), macro);
1543 AddMacroDef(ltCUSTOM_MACRO, macroName.c_str(), noArgs);
1544 }
254a2129 1545
9a29912f 1546 }
9c9691ba
WS
1547 wxChar mbuf[200];
1548 wxSnprintf(mbuf, sizeof(mbuf), _T("Read initialization file %s."), filename.c_str());
1549 OnInform(mbuf);
1550 return true;
9a29912f 1551}
254a2129 1552
6c155d33 1553CustomMacro *FindCustomMacro(wxChar *name)
9a29912f
JS
1554{
1555 wxNode *node = CustomMacroList.Find(name);
1556 if (node)
1557 {
ddc4f3b5 1558 CustomMacro *macro = (CustomMacro *)node->GetData();
9a29912f
JS
1559 return macro;
1560 }
1561 return NULL;
1562}
1563
1564// Display custom macros
1565void ShowCustomMacros(void)
1566{
ddc4f3b5 1567 wxNode *node = CustomMacroList.GetFirst();
9a29912f
JS
1568 if (!node)
1569 {
6c155d33 1570 OnInform(_T("No custom macros loaded.\n"));
9a29912f
JS
1571 return;
1572 }
254a2129 1573
6c155d33 1574 wxChar buf[400];
9a29912f
JS
1575 while (node)
1576 {
ddc4f3b5 1577 CustomMacro *macro = (CustomMacro *)node->GetData();
b63b07a8 1578 wxSnprintf(buf, sizeof(buf), _T("\\%s[%d]\n {%s}"), macro->macroName, macro->noArgs,
6c155d33 1579 macro->macroBody ? macro->macroBody : _T(""));
9a29912f 1580 OnInform(buf);
ddc4f3b5 1581 node = node->GetNext();
9a29912f
JS
1582 }
1583}
1584
1585// Parse a string into several comma-separated fields
6c155d33 1586wxChar *ParseMultifieldString(wxChar *allFields, int *pos)
9a29912f 1587{
6c155d33 1588 static wxChar buffer[300];
9a29912f
JS
1589 int i = 0;
1590 int fieldIndex = *pos;
6c155d33 1591 int len = wxStrlen(allFields);
9a29912f 1592 int oldPos = *pos;
b63b07a8 1593 bool keepGoing = true;
9a29912f
JS
1594 while ((fieldIndex <= len) && keepGoing)
1595 {
6c155d33 1596 if (allFields[fieldIndex] == _T(' '))
9a29912f
JS
1597 {
1598 // Skip
1599 fieldIndex ++;
1600 }
6c155d33 1601 else if (allFields[fieldIndex] == _T(','))
9a29912f
JS
1602 {
1603 *pos = fieldIndex + 1;
b63b07a8 1604 keepGoing = false;
9a29912f
JS
1605 }
1606 else if (allFields[fieldIndex] == 0)
1607 {
1608 *pos = fieldIndex + 1;
b63b07a8 1609 keepGoing = false;
9a29912f
JS
1610 }
1611 else
1612 {
1613 buffer[i] = allFields[fieldIndex];
1614 fieldIndex ++;
1615 i++;
1616 }
1617 }
1618 buffer[i] = 0;
1619 if (oldPos == (*pos))
1620 *pos = len + 1;
254a2129 1621
9a29912f
JS
1622 if (i == 0)
1623 return NULL;
1624 else
1625 return buffer;
1626}
1627
1628/*
1629 * Colour tables
1630 *
1631 */
254a2129 1632
6c155d33 1633ColourTableEntry::ColourTableEntry(const wxChar *theName, unsigned int r, unsigned int g, unsigned int b)
9a29912f
JS
1634{
1635 name = copystring(theName);
1636 red = r;
1637 green = g;
1638 blue = b;
1639}
1640
1641ColourTableEntry::~ColourTableEntry(void)
1642{
1643 delete[] name;
1644}
1645
6c155d33 1646void AddColour(const wxChar *theName, unsigned int r, unsigned int g, unsigned int b)
9a29912f
JS
1647{
1648 wxNode *node = ColourTable.Find(theName);
1649 if (node)
1650 {
ddc4f3b5 1651 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
9a29912f
JS
1652 if (entry->red == r || entry->green == g || entry->blue == b)
1653 return;
1654 else
1655 {
1656 delete entry;
1657 delete node;
1658 }
1659 }
1660 ColourTableEntry *entry = new ColourTableEntry(theName, r, g, b);
1661 ColourTable.Append(theName, entry);
1662}
1663
6c155d33 1664int FindColourPosition(wxChar *theName)
9a29912f
JS
1665{
1666 int i = 0;
ddc4f3b5 1667 wxNode *node = ColourTable.GetFirst();
9a29912f
JS
1668 while (node)
1669 {
ddc4f3b5 1670 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
6c155d33 1671 if (wxStrcmp(theName, entry->name) == 0)
9a29912f
JS
1672 return i;
1673 i ++;
ddc4f3b5 1674 node = node->GetNext();
9a29912f
JS
1675 }
1676 return -1;
1677}
1678
1679// Converts e.g. "red" -> "#FF0000"
6c155d33
JS
1680extern void DecToHex(int, wxChar *);
1681bool FindColourHTMLString(wxChar *theName, wxChar *buf)
9a29912f 1682{
ddc4f3b5 1683 wxNode *node = ColourTable.GetFirst();
9a29912f
JS
1684 while (node)
1685 {
ddc4f3b5 1686 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
6c155d33 1687 if (wxStrcmp(theName, entry->name) == 0)
9a29912f 1688 {
6c155d33 1689 wxStrcpy(buf, _T("#"));
254a2129 1690
6c155d33 1691 wxChar buf2[3];
9a29912f 1692 DecToHex(entry->red, buf2);
6c155d33 1693 wxStrcat(buf, buf2);
9a29912f 1694 DecToHex(entry->green, buf2);
6c155d33 1695 wxStrcat(buf, buf2);
9a29912f 1696 DecToHex(entry->blue, buf2);
6c155d33 1697 wxStrcat(buf, buf2);
9a29912f 1698
b63b07a8 1699 return true;
9a29912f 1700 }
ddc4f3b5 1701 node = node->GetNext();
9a29912f 1702 }
b63b07a8 1703 return false;
9a29912f
JS
1704}
1705
254a2129 1706
9a29912f
JS
1707void InitialiseColourTable(void)
1708{
1709 // \\red0\\green0\\blue0;
6c155d33 1710 AddColour(_T("black"), 0,0,0);
9a29912f
JS
1711
1712 // \\red0\\green0\\blue255;\\red0\\green255\\blue255;\n");
6c155d33 1713 AddColour(_T("cyan"), 0,255,255);
9a29912f
JS
1714
1715 // \\red0\\green255\\blue0;
6c155d33 1716 AddColour(_T("green"), 0,255,0);
254a2129 1717
9a29912f 1718 // \\red255\\green0\\blue255;
6c155d33 1719 AddColour(_T("magenta"), 255,0,255);
9a29912f
JS
1720
1721 // \\red255\\green0\\blue0;
6c155d33 1722 AddColour(_T("red"), 255,0,0);
254a2129 1723
9a29912f 1724 // \\red255\\green255\\blue0;
6c155d33 1725 AddColour(_T("yellow"), 255,255,0);
254a2129 1726
9a29912f 1727 // \\red255\\green255\\blue255;}");
6c155d33 1728 AddColour(_T("white"), 255,255,255);
9a29912f
JS
1729}
1730
1731/*
1732 * The purpose of this is to reduce the number of times wxYield is
1733 * called, since under Windows this can slow things down.
1734 */
9a29912f
JS
1735
1736void Tex2RTFYield(bool force)
1737{
532d575b 1738#ifdef __WINDOWS__
dda2e4fd 1739 static int yieldCount = 0;
254a2129 1740
dda2e4fd 1741 if (isSync)
4fe30bce 1742 return;
254a2129 1743
dda2e4fd 1744 if (force)
4fe30bce 1745 yieldCount = 0;
dda2e4fd
GD
1746 if (yieldCount == 0)
1747 {
4fe30bce
WS
1748 if (wxTheApp)
1749 wxYield();
1750 yieldCount = 10;
dda2e4fd
GD
1751 }
1752 yieldCount --;
532d575b
WS
1753#else
1754 wxUnusedVar(force);
9a29912f
JS
1755#endif
1756}
1757
1758// In both RTF generation and HTML generation for wxHelp version 2,
1759// we need to associate \indexed keywords with the current filename/topics.
1760
1761// Hash table for lists of keywords for topics (WinHelp).
1762wxHashTable TopicTable(wxKEY_STRING);
6c155d33 1763void AddKeyWordForTopic(wxChar *topic, wxChar *entry, wxChar *filename)
9a29912f
JS
1764{
1765 TexTopic *texTopic = (TexTopic *)TopicTable.Get(topic);
1766 if (!texTopic)
1767 {
1768 texTopic = new TexTopic(filename);
1769 texTopic->keywords = new wxStringList;
1770 TopicTable.Put(topic, texTopic);
1771 }
254a2129 1772
9a29912f
JS
1773 if (!texTopic->keywords->Member(entry))
1774 texTopic->keywords->Add(entry);
1775}
1776
1777void ClearKeyWordTable(void)
1778{
1779 TopicTable.BeginFind();
f6fe5318 1780 wxHashTable::Node *node = TopicTable.Next();
9a29912f
JS
1781 while (node)
1782 {
ddc4f3b5 1783 TexTopic *texTopic = (TexTopic *)node->GetData();
9a29912f
JS
1784 delete texTopic;
1785 node = TopicTable.Next();
1786 }
1787 TopicTable.Clear();
1788}
1789
1790
1791/*
1792 * TexTopic structure
1793 */
254a2129 1794
6c155d33 1795TexTopic::TexTopic(wxChar *f)
9a29912f
JS
1796{
1797 if (f)
1798 filename = copystring(f);
1799 else
1800 filename = NULL;
b63b07a8 1801 hasChildren = false;
9a29912f
JS
1802 keywords = NULL;
1803}
1804
1805TexTopic::~TexTopic(void)
1806{
1807 if (keywords)
1808 delete keywords;
1809 if (filename)
1810 delete[] filename;
1811}
1812
1813// Convert case, according to upperCaseNames setting.
6c155d33 1814wxChar *ConvertCase(wxChar *s)
9a29912f 1815{
6c155d33
JS
1816 static wxChar buf[256];
1817 int len = wxStrlen(s);
9a29912f
JS
1818 int i;
1819 if (upperCaseNames)
1820 for (i = 0; i < len; i ++)
254a2129 1821 buf[i] = (wxChar)wxToupper(s[i]);
9a29912f
JS
1822 else
1823 for (i = 0; i < len; i ++)
254a2129 1824 buf[i] = (wxChar)wxTolower(s[i]);
9a29912f 1825 buf[i] = 0;
254a2129 1826 return buf;
9a29912f 1827}
2b5f62a0 1828
4fe30bce 1829// if substring is true, search for str1 in str2
254a2129 1830bool StringMatch(const wxChar *str1, const wxChar *str2, bool subString,
2b5f62a0
VZ
1831 bool exact)
1832{
1833 if (subString)
1834 {
1835 wxString Sstr1(str1);
1836 wxString Sstr2(str2);
1837 if (!exact)
1838 {
1839 Sstr1.MakeUpper();
1840 Sstr2.MakeUpper();
1841 }
6a205442 1842 return Sstr2.Index(Sstr1) != (size_t)wxNOT_FOUND;
2b5f62a0
VZ
1843 }
1844 else
254a2129 1845 return exact ? wxString(str2).Cmp(str1) == 0 :
2b5f62a0
VZ
1846 wxString(str2).CmpNoCase(str1) == 0;
1847}