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