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