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