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