home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / utils / tex2rtf / src / texutils.cpp < prev    next >
C/C++ Source or Header  |  2002-07-19  |  44KB  |  1,674 lines

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