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