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