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