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