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