]> git.saurik.com Git - wxWidgets.git/blame - utils/tex2rtf/src/texutils.cpp
fixed typo in wxString::swap() which was completely broken
[wxWidgets.git] / utils / tex2rtf / src / texutils.cpp
CommitLineData
9a29912f
JS
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
5aa5c1e4 27#include "wx/hash.h"
9a29912f 28
1a464ed9
JS
29#ifdef new
30#undef new
31#endif
32
9a29912f
JS
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
44wxHashTable TexReferences(wxKEY_STRING);
45wxList BibList(wxKEY_STRING);
46wxStringList CitationList;
47wxList ColourTable(wxKEY_STRING);
48wxHashTable BibStringTable(wxKEY_STRING);
49wxList CustomMacroList(wxKEY_STRING);
50TexChunk *currentSection = NULL;
51char *fakeCurrentSection = NULL;
52
53static long BibLine = 1;
54
55void 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).
65void OutputCurrentSectionToString(char *buf)
66{
67 if (fakeCurrentSection)
68 strcpy(buf, fakeCurrentSection);
69 else
70 OutputChunkToString(currentSection, buf);
71}
72
73void 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
116void 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.
144static long topicCounter = 0;
145
146void ResetTopicCounter(void)
147{
148 topicCounter = 0;
149}
150
151static char *forceTopicName = NULL;
152
bbd08c6a 153void ForceTopicName(const char *name)
9a29912f
JS
154{
155 if (forceTopicName)
156 delete[] forceTopicName;
157 if (name)
158 forceTopicName = copystring(name);
159 else
160 forceTopicName = NULL;
161}
162
163char *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
207void StartSimulateArgument(char *data)
208{
209 strcpy(currentArgData, data);
210 haveArgData = TRUE;
211}
212
213void EndSimulateArgument(void)
214{
215 haveArgData = FALSE;
216}
217
218/*
219 * Parse and convert unit arguments to points
220 *
221 */
222
223int 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)
f90e5ed2 246 conversionFactor = (float)72.0/(float)2.51;
9a29912f 247 else if (strcmp(units, "mm") == 0)
f90e5ed2 248 conversionFactor = (float)72.0/(float)25.1;
9a29912f
JS
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
263void 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
283void 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
335void 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
383void WriteTexReferences(char *filename)
384{
dd107c50 385 wxSTD ofstream ostr(filename);
9a29912f
JS
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
407void ReadTexReferences(char *filename)
408{
dbda9e86
JS
409 if (!wxFileExists(filename))
410 return;
411
dd107c50 412 wxSTD ifstream istr(filename, ios::in);
dbda9e86 413
9a29912f
JS
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;
3924dd22
GT
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);
9a29912f 445 TexReferences.Put(label, new TexRef(label, file, section, sectionName));
3924dd22 446 TexReferences.DeleteContents(FALSE);
9a29912f
JS
447 }
448 }
449}
450
451
452/*
453 * Bibliography-handling code
454 *
455 */
456
dd107c50 457void BibEatWhiteSpace(wxSTD istream& str)
9a29912f
JS
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
dd107c50 485void BibReadWord(wxSTD istream& istr, char *buffer)
9a29912f
JS
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
dd107c50 502void BibReadToEOL(wxSTD istream& istr, char *buffer)
9a29912f
JS
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.
dd107c50 531void BibReadValue(wxSTD istream& istr, char *buffer, bool ignoreBraces = TRUE,
9a29912f
JS
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 ++;
08c6402a 542 if (i >= 4000)
9a29912f
JS
543 {
544 char buf[100];
11611a62
JS
545 sprintf(buf, "Sorry, value > 4000 chars in bib file at line %ld.", BibLine);
546 wxLogError(buf, "Tex2RTF Fatal Error");
547 return;
9a29912f
JS
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
582bool ReadBib(char *filename)
583{
dbda9e86
JS
584 if (!wxFileExists(filename))
585 return FALSE;
586
9a29912f 587 char buf[300];
dd107c50 588 wxSTD ifstream istr(filename, ios::in);
9a29912f
JS
589 if (istr.bad()) return FALSE;
590
591 BibLine = 1;
592
593 OnInform("Reading .bib file...");
594
595 char ch;
08c6402a 596 char fieldValue[4000];
9a29912f
JS
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
765void 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
964void 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
996static int citeCount = 1;
997
998void 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
1032void 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
1043TexRef *FindReference(char *key)
1044{
1045 return (TexRef *)TexReferences.Get(key);
1046}
1047
1048/*
1049 * Custom macro stuff
1050 *
1051 */
1052
1053bool 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
1066char *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);
14204c7a
VS
1181 else if (StringMatch(settingName, "htmlWorkshopFiles", FALSE, TRUE))
1182 htmlWorkshopFiles = StringTobool(settingValue);
9a29912f
JS
1183 else if (StringMatch(settingName, "htmlFrameContents", FALSE, TRUE))
1184 htmlFrameContents = StringTobool(settingValue);
1185 else if (StringMatch(settingName, "upperCaseNames", FALSE, TRUE))
1186 upperCaseNames = StringTobool(settingValue);
bf16085d
JS
1187 else if (StringMatch(settingName, "ignoreBadRefs", FALSE, TRUE))
1188 ignoreBadRefs = StringTobool(settingValue);
d7d17624
JS
1189 else if (StringMatch(settingName, "htmlFaceName", FALSE, TRUE))
1190 {
1191 delete[] htmlFaceName;
1192 htmlFaceName = copystring(settingValue);
1193 }
9a29912f
JS
1194 else if (StringMatch(settingName, "winHelpTitle", FALSE, TRUE))
1195 {
1196 if (winHelpTitle)
1197 delete[] winHelpTitle;
1198 winHelpTitle = copystring(settingValue);
1199 }
1200 else if (StringMatch(settingName, "indexSubsections", FALSE, TRUE))
1201 indexSubsections = StringTobool(settingValue);
1202 else if (StringMatch(settingName, "compatibility", FALSE, TRUE))
1203 compatibilityMode = StringTobool(settingValue);
1204 else if (StringMatch(settingName, "defaultColumnWidth", FALSE, TRUE))
1205 {
1206 StringToInt(settingValue, &defaultTableColumnWidth);
1207 defaultTableColumnWidth = 20*defaultTableColumnWidth;
1208 }
1209 else if (StringMatch(settingName, "bitmapMethod", FALSE, TRUE))
1210 {
1211 if ((strcmp(settingValue, "includepicture") != 0) && (strcmp(settingValue, "hex") != 0) &&
1212 (strcmp(settingValue, "import") != 0))
1213 {
1214 if (interactive)
1215 OnError("Unknown bitmapMethod");
1216 strcpy(errorCode, "Unknown bitmapMethod");
1217 }
1218 else
1219 {
1220 delete[] bitmapMethod;
1221 bitmapMethod = copystring(settingValue);
1222 }
1223 }
1224 else if (StringMatch(settingName, "htmlBrowseButtons", FALSE, TRUE))
1225 {
1226 if (strcmp(settingValue, "none") == 0)
1227 htmlBrowseButtons = HTML_BUTTONS_NONE;
1228 else if (strcmp(settingValue, "bitmap") == 0)
1229 htmlBrowseButtons = HTML_BUTTONS_BITMAP;
1230 else if (strcmp(settingValue, "text") == 0)
1231 htmlBrowseButtons = HTML_BUTTONS_TEXT;
1232 else
1233 {
1234 if (interactive)
1235 OnInform("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text.");
1236 strcpy(errorCode, "Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text.");
1237 }
1238 }
1239 else if (StringMatch(settingName, "backgroundImage", FALSE, TRUE))
1240 {
1241 backgroundImageString = copystring(settingValue);
1242 }
1243 else if (StringMatch(settingName, "backgroundColour", FALSE, TRUE))
1244 {
1245 delete[] backgroundColourString;
1246 backgroundColourString = copystring(settingValue);
1247 }
1248 else if (StringMatch(settingName, "textColour", FALSE, TRUE))
1249 {
1250 textColourString = copystring(settingValue);
1251 }
1252 else if (StringMatch(settingName, "linkColour", FALSE, TRUE))
1253 {
1254 linkColourString = copystring(settingValue);
1255 }
1256 else if (StringMatch(settingName, "followedLinkColour", FALSE, TRUE))
1257 {
1258 followedLinkColourString = copystring(settingValue);
1259 }
1260 else if (StringMatch(settingName, "conversionMode", FALSE, TRUE))
1261 {
1262 if (StringMatch(settingValue, "RTF", FALSE, TRUE))
1263 {
1264 winHelp = FALSE; convertMode = TEX_RTF;
1265 }
1266 else if (StringMatch(settingValue, "WinHelp", FALSE, TRUE))
1267 {
1268 winHelp = TRUE; convertMode = TEX_RTF;
1269 }
1270 else if (StringMatch(settingValue, "XLP", FALSE, TRUE) ||
1271 StringMatch(settingValue, "wxHelp", FALSE, TRUE))
1272 {
1273 convertMode = TEX_XLP;
1274 }
1275 else if (StringMatch(settingValue, "HTML", FALSE, TRUE))
1276 {
1277 convertMode = TEX_HTML;
1278 }
1279 else
1280 {
1281 if (interactive)
1282 OnInform("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML.");
1283 strcpy(errorCode, "Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML.");
1284 }
1285 }
1286 else if (StringMatch(settingName, "documentFontSize", FALSE, TRUE))
1287 {
1288 int n;
1289 StringToInt(settingValue, &n);
1290 if (n == 10 || n == 11 || n == 12)
1291 SetFontSizes(n);
1292 else
1293 {
1294 char buf[200];
1295 sprintf(buf, "Initialisation file error: nonstandard document font size %d.", n);
1296 if (interactive)
1297 OnInform(buf);
1298 strcpy(errorCode, buf);
1299 }
1300 }
1301 else
1302 {
1303 char buf[200];
1304 sprintf(buf, "Initialisation file error: unrecognised setting %s.", settingName);
1305 if (interactive)
1306 OnInform(buf);
1307 strcpy(errorCode, buf);
1308 }
1309 return errorCode;
1310}
1311
1312bool ReadCustomMacros(char *filename)
1313{
dbda9e86
JS
1314 if (!wxFileExists(filename))
1315 return FALSE;
1316
dd107c50 1317 wxSTD ifstream istr(filename, ios::in);
dbda9e86 1318
9a29912f
JS
1319 if (istr.bad()) return FALSE;
1320
1321 CustomMacroList.Clear();
1322 char ch;
1323 char macroName[100];
1324 char macroBody[1000];
1325 int noArgs;
1326
1327 while (!istr.eof())
1328 {
1329 BibEatWhiteSpace(istr);
1330 istr.get(ch);
1331 if (istr.eof())
1332 break;
1333
1334 if (ch != '\\') // Not a macro definition, so must be NAME=VALUE
1335 {
1336 char settingName[100];
1337 settingName[0] = ch;
1338 BibReadWord(istr, (settingName+1));
1339 BibEatWhiteSpace(istr);
1340 istr.get(ch);
1341 if (ch != '=')
1342 {
1343 OnError("Expected = following name: malformed tex2rtf.ini file.");
1344 return FALSE;
1345 }
1346 else
1347 {
1348 char settingValue[200];
1349 BibEatWhiteSpace(istr);
1350 BibReadToEOL(istr, settingValue);
1351 RegisterSetting(settingName, settingValue);
1352 }
1353 }
1354 else
1355 {
1356 BibReadWord(istr, macroName);
1357 BibEatWhiteSpace(istr);
1358 istr.get(ch);
1359 if (ch != '[')
1360 {
1361 OnError("Expected [ followed by number of arguments: malformed tex2rtf.ini file.");
1362 return FALSE;
1363 }
1364 istr >> noArgs;
1365 istr.get(ch);
1366 if (ch != ']')
1367 {
1368 OnError("Expected ] following number of arguments: malformed tex2rtf.ini file.");
1369 return FALSE;
1370 }
1371 BibEatWhiteSpace(istr);
1372 istr.get(ch);
1373 if (ch != '{')
1374 {
1375 OnError("Expected { followed by macro body: malformed tex2rtf.ini file.");
1376 return FALSE;
1377 }
1378 CustomMacro *macro = new CustomMacro(macroName, noArgs, NULL);
1379 BibReadValue(istr, macroBody, FALSE, FALSE); // Don't ignore extra braces
1380 if (strlen(macroBody) > 0)
1381 macro->macroBody = copystring(macroBody);
1382
1383 BibEatWhiteSpace(istr);
1384 CustomMacroList.Append(macroName, macro);
1385 AddMacroDef(ltCUSTOM_MACRO, macroName, noArgs);
1386 }
1387 }
1388 char mbuf[200];
1389 sprintf(mbuf, "Read initialization file %s.", filename);
1390 OnInform(mbuf);
1391 return TRUE;
1392}
1393
1394CustomMacro *FindCustomMacro(char *name)
1395{
1396 wxNode *node = CustomMacroList.Find(name);
1397 if (node)
1398 {
1399 CustomMacro *macro = (CustomMacro *)node->Data();
1400 return macro;
1401 }
1402 return NULL;
1403}
1404
1405// Display custom macros
1406void ShowCustomMacros(void)
1407{
1408 wxNode *node = CustomMacroList.First();
1409 if (!node)
1410 {
1411 OnInform("No custom macros loaded.\n");
1412 return;
1413 }
1414
1415 char buf[400];
1416 while (node)
1417 {
1418 CustomMacro *macro = (CustomMacro *)node->Data();
1419 sprintf(buf, "\\%s[%d]\n {%s}", macro->macroName, macro->noArgs,
1420 macro->macroBody ? macro->macroBody : "");
1421 OnInform(buf);
1422 node = node->Next();
1423 }
1424}
1425
1426// Parse a string into several comma-separated fields
1427char *ParseMultifieldString(char *allFields, int *pos)
1428{
1429 static char buffer[300];
1430 int i = 0;
1431 int fieldIndex = *pos;
1432 int len = strlen(allFields);
1433 int oldPos = *pos;
1434 bool keepGoing = TRUE;
1435 while ((fieldIndex <= len) && keepGoing)
1436 {
1437 if (allFields[fieldIndex] == ' ')
1438 {
1439 // Skip
1440 fieldIndex ++;
1441 }
1442 else if (allFields[fieldIndex] == ',')
1443 {
1444 *pos = fieldIndex + 1;
1445 keepGoing = FALSE;
1446 }
1447 else if (allFields[fieldIndex] == 0)
1448 {
1449 *pos = fieldIndex + 1;
1450 keepGoing = FALSE;
1451 }
1452 else
1453 {
1454 buffer[i] = allFields[fieldIndex];
1455 fieldIndex ++;
1456 i++;
1457 }
1458 }
1459 buffer[i] = 0;
1460 if (oldPos == (*pos))
1461 *pos = len + 1;
1462
1463 if (i == 0)
1464 return NULL;
1465 else
1466 return buffer;
1467}
1468
1469/*
1470 * Colour tables
1471 *
1472 */
1473
bbd08c6a 1474ColourTableEntry::ColourTableEntry(const char *theName, unsigned int r, unsigned int g, unsigned int b)
9a29912f
JS
1475{
1476 name = copystring(theName);
1477 red = r;
1478 green = g;
1479 blue = b;
1480}
1481
1482ColourTableEntry::~ColourTableEntry(void)
1483{
1484 delete[] name;
1485}
1486
bbd08c6a 1487void AddColour(const char *theName, unsigned int r, unsigned int g, unsigned int b)
9a29912f
JS
1488{
1489 wxNode *node = ColourTable.Find(theName);
1490 if (node)
1491 {
1492 ColourTableEntry *entry = (ColourTableEntry *)node->Data();
1493 if (entry->red == r || entry->green == g || entry->blue == b)
1494 return;
1495 else
1496 {
1497 delete entry;
1498 delete node;
1499 }
1500 }
1501 ColourTableEntry *entry = new ColourTableEntry(theName, r, g, b);
1502 ColourTable.Append(theName, entry);
1503}
1504
1505int FindColourPosition(char *theName)
1506{
1507 int i = 0;
1508 wxNode *node = ColourTable.First();
1509 while (node)
1510 {
1511 ColourTableEntry *entry = (ColourTableEntry *)node->Data();
1512 if (strcmp(theName, entry->name) == 0)
1513 return i;
1514 i ++;
1515 node = node->Next();
1516 }
1517 return -1;
1518}
1519
1520// Converts e.g. "red" -> "#FF0000"
1521extern void DecToHex(int, char *);
1522bool FindColourHTMLString(char *theName, char *buf)
1523{
1524 int i = 0;
1525 wxNode *node = ColourTable.First();
1526 while (node)
1527 {
1528 ColourTableEntry *entry = (ColourTableEntry *)node->Data();
1529 if (strcmp(theName, entry->name) == 0)
1530 {
1531 strcpy(buf, "#");
1532
1533 char buf2[3];
1534 DecToHex(entry->red, buf2);
1535 strcat(buf, buf2);
1536 DecToHex(entry->green, buf2);
1537 strcat(buf, buf2);
1538 DecToHex(entry->blue, buf2);
1539 strcat(buf, buf2);
1540
1541 return TRUE;
1542 }
1543 i ++;
1544 node = node->Next();
1545 }
1546 return FALSE;
1547}
1548
1549
1550void InitialiseColourTable(void)
1551{
1552 // \\red0\\green0\\blue0;
1553 AddColour("black", 0,0,0);
1554
1555 // \\red0\\green0\\blue255;\\red0\\green255\\blue255;\n");
1556 AddColour("cyan", 0,255,255);
1557
1558 // \\red0\\green255\\blue0;
1559 AddColour("green", 0,255,0);
1560
1561 // \\red255\\green0\\blue255;
1562 AddColour("magenta", 255,0,255);
1563
1564 // \\red255\\green0\\blue0;
1565 AddColour("red", 255,0,0);
1566
1567 // \\red255\\green255\\blue0;
1568 AddColour("yellow", 255,255,0);
1569
1570 // \\red255\\green255\\blue255;}");
1571 AddColour("white", 255,255,255);
1572}
1573
1574/*
1575 * The purpose of this is to reduce the number of times wxYield is
1576 * called, since under Windows this can slow things down.
1577 */
1578
1579static int yieldCount = 0;
1580
1581void Tex2RTFYield(bool force)
1582{
1583#ifdef __WXMSW__
1584 if (isSync)
1585 return;
1586
1587 if (force)
1588 yieldCount = 0;
1589 if (yieldCount == 0)
1590 {
3f8e5072
JS
1591 if (wxTheApp)
1592 wxYield();
9a29912f
JS
1593 yieldCount = 10;
1594 }
1595 yieldCount --;
1596#endif
1597}
1598
1599// In both RTF generation and HTML generation for wxHelp version 2,
1600// we need to associate \indexed keywords with the current filename/topics.
1601
1602// Hash table for lists of keywords for topics (WinHelp).
1603wxHashTable TopicTable(wxKEY_STRING);
1604void AddKeyWordForTopic(char *topic, char *entry, char *filename)
1605{
1606 TexTopic *texTopic = (TexTopic *)TopicTable.Get(topic);
1607 if (!texTopic)
1608 {
1609 texTopic = new TexTopic(filename);
1610 texTopic->keywords = new wxStringList;
1611 TopicTable.Put(topic, texTopic);
1612 }
1613
1614 if (!texTopic->keywords->Member(entry))
1615 texTopic->keywords->Add(entry);
1616}
1617
1618void ClearKeyWordTable(void)
1619{
1620 TopicTable.BeginFind();
1621 wxNode *node = TopicTable.Next();
1622 while (node)
1623 {
1624 TexTopic *texTopic = (TexTopic *)node->Data();
1625 delete texTopic;
1626 node = TopicTable.Next();
1627 }
1628 TopicTable.Clear();
1629}
1630
1631
1632/*
1633 * TexTopic structure
1634 */
1635
1636TexTopic::TexTopic(char *f)
1637{
1638 if (f)
1639 filename = copystring(f);
1640 else
1641 filename = NULL;
1642 hasChildren = FALSE;
1643 keywords = NULL;
1644}
1645
1646TexTopic::~TexTopic(void)
1647{
1648 if (keywords)
1649 delete keywords;
1650 if (filename)
1651 delete[] filename;
1652}
1653
1654// Convert case, according to upperCaseNames setting.
1655char *ConvertCase(char *s)
1656{
1657 static char buf[256];
1658 int len = strlen(s);
1659 int i;
1660 if (upperCaseNames)
1661 for (i = 0; i < len; i ++)
a4146f16 1662 buf[i] = toupper(s[i]);
9a29912f
JS
1663 else
1664 for (i = 0; i < len; i ++)
a4146f16 1665 buf[i] = tolower(s[i]);
9a29912f
JS
1666 buf[i] = 0;
1667 return buf;
1668}