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