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