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