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