]> git.saurik.com Git - wxWidgets.git/blob - utils/tex2rtf/src/texutils.cpp
resolving conflicts in files I had forgot to commit (sorry)
[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 wxChar *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(wxChar *buf)
78 {
79 if (fakeCurrentSection)
80 wxStrcpy(buf, fakeCurrentSection);
81 else
82 OutputChunkToString(currentSection, buf);
83 }
84
85 void OutputChunkToString(TexChunk *chunk, wxChar *buf)
86 {
87 FILE *tempfd = wxFopen(_T("tmp.tmp"), _T("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 = wxFopen(_T("tmp.tmp"), _T("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(_T("tmp.tmp"));
125 }
126
127 // Called by Tex2Any to simulate a section
128 void FakeCurrentSection(wxChar *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 wxChar *forceTopicName = NULL;
164
165 void ForceTopicName(const wxChar *name)
166 {
167 if (forceTopicName)
168 delete[] forceTopicName;
169 if (name)
170 forceTopicName = copystring(name);
171 else
172 forceTopicName = NULL;
173 }
174
175 wxChar *FindTopicName(TexChunk *chunk)
176 {
177 if (forceTopicName)
178 return forceTopicName;
179
180 wxChar *topicName = NULL;
181 static wxChar 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 wxSprintf(topicBuf, _T("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(wxChar *data)
220 {
221 wxStrcpy(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(wxChar *unitArg)
236 {
237 float conversionFactor = 1.0;
238 float unitValue = 0.0;
239 int len = wxStrlen(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 = wxStrlen(unitArg);
245
246 if (unitArg && (len > 0) && (isdigit(unitArg[0]) || unitArg[0] == '-'))
247 {
248 wxSscanf(unitArg, _T("%f"), &unitValue);
249 if (len > 1)
250 {
251 wxChar units[3];
252 units[0] = unitArg[len-2];
253 units[1] = unitArg[len-1];
254 units[2] = 0;
255 if (wxStrcmp(units, _T("in")) == 0)
256 conversionFactor = 72.0;
257 else if (wxStrcmp(units, _T("cm")) == 0)
258 conversionFactor = (float)72.0/(float)2.51;
259 else if (wxStrcmp(units, _T("mm")) == 0)
260 conversionFactor = (float)72.0/(float)25.1;
261 else if (wxStrcmp(units, _T("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(wxChar *buffer)
276 {
277 int len = wxStrlen(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(wxChar *name, wxChar *file, wxChar *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 wxChar buf[100];
354 buf[0] = 0;
355 /*
356 if (sectionName)
357 {
358 wxStrcat(buf, sectionName);
359 wxStrcat(buf, " ");
360 }
361 */
362 if (chapter)
363 {
364 wxChar buf2[10];
365 wxSprintf(buf2, _T("%d"), chapter);
366 wxStrcat(buf, buf2);
367 }
368 if (section)
369 {
370 wxChar buf2[10];
371 if (chapter)
372 wxStrcat(buf, _T("."));
373
374 wxSprintf(buf2, _T("%d"), section);
375 wxStrcat(buf, buf2);
376 }
377 if (subsection)
378 {
379 wxChar buf2[10];
380 wxStrcat(buf, _T("."));
381 wxSprintf(buf2, _T("%d"), subsection);
382 wxStrcat(buf, buf2);
383 }
384 if (subsubsection)
385 {
386 wxChar buf2[10];
387 wxStrcat(buf, _T("."));
388 wxSprintf(buf2, _T("%d"), subsubsection);
389 wxStrcat(buf, buf2);
390 }
391 wxChar *tmp = ((wxStrlen(buf) > 0) ? buf : (wxChar *)NULL);
392 TexReferences.Put(name, new TexRef(name, file, tmp, sectionName));
393 }
394
395 void WriteTexReferences(wxChar *filename)
396 {
397 wxSTD ofstream ostr(filename);
398 if (ostr.bad()) return;
399 wxChar 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 << _T(" ") << (ref->refFile ? ref->refFile : _T("??")) << _T(" ");
408 ostr << (ref->sectionName ? ref->sectionName : _T("??")) << _T(" ");
409 ostr << (ref->sectionNumber ? ref->sectionNumber : _T("??")) << _T("\n");
410 if (!ref->sectionNumber || (wxStrcmp(ref->sectionNumber, _T("??")) == 0 && wxStrcmp(ref->sectionName, _T("??")) == 0))
411 {
412 wxSprintf(buf, _T("Warning: reference %s not resolved."), ref->refLabel);
413 OnInform(buf);
414 }
415 node = TexReferences.Next();
416 }
417 }
418
419 void ReadTexReferences(wxChar *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 wxChar label[100];
429 wxChar file[400];
430 wxChar section[100];
431 wxChar 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, wxChar *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, wxChar *buffer)
515 {
516 int i = 0;
517 buffer[i] = 0;
518 wxChar ch = istr.peek();
519 bool inQuotes = FALSE;
520 if (ch == _T('"'))
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 != _T('"') &&
529 (inQuotes || ((ch != _T(' ')) && (ch != 9) &&
530 (ch != _T(';')) && (ch != _T('%')) && (ch != _T('#')))))
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, wxChar *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 wxChar buf[100];
557 wxSprintf(buf, _T("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 wxUnusedVar(stopping);
593 }
594
595 bool ReadBib(wxChar *filename)
596 {
597 if (!wxFileExists(filename))
598 return FALSE;
599
600 wxChar buf[300];
601 wxSTD ifstream istr(filename, wxSTD ios::in);
602 if (istr.bad()) return FALSE;
603
604 BibLine = 1;
605
606 OnInform(_T("Reading .bib file..."));
607
608 char ch;
609 wxChar fieldValue[4000];
610 wxChar recordType[100];
611 wxChar recordKey[100];
612 wxChar recordField[100];
613 while (!istr.eof())
614 {
615 Tex2RTFYield();
616
617 BibEatWhiteSpace(istr);
618 istr.get(ch);
619 if (ch != '@')
620 {
621 wxSprintf(buf, _T("Expected @: malformed bib file at line %ld (%s)"), BibLine, filename);
622 OnError(buf);
623 return FALSE;
624 }
625 BibReadWord(istr, recordType);
626 BibEatWhiteSpace(istr);
627 istr.get(ch);
628 if (ch != '{' && ch != '(')
629 {
630 wxSprintf(buf, _T("Expected { or ( after record type: malformed .bib file at line %ld (%s)"), BibLine, filename);
631 OnError(buf);
632 return FALSE;
633 }
634 BibEatWhiteSpace(istr);
635 if (StringMatch(recordType, _T("string"), FALSE, TRUE))
636 {
637 BibReadWord(istr, recordType);
638 BibEatWhiteSpace(istr);
639 istr.get(ch);
640 if (ch != '=')
641 {
642 wxSprintf(buf, _T("Expected = after string key: malformed .bib file at line %ld (%s)"), BibLine, filename);
643 OnError(buf);
644 return FALSE;
645 }
646 BibEatWhiteSpace(istr);
647 istr.get(ch);
648 if (ch != '"' && ch != '{')
649 {
650 wxSprintf(buf, _T("Expected = after string key: malformed .bib file at line %ld (%s)"), BibLine, filename);
651 OnError(buf);
652 return FALSE;
653 }
654 BibReadValue(istr, fieldValue);
655
656 // Now put in hash table if necesary
657 if (!BibStringTable.Get(recordType))
658 BibStringTable.Put(recordType, (wxObject *)copystring(fieldValue));
659
660 // Read closing ) or }
661 BibEatWhiteSpace(istr);
662 istr.get(ch);
663 BibEatWhiteSpace(istr);
664 }
665 else
666 {
667 BibReadWord(istr, recordKey);
668
669 BibEntry *bibEntry = new BibEntry;
670 bibEntry->key = copystring(recordKey);
671 bibEntry->type = copystring(recordType);
672
673 bool moreRecords = TRUE;
674 while (moreRecords && !istr.eof())
675 {
676 BibEatWhiteSpace(istr);
677 istr.get(ch);
678 if (ch == '}' || ch == ')')
679 {
680 moreRecords = FALSE;
681 }
682 else if (ch == ',')
683 {
684 BibEatWhiteSpace(istr);
685 BibReadWord(istr, recordField);
686 BibEatWhiteSpace(istr);
687 istr.get(ch);
688 if (ch != '=')
689 {
690 wxSprintf(buf, _T("Expected = after field type: malformed .bib file at line %ld (%s)"), BibLine, filename);
691 OnError(buf);
692 return FALSE;
693 }
694 BibEatWhiteSpace(istr);
695 istr.get(ch);
696 if (ch != '{' && ch != '"')
697 {
698 fieldValue[0] = ch;
699 BibReadWord(istr, fieldValue+1);
700
701 // If in the table of strings, replace with string from table.
702 wxChar *s = (wxChar *)BibStringTable.Get(fieldValue);
703 if (s)
704 {
705 wxStrcpy(fieldValue, s);
706 }
707 }
708 else
709 BibReadValue(istr, fieldValue, TRUE, (ch == _T('"') ? TRUE : FALSE));
710
711 // Now we can add a field
712 if (StringMatch(recordField, _T("author"), FALSE, TRUE))
713 bibEntry->author = copystring(fieldValue);
714 else if (StringMatch(recordField, _T("key"), FALSE, TRUE))
715 {}
716 else if (StringMatch(recordField, _T("annotate"), FALSE, TRUE))
717 {}
718 else if (StringMatch(recordField, _T("abstract"), FALSE, TRUE))
719 {}
720 else if (StringMatch(recordField, _T("edition"), FALSE, TRUE))
721 {}
722 else if (StringMatch(recordField, _T("howpublished"), FALSE, TRUE))
723 {}
724 else if (StringMatch(recordField, _T("note"), FALSE, TRUE) || StringMatch(recordField, _T("notes"), FALSE, TRUE))
725 {}
726 else if (StringMatch(recordField, _T("series"), FALSE, TRUE))
727 {}
728 else if (StringMatch(recordField, _T("type"), FALSE, TRUE))
729 {}
730 else if (StringMatch(recordField, _T("keywords"), FALSE, TRUE))
731 {}
732 else if (StringMatch(recordField, _T("editor"), FALSE, TRUE) || StringMatch(recordField, _T("editors"), FALSE, TRUE))
733 bibEntry->editor= copystring(fieldValue);
734 else if (StringMatch(recordField, _T("title"), FALSE, TRUE))
735 bibEntry->title= copystring(fieldValue);
736 else if (StringMatch(recordField, _T("booktitle"), FALSE, TRUE))
737 bibEntry->booktitle= copystring(fieldValue);
738 else if (StringMatch(recordField, _T("journal"), FALSE, TRUE))
739 bibEntry->journal= copystring(fieldValue);
740 else if (StringMatch(recordField, _T("volume"), FALSE, TRUE))
741 bibEntry->volume= copystring(fieldValue);
742 else if (StringMatch(recordField, _T("number"), FALSE, TRUE))
743 bibEntry->number= copystring(fieldValue);
744 else if (StringMatch(recordField, _T("year"), FALSE, TRUE))
745 bibEntry->year= copystring(fieldValue);
746 else if (StringMatch(recordField, _T("month"), FALSE, TRUE))
747 bibEntry->month= copystring(fieldValue);
748 else if (StringMatch(recordField, _T("pages"), FALSE, TRUE))
749 bibEntry->pages= copystring(fieldValue);
750 else if (StringMatch(recordField, _T("publisher"), FALSE, TRUE))
751 bibEntry->publisher= copystring(fieldValue);
752 else if (StringMatch(recordField, _T("address"), FALSE, TRUE))
753 bibEntry->address= copystring(fieldValue);
754 else if (StringMatch(recordField, _T("institution"), FALSE, TRUE) || StringMatch(recordField, _T("school"), FALSE, TRUE))
755 bibEntry->institution= copystring(fieldValue);
756 else if (StringMatch(recordField, _T("organization"), FALSE, TRUE) || StringMatch(recordField, _T("organisation"), FALSE, TRUE))
757 bibEntry->organization= copystring(fieldValue);
758 else if (StringMatch(recordField, _T("comment"), FALSE, TRUE) || StringMatch(recordField, _T("comments"), FALSE, TRUE))
759 bibEntry->comment= copystring(fieldValue);
760 else if (StringMatch(recordField, _T("annote"), FALSE, TRUE))
761 bibEntry->comment= copystring(fieldValue);
762 else if (StringMatch(recordField, _T("chapter"), FALSE, TRUE))
763 bibEntry->chapter= copystring(fieldValue);
764 else
765 {
766 wxSprintf(buf, _T("Unrecognised bib field type %s at line %ld (%s)"), recordField, BibLine, filename);
767 OnError(buf);
768 }
769 }
770 }
771 BibList.Append(recordKey, bibEntry);
772 BibEatWhiteSpace(istr);
773 }
774 }
775 return TRUE;
776 }
777
778 void OutputBibItem(TexRef *ref, BibEntry *bib)
779 {
780 Tex2RTFYield();
781
782 OnMacro(ltNUMBEREDBIBITEM, 2, TRUE);
783 OnArgument(ltNUMBEREDBIBITEM, 1, TRUE);
784 TexOutput(ref->sectionNumber);
785 OnArgument(ltNUMBEREDBIBITEM, 1, FALSE);
786 OnArgument(ltNUMBEREDBIBITEM, 2, TRUE);
787
788 TexOutput(_T(" "));
789 OnMacro(ltBF, 1, TRUE);
790 OnArgument(ltBF, 1, TRUE);
791 if (bib->author)
792 TexOutput(bib->author);
793 OnArgument(ltBF, 1, FALSE);
794 OnMacro(ltBF, 1, FALSE);
795 if (bib->author && (wxStrlen(bib->author) > 0) && (bib->author[wxStrlen(bib->author) - 1] != '.'))
796 TexOutput(_T(". "));
797 else
798 TexOutput(_T(" "));
799
800 if (bib->year)
801 {
802 TexOutput(bib->year);
803 }
804 if (bib->month)
805 {
806 TexOutput(_T(" ("));
807 TexOutput(bib->month);
808 TexOutput(_T(")"));
809 }
810 if (bib->year || bib->month)
811 TexOutput(_T(". "));
812
813 if (StringMatch(bib->type, _T("article"), FALSE, TRUE))
814 {
815 if (bib->title)
816 {
817 TexOutput(bib->title);
818 TexOutput(_T(". "));
819 }
820 if (bib->journal)
821 {
822 OnMacro(ltIT, 1, TRUE);
823 OnArgument(ltIT, 1, TRUE);
824 TexOutput(bib->journal);
825 OnArgument(ltIT, 1, FALSE);
826 OnMacro(ltIT, 1, FALSE);
827 }
828 if (bib->volume)
829 {
830 TexOutput(_T(", "));
831 OnMacro(ltBF, 1, TRUE);
832 OnArgument(ltBF, 1, TRUE);
833 TexOutput(bib->volume);
834 OnArgument(ltBF, 1, FALSE);
835 OnMacro(ltBF, 1, FALSE);
836 }
837 if (bib->number)
838 {
839 TexOutput(_T("("));
840 TexOutput(bib->number);
841 TexOutput(_T(")"));
842 }
843 if (bib->pages)
844 {
845 TexOutput(_T(", pages "));
846 TexOutput(bib->pages);
847 }
848 TexOutput(_T("."));
849 }
850 else if (StringMatch(bib->type, _T("book"), FALSE, TRUE) ||
851 StringMatch(bib->type, _T("unpublished"), FALSE, TRUE) ||
852 StringMatch(bib->type, _T("manual"), FALSE, TRUE) ||
853 StringMatch(bib->type, _T("phdthesis"), FALSE, TRUE) ||
854 StringMatch(bib->type, _T("mastersthesis"), FALSE, TRUE) ||
855 StringMatch(bib->type, _T("misc"), FALSE, TRUE) ||
856 StringMatch(bib->type, _T("techreport"), FALSE, TRUE) ||
857 StringMatch(bib->type, _T("booklet"), FALSE, TRUE))
858 {
859 if (bib->title || bib->booktitle)
860 {
861 OnMacro(ltIT, 1, TRUE);
862 OnArgument(ltIT, 1, TRUE);
863 TexOutput(bib->title ? bib->title : bib->booktitle);
864 TexOutput(_T(". "));
865 OnArgument(ltIT, 1, FALSE);
866 OnMacro(ltIT, 1, FALSE);
867 }
868 if (StringMatch(bib->type, _T("phdthesis"), FALSE, TRUE))
869 TexOutput(_T("PhD thesis. "));
870 if (StringMatch(bib->type, _T("techreport"), FALSE, TRUE))
871 TexOutput(_T("Technical report. "));
872 if (bib->editor)
873 {
874 TexOutput(_T("Ed. "));
875 TexOutput(bib->editor);
876 TexOutput(_T(". "));
877 }
878 if (bib->institution)
879 {
880 TexOutput(bib->institution);
881 TexOutput(_T(". "));
882 }
883 if (bib->organization)
884 {
885 TexOutput(bib->organization);
886 TexOutput(_T(". "));
887 }
888 if (bib->publisher)
889 {
890 TexOutput(bib->publisher);
891 TexOutput(_T(". "));
892 }
893 if (bib->address)
894 {
895 TexOutput(bib->address);
896 TexOutput(_T(". "));
897 }
898 }
899 else if (StringMatch(bib->type, _T("inbook"), FALSE, TRUE) ||
900 StringMatch(bib->type, _T("inproceedings"), FALSE, TRUE) ||
901 StringMatch(bib->type, _T("incollection"), FALSE, TRUE) ||
902 StringMatch(bib->type, _T("conference"), FALSE, TRUE))
903 {
904 if (bib->title)
905 {
906 TexOutput(bib->title);
907 }
908 if (bib->booktitle)
909 {
910 TexOutput(_T(", from "));
911 OnMacro(ltIT, 1, TRUE);
912 OnArgument(ltIT, 1, TRUE);
913 TexOutput(bib->booktitle);
914 TexOutput(_T("."));
915 OnArgument(ltIT, 1, FALSE);
916 OnMacro(ltIT, 1, FALSE);
917 }
918 if (bib->editor)
919 {
920 TexOutput(_T(", ed. "));
921 TexOutput(bib->editor);
922 }
923 if (bib->publisher)
924 {
925 TexOutput(_T(" "));
926 TexOutput(bib->publisher);
927 }
928 if (bib->address)
929 {
930 if (bib->publisher) TexOutput(_T(", "));
931 else TexOutput(_T(" "));
932 TexOutput(bib->address);
933 }
934 if (bib->publisher || bib->address)
935 TexOutput(_T("."));
936
937 if (bib->volume)
938 {
939 TexOutput(_T(" "));
940 OnMacro(ltBF, 1, TRUE);
941 OnArgument(ltBF, 1, TRUE);
942 TexOutput(bib->volume);
943 OnArgument(ltBF, 1, FALSE);
944 OnMacro(ltBF, 1, FALSE);
945 }
946 if (bib->number)
947 {
948 if (bib->volume)
949 {
950 TexOutput(_T("("));
951 TexOutput(bib->number);
952 TexOutput(_T(")."));
953 }
954 else
955 {
956 TexOutput(_T(" Number "));
957 TexOutput(bib->number);
958 TexOutput(_T("."));
959 }
960 }
961 if (bib->chapter)
962 {
963 TexOutput(_T(" Chap. "));
964 TexOutput(bib->chapter);
965 }
966 if (bib->pages)
967 {
968 if (bib->chapter) TexOutput(_T(", pages "));
969 else TexOutput(_T(" Pages "));
970 TexOutput(bib->pages);
971 TexOutput(_T("."));
972 }
973 }
974 OnArgument(ltNUMBEREDBIBITEM, 2, FALSE);
975 OnMacro(ltNUMBEREDBIBITEM, 2, FALSE);
976 }
977
978 void OutputBib(void)
979 {
980 // Write the heading
981 ForceTopicName(_T("bibliography"));
982 FakeCurrentSection(ReferencesNameString);
983 ForceTopicName(NULL);
984
985 OnMacro(ltPAR, 0, TRUE);
986 OnMacro(ltPAR, 0, FALSE);
987
988 if ((convertMode == TEX_RTF) && !winHelp)
989 {
990 OnMacro(ltPAR, 0, TRUE);
991 OnMacro(ltPAR, 0, FALSE);
992 }
993
994 wxStringListNode *node = CitationList.GetFirst();
995 while (node)
996 {
997 wxChar *citeKey = (wxChar *)node->GetData();
998 // wxNode *texNode = TexReferences.Find(citeKey);
999 TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
1000 wxNode *bibNode = BibList.Find(citeKey);
1001 if (bibNode && ref)
1002 {
1003 BibEntry *entry = (BibEntry *)bibNode->GetData();
1004 OutputBibItem(ref, entry);
1005 }
1006 node = node->GetNext();
1007 }
1008 }
1009
1010 static int citeCount = 1;
1011
1012 void ResolveBibReferences(void)
1013 {
1014 if (CitationList.GetCount() > 0)
1015 OnInform(_T("Resolving bibliographic references..."));
1016
1017 citeCount = 1;
1018 wxChar buf[200];
1019 wxStringListNode *node = CitationList.GetFirst();
1020 while (node)
1021 {
1022 Tex2RTFYield();
1023 wxChar *citeKey = (wxChar *)node->GetData();
1024 // wxNode *texNode = TexReferences.Find(citeKey);
1025 TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
1026 wxNode *bibNode = BibList.Find(citeKey);
1027 if (bibNode && ref)
1028 {
1029 // Unused Variable
1030 //BibEntry *entry = (BibEntry *)bibNode->GetData();
1031 if (ref->sectionNumber) delete[] ref->sectionNumber;
1032 wxSprintf(buf, _T("[%d]"), citeCount);
1033 ref->sectionNumber = copystring(buf);
1034 citeCount ++;
1035 }
1036 else
1037 {
1038 wxSprintf(buf, _T("Warning: bib ref %s not resolved."), citeKey);
1039 OnInform(buf);
1040 }
1041 node = node->GetNext();
1042 }
1043 }
1044
1045 // Remember we need to resolve this citation
1046 void AddCitation(wxChar *citeKey)
1047 {
1048 if (!CitationList.Member(citeKey))
1049 CitationList.Add(citeKey);
1050
1051 if (!TexReferences.Get(citeKey))
1052 {
1053 TexReferences.Put(citeKey, new TexRef(citeKey, _T("??"), NULL));
1054 }
1055 }
1056
1057 TexRef *FindReference(wxChar *key)
1058 {
1059 return (TexRef *)TexReferences.Get(key);
1060 }
1061
1062 /*
1063 * Custom macro stuff
1064 *
1065 */
1066
1067 bool StringTobool(wxChar *val)
1068 {
1069 if (wxStrncmp(val, _T("yes"), 3) == 0 || wxStrncmp(val, _T("YES"), 3) == 0 ||
1070 wxStrncmp(val, _T("on"), 2) == 0 || wxStrncmp(val, _T("ON"), 2) == 0 ||
1071 wxStrncmp(val, _T("true"), 4) == 0 || wxStrncmp(val, _T("TRUE"), 4) == 0 ||
1072 wxStrncmp(val, _T("ok"), 2) == 0 || wxStrncmp(val, _T("OK"), 2) == 0 ||
1073 wxStrncmp(val, _T("1"), 1) == 0)
1074 return TRUE;
1075 else
1076 return FALSE;
1077 }
1078
1079 // Define a variable value from the .ini file
1080 wxChar *RegisterSetting(wxChar *settingName, wxChar *settingValue, bool interactive)
1081 {
1082 static wxChar errorCode[100];
1083 wxStrcpy(errorCode, _T("OK"));
1084 if (StringMatch(settingName, _T("chapterName"), FALSE, TRUE))
1085 {
1086 delete[] ChapterNameString;
1087 ChapterNameString = copystring(settingValue);
1088 }
1089 else if (StringMatch(settingName, _T("sectionName"), FALSE, TRUE))
1090 {
1091 delete[] SectionNameString;
1092 SectionNameString = copystring(settingValue);
1093 }
1094 else if (StringMatch(settingName, _T("subsectionName"), FALSE, TRUE))
1095 {
1096 delete[] SubsectionNameString;
1097 SubsectionNameString = copystring(settingValue);
1098 }
1099 else if (StringMatch(settingName, _T("subsubsectionName"), FALSE, TRUE))
1100 {
1101 delete[] SubsubsectionNameString;
1102 SubsubsectionNameString = copystring(settingValue);
1103 }
1104 else if (StringMatch(settingName, _T("indexName"), FALSE, TRUE))
1105 {
1106 delete[] IndexNameString;
1107 IndexNameString = copystring(settingValue);
1108 }
1109 else if (StringMatch(settingName, _T("contentsName"), FALSE, TRUE))
1110 {
1111 delete[] ContentsNameString;
1112 ContentsNameString = copystring(settingValue);
1113 }
1114 else if (StringMatch(settingName, _T("glossaryName"), FALSE, TRUE))
1115 {
1116 delete[] GlossaryNameString;
1117 GlossaryNameString = copystring(settingValue);
1118 }
1119 else if (StringMatch(settingName, _T("referencesName"), FALSE, TRUE))
1120 {
1121 delete[] ReferencesNameString;
1122 ReferencesNameString = copystring(settingValue);
1123 }
1124 else if (StringMatch(settingName, _T("tablesName"), FALSE, TRUE))
1125 {
1126 delete[] TablesNameString;
1127 TablesNameString = copystring(settingValue);
1128 }
1129 else if (StringMatch(settingName, _T("figuresName"), FALSE, TRUE))
1130 {
1131 delete[] FiguresNameString;
1132 FiguresNameString = copystring(settingValue);
1133 }
1134 else if (StringMatch(settingName, _T("tableName"), FALSE, TRUE))
1135 {
1136 delete[] TableNameString;
1137 TableNameString = copystring(settingValue);
1138 }
1139 else if (StringMatch(settingName, _T("figureName"), FALSE, TRUE))
1140 {
1141 delete[] FigureNameString;
1142 FigureNameString = copystring(settingValue);
1143 }
1144 else if (StringMatch(settingName, _T("abstractName"), FALSE, TRUE))
1145 {
1146 delete[] AbstractNameString;
1147 AbstractNameString = copystring(settingValue);
1148 }
1149 else if (StringMatch(settingName, _T("chapterFontSize"), FALSE, TRUE))
1150 StringToInt(settingValue, &chapterFont);
1151 else if (StringMatch(settingName, _T("sectionFontSize"), FALSE, TRUE))
1152 StringToInt(settingValue, &sectionFont);
1153 else if (StringMatch(settingName, _T("subsectionFontSize"), FALSE, TRUE))
1154 StringToInt(settingValue, &subsectionFont);
1155 else if (StringMatch(settingName, _T("titleFontSize"), FALSE, TRUE))
1156 StringToInt(settingValue, &titleFont);
1157 else if (StringMatch(settingName, _T("authorFontSize"), FALSE, TRUE))
1158 StringToInt(settingValue, &authorFont);
1159 else if (StringMatch(settingName, _T("ignoreInput"), FALSE, TRUE))
1160 IgnorableInputFiles.Add(wxFileNameFromPath(settingValue));
1161 else if (StringMatch(settingName, _T("mirrorMargins"), FALSE, TRUE))
1162 mirrorMargins = StringTobool(settingValue);
1163 else if (StringMatch(settingName, _T("runTwice"), FALSE, TRUE))
1164 runTwice = StringTobool(settingValue);
1165 else if (StringMatch(settingName, _T("isInteractive"), FALSE, TRUE))
1166 isInteractive = StringTobool(settingValue);
1167 else if (StringMatch(settingName, _T("headerRule"), FALSE, TRUE))
1168 headerRule = StringTobool(settingValue);
1169 else if (StringMatch(settingName, _T("footerRule"), FALSE, TRUE))
1170 footerRule = StringTobool(settingValue);
1171 else if (StringMatch(settingName, _T("combineSubSections"), FALSE, TRUE))
1172 combineSubSections = StringTobool(settingValue);
1173 else if (StringMatch(settingName, _T("listLabelIndent"), FALSE, TRUE))
1174 StringToInt(settingValue, &labelIndentTab);
1175 else if (StringMatch(settingName, _T("listItemIndent"), FALSE, TRUE))
1176 StringToInt(settingValue, &itemIndentTab);
1177 else if (StringMatch(settingName, _T("useUpButton"), FALSE, TRUE))
1178 useUpButton = StringTobool(settingValue);
1179 else if (StringMatch(settingName, _T("useHeadingStyles"), FALSE, TRUE))
1180 useHeadingStyles = StringTobool(settingValue);
1181 else if (StringMatch(settingName, _T("useWord"), FALSE, TRUE))
1182 useWord = StringTobool(settingValue);
1183 else if (StringMatch(settingName, _T("contentsDepth"), FALSE, TRUE))
1184 StringToInt(settingValue, &contentsDepth);
1185 else if (StringMatch(settingName, _T("generateHPJ"), FALSE, TRUE))
1186 generateHPJ = StringTobool(settingValue);
1187 else if (StringMatch(settingName, _T("truncateFilenames"), FALSE, TRUE))
1188 truncateFilenames = StringTobool(settingValue);
1189 else if (StringMatch(settingName, _T("winHelpVersion"), FALSE, TRUE))
1190 StringToInt(settingValue, &winHelpVersion);
1191 else if (StringMatch(settingName, _T("winHelpContents"), FALSE, TRUE))
1192 winHelpContents = StringTobool(settingValue);
1193 else if (StringMatch(settingName, _T("htmlIndex"), FALSE, TRUE))
1194 htmlIndex = StringTobool(settingValue);
1195 else if (StringMatch(settingName, _T("htmlWorkshopFiles"), FALSE, TRUE))
1196 htmlWorkshopFiles = StringTobool(settingValue);
1197 else if (StringMatch(settingName, _T("htmlFrameContents"), FALSE, TRUE))
1198 htmlFrameContents = StringTobool(settingValue);
1199 else if (StringMatch(settingName, _T("htmlStylesheet"), FALSE, TRUE))
1200 {
1201 if (htmlStylesheet) delete[] htmlStylesheet;
1202 htmlStylesheet = copystring(settingValue);
1203 }
1204 else if (StringMatch(settingName, _T("upperCaseNames"), FALSE, TRUE))
1205 upperCaseNames = StringTobool(settingValue);
1206 else if (StringMatch(settingName, _T("ignoreBadRefs"), FALSE, TRUE))
1207 ignoreBadRefs = StringTobool(settingValue);
1208 else if (StringMatch(settingName, _T("htmlFaceName"), FALSE, TRUE))
1209 {
1210 delete[] htmlFaceName;
1211 htmlFaceName = copystring(settingValue);
1212 }
1213 else if (StringMatch(settingName, _T("winHelpTitle"), FALSE, TRUE))
1214 {
1215 if (winHelpTitle)
1216 delete[] winHelpTitle;
1217 winHelpTitle = copystring(settingValue);
1218 }
1219 else if (StringMatch(settingName, _T("indexSubsections"), FALSE, TRUE))
1220 indexSubsections = StringTobool(settingValue);
1221 else if (StringMatch(settingName, _T("compatibility"), FALSE, TRUE))
1222 compatibilityMode = StringTobool(settingValue);
1223 else if (StringMatch(settingName, _T("defaultColumnWidth"), FALSE, TRUE))
1224 {
1225 StringToInt(settingValue, &defaultTableColumnWidth);
1226 defaultTableColumnWidth = 20*defaultTableColumnWidth;
1227 }
1228 else if (StringMatch(settingName, _T("bitmapMethod"), FALSE, TRUE))
1229 {
1230 if ((wxStrcmp(settingValue, _T("includepicture")) != 0) && (wxStrcmp(settingValue, _T("hex")) != 0) &&
1231 (wxStrcmp(settingValue, _T("import")) != 0))
1232 {
1233 if (interactive)
1234 OnError(_T("Unknown bitmapMethod"));
1235 wxStrcpy(errorCode, _T("Unknown bitmapMethod"));
1236 }
1237 else
1238 {
1239 delete[] bitmapMethod;
1240 bitmapMethod = copystring(settingValue);
1241 }
1242 }
1243 else if (StringMatch(settingName, _T("htmlBrowseButtons"), FALSE, TRUE))
1244 {
1245 if (wxStrcmp(settingValue, _T("none")) == 0)
1246 htmlBrowseButtons = HTML_BUTTONS_NONE;
1247 else if (wxStrcmp(settingValue, _T("bitmap")) == 0)
1248 htmlBrowseButtons = HTML_BUTTONS_BITMAP;
1249 else if (wxStrcmp(settingValue, _T("text")) == 0)
1250 htmlBrowseButtons = HTML_BUTTONS_TEXT;
1251 else
1252 {
1253 if (interactive)
1254 OnInform(_T("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text."));
1255 wxStrcpy(errorCode, _T("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text."));
1256 }
1257 }
1258 else if (StringMatch(settingName, _T("backgroundImage"), FALSE, TRUE))
1259 {
1260 backgroundImageString = copystring(settingValue);
1261 }
1262 else if (StringMatch(settingName, _T("backgroundColour"), FALSE, TRUE))
1263 {
1264 delete[] backgroundColourString;
1265 backgroundColourString = copystring(settingValue);
1266 }
1267 else if (StringMatch(settingName, _T("textColour"), FALSE, TRUE))
1268 {
1269 textColourString = copystring(settingValue);
1270 }
1271 else if (StringMatch(settingName, _T("linkColour"), FALSE, TRUE))
1272 {
1273 linkColourString = copystring(settingValue);
1274 }
1275 else if (StringMatch(settingName, _T("followedLinkColour"), FALSE, TRUE))
1276 {
1277 followedLinkColourString = copystring(settingValue);
1278 }
1279 else if (StringMatch(settingName, _T("conversionMode"), FALSE, TRUE))
1280 {
1281 if (StringMatch(settingValue, _T("RTF"), FALSE, TRUE))
1282 {
1283 winHelp = FALSE; convertMode = TEX_RTF;
1284 }
1285 else if (StringMatch(settingValue, _T("WinHelp"), FALSE, TRUE))
1286 {
1287 winHelp = TRUE; convertMode = TEX_RTF;
1288 }
1289 else if (StringMatch(settingValue, _T("XLP"), FALSE, TRUE) ||
1290 StringMatch(settingValue, _T("wxHelp"), FALSE, TRUE))
1291 {
1292 convertMode = TEX_XLP;
1293 }
1294 else if (StringMatch(settingValue, _T("HTML"), FALSE, TRUE))
1295 {
1296 convertMode = TEX_HTML;
1297 }
1298 else
1299 {
1300 if (interactive)
1301 OnInform(_T("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML."));
1302 wxStrcpy(errorCode, _T("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML."));
1303 }
1304 }
1305 else if (StringMatch(settingName, _T("documentFontSize"), FALSE, TRUE))
1306 {
1307 int n;
1308 StringToInt(settingValue, &n);
1309 if (n == 10 || n == 11 || n == 12)
1310 SetFontSizes(n);
1311 else
1312 {
1313 wxChar buf[200];
1314 wxSprintf(buf, _T("Initialisation file error: nonstandard document font size %d."), n);
1315 if (interactive)
1316 OnInform(buf);
1317 wxStrcpy(errorCode, buf);
1318 }
1319 }
1320 else
1321 {
1322 wxChar buf[200];
1323 wxSprintf(buf, _T("Initialisation file error: unrecognised setting %s."), settingName);
1324 if (interactive)
1325 OnInform(buf);
1326 wxStrcpy(errorCode, buf);
1327 }
1328 return errorCode;
1329 }
1330
1331 bool ReadCustomMacros(wxChar *filename)
1332 {
1333 if (!wxFileExists(filename))
1334 return FALSE;
1335
1336 wxSTD ifstream istr(filename, wxSTD ios::in);
1337
1338 if (istr.bad()) return FALSE;
1339
1340 CustomMacroList.Clear();
1341 char ch;
1342 wxChar macroName[100];
1343 wxChar macroBody[1000];
1344 int noArgs;
1345
1346 while (!istr.eof())
1347 {
1348 BibEatWhiteSpace(istr);
1349 istr.get(ch);
1350 if (istr.eof())
1351 break;
1352
1353 if (ch != '\\') // Not a macro definition, so must be NAME=VALUE
1354 {
1355 wxChar settingName[100];
1356 settingName[0] = ch;
1357 BibReadWord(istr, (settingName+1));
1358 BibEatWhiteSpace(istr);
1359 istr.get(ch);
1360 if (ch != '=')
1361 {
1362 OnError(_T("Expected = following name: malformed tex2rtf.ini file."));
1363 return FALSE;
1364 }
1365 else
1366 {
1367 wxChar settingValue[200];
1368 BibEatWhiteSpace(istr);
1369 BibReadToEOL(istr, settingValue);
1370 RegisterSetting(settingName, settingValue);
1371 }
1372 }
1373 else
1374 {
1375 BibReadWord(istr, macroName);
1376 BibEatWhiteSpace(istr);
1377 istr.get(ch);
1378 if (ch != '[')
1379 {
1380 OnError(_T("Expected [ followed by number of arguments: malformed tex2rtf.ini file."));
1381 return FALSE;
1382 }
1383 istr >> noArgs;
1384 istr.get(ch);
1385 if (ch != ']')
1386 {
1387 OnError(_T("Expected ] following number of arguments: malformed tex2rtf.ini file."));
1388 return FALSE;
1389 }
1390 BibEatWhiteSpace(istr);
1391 istr.get(ch);
1392 if (ch != '{')
1393 {
1394 OnError(_T("Expected { followed by macro body: malformed tex2rtf.ini file."));
1395 return FALSE;
1396 }
1397 CustomMacro *macro = new CustomMacro(macroName, noArgs, NULL);
1398 BibReadValue(istr, macroBody, FALSE, FALSE); // Don't ignore extra braces
1399 if (wxStrlen(macroBody) > 0)
1400 macro->macroBody = copystring(macroBody);
1401
1402 BibEatWhiteSpace(istr);
1403 CustomMacroList.Append(macroName, macro);
1404 AddMacroDef(ltCUSTOM_MACRO, macroName, noArgs);
1405 }
1406 }
1407 wxChar mbuf[200];
1408 wxSprintf(mbuf, _T("Read initialization file %s."), filename);
1409 OnInform(mbuf);
1410 return TRUE;
1411 }
1412
1413 CustomMacro *FindCustomMacro(wxChar *name)
1414 {
1415 wxNode *node = CustomMacroList.Find(name);
1416 if (node)
1417 {
1418 CustomMacro *macro = (CustomMacro *)node->GetData();
1419 return macro;
1420 }
1421 return NULL;
1422 }
1423
1424 // Display custom macros
1425 void ShowCustomMacros(void)
1426 {
1427 wxNode *node = CustomMacroList.GetFirst();
1428 if (!node)
1429 {
1430 OnInform(_T("No custom macros loaded.\n"));
1431 return;
1432 }
1433
1434 wxChar buf[400];
1435 while (node)
1436 {
1437 CustomMacro *macro = (CustomMacro *)node->GetData();
1438 wxSprintf(buf, _T("\\%s[%d]\n {%s}"), macro->macroName, macro->noArgs,
1439 macro->macroBody ? macro->macroBody : _T(""));
1440 OnInform(buf);
1441 node = node->GetNext();
1442 }
1443 }
1444
1445 // Parse a string into several comma-separated fields
1446 wxChar *ParseMultifieldString(wxChar *allFields, int *pos)
1447 {
1448 static wxChar buffer[300];
1449 int i = 0;
1450 int fieldIndex = *pos;
1451 int len = wxStrlen(allFields);
1452 int oldPos = *pos;
1453 bool keepGoing = TRUE;
1454 while ((fieldIndex <= len) && keepGoing)
1455 {
1456 if (allFields[fieldIndex] == _T(' '))
1457 {
1458 // Skip
1459 fieldIndex ++;
1460 }
1461 else if (allFields[fieldIndex] == _T(','))
1462 {
1463 *pos = fieldIndex + 1;
1464 keepGoing = FALSE;
1465 }
1466 else if (allFields[fieldIndex] == 0)
1467 {
1468 *pos = fieldIndex + 1;
1469 keepGoing = FALSE;
1470 }
1471 else
1472 {
1473 buffer[i] = allFields[fieldIndex];
1474 fieldIndex ++;
1475 i++;
1476 }
1477 }
1478 buffer[i] = 0;
1479 if (oldPos == (*pos))
1480 *pos = len + 1;
1481
1482 if (i == 0)
1483 return NULL;
1484 else
1485 return buffer;
1486 }
1487
1488 /*
1489 * Colour tables
1490 *
1491 */
1492
1493 ColourTableEntry::ColourTableEntry(const wxChar *theName, unsigned int r, unsigned int g, unsigned int b)
1494 {
1495 name = copystring(theName);
1496 red = r;
1497 green = g;
1498 blue = b;
1499 }
1500
1501 ColourTableEntry::~ColourTableEntry(void)
1502 {
1503 delete[] name;
1504 }
1505
1506 void AddColour(const wxChar *theName, unsigned int r, unsigned int g, unsigned int b)
1507 {
1508 wxNode *node = ColourTable.Find(theName);
1509 if (node)
1510 {
1511 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
1512 if (entry->red == r || entry->green == g || entry->blue == b)
1513 return;
1514 else
1515 {
1516 delete entry;
1517 delete node;
1518 }
1519 }
1520 ColourTableEntry *entry = new ColourTableEntry(theName, r, g, b);
1521 ColourTable.Append(theName, entry);
1522 }
1523
1524 int FindColourPosition(wxChar *theName)
1525 {
1526 int i = 0;
1527 wxNode *node = ColourTable.GetFirst();
1528 while (node)
1529 {
1530 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
1531 if (wxStrcmp(theName, entry->name) == 0)
1532 return i;
1533 i ++;
1534 node = node->GetNext();
1535 }
1536 return -1;
1537 }
1538
1539 // Converts e.g. "red" -> "#FF0000"
1540 extern void DecToHex(int, wxChar *);
1541 bool FindColourHTMLString(wxChar *theName, wxChar *buf)
1542 {
1543 wxNode *node = ColourTable.GetFirst();
1544 while (node)
1545 {
1546 ColourTableEntry *entry = (ColourTableEntry *)node->GetData();
1547 if (wxStrcmp(theName, entry->name) == 0)
1548 {
1549 wxStrcpy(buf, _T("#"));
1550
1551 wxChar buf2[3];
1552 DecToHex(entry->red, buf2);
1553 wxStrcat(buf, buf2);
1554 DecToHex(entry->green, buf2);
1555 wxStrcat(buf, buf2);
1556 DecToHex(entry->blue, buf2);
1557 wxStrcat(buf, buf2);
1558
1559 return TRUE;
1560 }
1561 node = node->GetNext();
1562 }
1563 return FALSE;
1564 }
1565
1566
1567 void InitialiseColourTable(void)
1568 {
1569 // \\red0\\green0\\blue0;
1570 AddColour(_T("black"), 0,0,0);
1571
1572 // \\red0\\green0\\blue255;\\red0\\green255\\blue255;\n");
1573 AddColour(_T("cyan"), 0,255,255);
1574
1575 // \\red0\\green255\\blue0;
1576 AddColour(_T("green"), 0,255,0);
1577
1578 // \\red255\\green0\\blue255;
1579 AddColour(_T("magenta"), 255,0,255);
1580
1581 // \\red255\\green0\\blue0;
1582 AddColour(_T("red"), 255,0,0);
1583
1584 // \\red255\\green255\\blue0;
1585 AddColour(_T("yellow"), 255,255,0);
1586
1587 // \\red255\\green255\\blue255;}");
1588 AddColour(_T("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(wxChar *topic, wxChar *entry, wxChar *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(wxChar *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 wxChar *ConvertCase(wxChar *s)
1673 {
1674 static wxChar buf[256];
1675 int len = wxStrlen(s);
1676 int i;
1677 if (upperCaseNames)
1678 for (i = 0; i < len; i ++)
1679 buf[i] = wxToupper(s[i]);
1680 else
1681 for (i = 0; i < len; i ++)
1682 buf[i] = wxTolower(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