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