/*
 * rtfutils.cc
 *
 * Utility functions for helping convert Latex files
 * into RTF files suitable for compiling into WinHelp
 * files.
 *
 * Julian Smart September 1993
 *
 */

#include "wx.h"
#include "tex2any.h"
#include "tex2rtf.h"
#include <ctype.h>
#include "bmputils.h"

wxList itemizeStack;
static int tabCount = 0; // Output a tab if we've set a tab stop in an environment
static int indentLevel = 0;
static int forbidParindent = 0; // if > 0, no parindent (e.g. in center environment)
static char *contentsLineSection = NULL;
static char *contentsLineValue = NULL;
static TexChunk *descriptionItemArg = NULL;
static wxStringList environmentStack; // Stack of paragraph styles we need to remember
Bool inTable = FALSE;
Bool startRows = FALSE;
Bool tableVerticalLineLeft = FALSE;
Bool tableVerticalLineRight = FALSE;
int noColumns = 0;   // Current number of columns in table
extern Bool winHelp;
extern Bool startedSections;
extern FILE *Contents;
extern FILE *Chapters;
// This is defined in the Tex2Any library and isn't in use after parsing
extern char *BigBuffer;
// Are we in verbatim mode? If so, format differently.
static Bool inVerbatim = FALSE;


 /*
  * Write a suitable RTF header.
  *
  */
  
void WriteRTFHeader(FILE *fd)
{
  fprintf(fd, "{\\rtf1\\ansi \\deff0\n");
  fprintf(fd, "{\\fonttbl{\\f0\\froman Times New Roman;}{\\f1\\fdecor Symbol;}{\\f2\\fswiss Arial;}\n");
  fprintf(fd, "{\\f3\\fmodern Courier;}\n}\n{\\colortbl;\n");
  fprintf(fd, "\\red0\\green0\\blue0;\\red0\\green0\\blue255;\\red0\\green255\\blue255;\n");
  fprintf(fd, "\\red0\\green255\\blue0;\n");
  fprintf(fd, "\\red255\\green0\\blue255;\\red255\\green0\\blue0;\\red255\\green255\\blue0;\n");
  fprintf(fd, "\\red255\\green255\\blue255;}\n");
}


/*
 * Given a TexChunk with a string value, scans through the string
 * converting Latex-isms into RTF-isms, such as 2 newlines -> \par,
 * and inserting spaces at the start of lines since in Latex, a newline
 * implies a space, but not in RTF.
 *
 */
 
void ProcessText2RTF(TexChunk *chunk)
{
  Bool changed = FALSE;
  int ptr = 0;
  int i = 0;
  char ch = 1;
  int len = strlen(chunk->value);
  while (ch != 0)
  {
    ch = chunk->value[i];

    if (ch == 10)
    {
      if (inVerbatim)
      {
        BigBuffer[ptr] = 0; strcat(BigBuffer, "\\line\n"); ptr += 6;
        i ++;
        changed = TRUE;
      }
      else
      {
/*
        // 2 newlines means 2 \pars
        if ((len > i+1 && chunk->value[i+1] == 10) ||
             ((len > i+1 && chunk->value[i+1] == 13) &&
              (len > i+2 && chunk->value[i+2] == 10)))
        {
          BigBuffer[ptr] = 0;
//          strcat(BigBuffer, "\\sa240\\par\\pard\n"); ptr += 16;
          strcat(BigBuffer, "\\par\\par\n"); ptr += 9;
          i += 2;
          changed = TRUE;
        }
*/        
        // If the first character of the next line is ASCII,
        // put a space in. Implicit in Latex, not in RTF.
        if ((i > 0) && (len > i+1 && isascii(chunk->value[i+1]) &&
                  !isspace(chunk->value[i+1])) ||
            ((len > i+1 && chunk->value[i+1] == 13) &&
             (len > i+2 && isascii(chunk->value[i+2]) &&
              !isspace(chunk->value[i+2]))))
        {
          // DOS files have a 13 after the 10
          BigBuffer[ptr] = 10;
          ptr ++;
          i ++;
          if (chunk->value[i] == 13)
          {
            BigBuffer[ptr] = 13;
            ptr ++;
            i ++;
          }

          BigBuffer[ptr] = ' ';
          ptr ++;

          // Note that the actual ASCII character seen is dealt with in the next
          // iteration
          changed = TRUE;
        }
        else
        {
          BigBuffer[ptr] = ch;
          i ++;
        }
      }
    }
    else if (!inVerbatim && ch == '`' && (len >= i+1 && chunk->value[i+1] == '`'))
    {
      BigBuffer[ptr] = '"'; ptr ++;
      i += 2;
      changed = TRUE;
    }
    else if (!inVerbatim && ch == '`') // Change ` to '
    {
      BigBuffer[ptr] = 39; ptr ++;
      i += 1;
      changed = TRUE;
    }
    else if (inVerbatim && ch == '\\') // Change backslash to two backslashes
    {
      BigBuffer[ptr] = '\\'; ptr ++;
      BigBuffer[ptr] = '\\'; ptr ++;
      i += 1;
      changed = TRUE;
    }
    else if (inVerbatim && (ch == '{' || ch == '}')) // Escape the curly bracket
    {
      BigBuffer[ptr] = '\\'; ptr ++;
      BigBuffer[ptr] = ch; ptr ++;
      i += 1;
      changed = TRUE;
    }
    else
    {
      BigBuffer[ptr] = ch;
      i ++;
      ptr ++;
    }
  }
  BigBuffer[ptr] = 0;

  if (changed)
  {
    delete chunk->value;
    chunk->value = copystring(BigBuffer);
  }
}

/*
 * Scan through all chunks starting from the given one,
 * calling ProcessText2RTF to convert Latex-isms to RTF-isms.
 * This should be called after Tex2Any has parsed the file,
 * and before TraverseDocument is called.
 *
 */
 
void Text2RTF(TexChunk *chunk)
{
  switch (chunk->type)
  {
    case CHUNK_TYPE_MACRO:
    {
      TexMacroDef *def = NULL;
      wxNode *node = MacroDefs.Find(chunk->name);

      if (node)
      {
        def = (TexMacroDef *)node->Data();
        if (def->ignore)
          return;
      }

      if (def && strcmp(def->name, "verbatim") == 0)
        inVerbatim = TRUE;

      node = chunk->children.First();
      while (node)
      {
        TexChunk *child_chunk = (TexChunk *)node->Data();
        Text2RTF(child_chunk);
        node = node->Next();
      }

      if (def && strcmp(def->name, "verbatim") == 0)
        inVerbatim = FALSE;

      break;
    }
    case CHUNK_TYPE_ARG:
    {
      wxNode *node = chunk->children.First();
      while (node)
      {
        TexChunk *child_chunk = (TexChunk *)node->Data();
        Text2RTF(child_chunk);
        node = node->Next();
      }

      break;
    }
    case CHUNK_TYPE_STRING:
    {
      if (chunk->value)
        ProcessText2RTF(chunk);
      break;
    }
  }
}

/*
 * Not used yet
 *
 */
 
char browseBuf[100];
char *GetBrowseString(void)
{
  sprintf(browseBuf, "%ld", NewId());
  return browseBuf;
}

/*
 * Keeping track of environments to restore the styles after \pard.
 * Push strings like "\qc" onto stack.
 *
 */

void PushEnvironmentStyle(char *style)
{
  environmentStack.Add(style);
}

void PopEnvironmentStyle(void)
{
  wxNode *node = environmentStack.Last();
  if (node)
  {
    char *val = (char *)node->Data();
    delete[] val;
    delete node;
  }
}

// Write out the styles, most recent first.
void WriteEnvironmentStyles(void)
{
  wxNode *node = environmentStack.Last();
  while (node)
  {
    char *val = (char *)node->Data();
    TexOutput(val);
    node = node->Next();
  }
  if (!inTable && (ParIndent > 0) && (forbidParindent == 0))
  {
    char buf[15];
    sprintf(buf, "\\fi%d", ParIndent*20); // Convert points to TWIPS
    TexOutput(buf);
  }
  if (environmentStack.Number() > 0 || (ParIndent > 0))
    TexOutput("\n");
}


// Called on start/end of macro examination
void RTFOnMacro(char *name, int no_args, Bool start)
{
  char buf[300];
  if (strcmp(name, "chapter") == 0 || strcmp(name, "chapter*") == 0 || strcmp(name, "myheading") == 0)
  {
    if (start)
    {
      sectionNo = 0;
      figureNo = 0;
      subsectionNo = 0;
      subsubsectionNo = 0;
      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }

      if (winHelp)
        SetCurrentOutputs(Contents, Chapters);
      else
        SetCurrentOutput(Contents);

      fprintf(Chapters, "\\page\n");
      if (!startedSections)
        fprintf(Contents, "{\n\\par\n\\pard\\b\\fs%d Contents}\\par\\par\\pard\n\n",
          chapterFont*2);

      if (winHelp)
        fprintf(Contents, "\n{\\uldb ");
      else if (strcmp(name, "chapter*") != 0 && strcmp(name, "myheading") != 0)
      {
        chapterNo ++;
        fprintf(Contents, "\\par\n\\pard{\\b %d\\tab ", chapterNo);
      }
      else SetCurrentOutput(NULL);

      startedSections = TRUE;

      if (winHelp)
        fprintf(Chapters, "\n${\\footnote ");
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());

      if (!winHelp)
        AddTexRef(topicName, NULL, "chapter", chapterNo);
      
      if (winHelp)
        fprintf(Contents, "}{\\v %s}\\par\\pard\n", topicName);
      else if (strcmp(name, "chapter*") != 0 && strcmp(name, "myheading") != 0)
        fprintf(Contents, "}\\par\\par\\pard\n");

      SetCurrentOutput(Chapters);

      if (winHelp)
      {
        fprintf(Chapters, "}\n#{\\footnote %s}\n", topicName);
        fprintf(Chapters, "+{\\footnote b}\n");
        fprintf(Chapters, "K{\\footnote ");
        TraverseChildrenFromChunk(currentSection);
        fprintf(Chapters, "}\n");
      }
      
      fprintf(Chapters, "\\pard{%s\\b\\fs%d ", (winHelp ? "\\keepn" : ""), chapterFont*2);
      if (!winHelp)
      {
        if (strcmp(name, "chapter*") != 0)
          fprintf(Chapters, "Chapter %d\\par\\par\n", chapterNo);
      }
      TraverseChildrenFromChunk(currentSection);
      TexOutput("}\n");
//      if (winHelp) TexOutput("\\pard");
    }
  }
  else if (strcmp(name, "section") == 0 || strcmp(name, "section*") == 0 ||
           strcmp(name, "gloss") == 0 || strcmp(name, "problem") == 0)
  {
    FILE *jumpFrom;
    if (DocumentStyle == LATEX_ARTICLE)
      jumpFrom = Contents;
    else
      jumpFrom = Chapters;

    if (start)
    {
      subsectionNo = 0;
      subsubsectionNo = 0;

      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }
      if (winHelp)
      {
        SetCurrentOutputs(jumpFrom, Sections);
        // Newline for a new section if this is an article
        if ((DocumentStyle == LATEX_ARTICLE) && (strcmp(name, "section") == 0 || strcmp(name, "section*") == 0))
          fprintf(Sections, "\\page\n");
      }
      else
        SetCurrentOutput(Contents);

      if (!startedSections)  // Might be an article, with no Chapters
        fprintf(Contents, "{\n\\par\n\\pard\\b\\fs%d Contents}\\par\\par\\pard\n\n",
         sectionFont*2);

      if (winHelp)
        fprintf(jumpFrom, "\n{\\uldb ");
      else if (strcmp(name, "section*") != 0)
      {
        sectionNo ++;

        if (DocumentStyle == LATEX_REPORT)
          fprintf(Contents, "\n\\pard{\\tab %d.%d\\tab ", chapterNo, sectionNo);
        else
          fprintf(Contents, "\\par\n\\pard{\\b %d\\tab ", sectionNo);
      }
      else SetCurrentOutput(NULL);

      if (startedSections)
      {
        if (winHelp)
          fprintf(Sections, "\\page\n");
      }

      startedSections = TRUE;

      if (winHelp)
        fprintf(Sections, "\n${\\footnote ");
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());
      if (!winHelp)
        AddTexRef(topicName, NULL, "section", chapterNo, sectionNo);

      if (winHelp)
        fprintf(jumpFrom, "}{\\v %s}\\par\\pard\n", topicName);
      else if (strcmp(name, "section*") != 0)
      {
        if (DocumentStyle == LATEX_REPORT)
          fprintf(Contents, "}\\par\\pard\n");
        else
          fprintf(Contents, "}\\par\\par\\pard\n");
      }
        
      SetCurrentOutput(winHelp ? Sections : Chapters);

      if (winHelp)
      {
        fprintf(Sections, "}\n#{\\footnote %s}\n", topicName);
        fprintf(Sections, "+{\\footnote b}\n");
        fprintf(Sections, "K{\\footnote ");
        TraverseChildrenFromChunk(currentSection);
        fprintf(Sections, "}\n");
      }

      fprintf(winHelp ? Sections : Chapters, "\\pard{%s\\b\\fs%d ", (winHelp ? "\\keepn" : ""),
               sectionFont*2);
      if (!winHelp)
      {
        if (strcmp(name, "section*") != 0)
        {
          if (DocumentStyle == LATEX_REPORT)
            fprintf(Chapters, "%d.%d. ", chapterNo, sectionNo);
          else
            fprintf(Chapters, "%d. ", sectionNo);
        }
      }
      TraverseChildrenFromChunk(currentSection);
      TexOutput("}\n");
//      if (winHelp) TexOutput("\\pard");
    }
  }
  // Write references title as if it were a chapter or section
  else if (strcmp(name, "references") == 0)
  {
    FILE *jumpTo;
    if (DocumentStyle == LATEX_ARTICLE)
      jumpTo = Sections;
    else
      jumpTo = Chapters;

    if (start)
    {
      if (winHelp)
      {
        SetCurrentOutputs(Contents, jumpTo);

        // Newline for a new section if this is an article
        if ((DocumentStyle == LATEX_ARTICLE) && (strcmp(name, "section") == 0 || strcmp(name, "section*") == 0))
          fprintf(Sections, "\\page\n");
      }
      else
        SetCurrentOutput(Contents);

      if (!startedSections)  // Might be an article, with no Chapters
        fprintf(Contents, "{\n\\par\n\\pard\\b\\fs%d Contents}\\par\\par\\pard\n\n",
         sectionFont*2);

      if (winHelp)
        fprintf(Contents, "\n{\\uldb References}");
      else
      {
        fprintf(Contents, "\n\\par\\pard{\\b References}\\par\\par\\pard");
      }

      if (startedSections && winHelp)
        fprintf(jumpTo, "\\page\n");

      startedSections = TRUE;

      if (winHelp)
        fprintf(jumpTo, "\n${\\footnote References}");

      char *topicName = "references";
      if (!winHelp)
        AddTexRef(topicName, NULL, "chapter", chapterNo);

      if (winHelp)
        fprintf(Contents, "{\\v %s}\\par\\pard\n", topicName);
        
      SetCurrentOutput(jumpTo);

      if (winHelp)
      {
        fprintf(jumpTo, "\n#{\\footnote %s}\n", topicName);
        fprintf(jumpTo, "+{\\footnote b}\n");
        fprintf(jumpTo, "K{\\footnote references}\n");
      }

      fprintf(jumpTo, "\\pard{%s\\b\\fs%d References}", (winHelp ? "\\keepn" : ""),
               sectionFont*2);
      TexOutput("\\par\\pard\\par\\par");
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(name, "subsection") == 0 || strcmp(name, "subsection*") == 0 ||
           strcmp(name, "membersection") == 0 || strcmp(name, "functionsection") == 0)
  {
    if (start)
    {
      subsubsectionNo = 0;

      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }

      if (winHelp)
        SetCurrentOutputs(Sections, Subsections);
      else
        SetCurrentOutput(Contents);

      if (winHelp)
      {
        SetCurrentOutputs(Sections, Subsections);
        fprintf(Sections, "\n{\\uldb ");
      }
      else if (strcmp(name, "subsection*") != 0 && strcmp(name, "membersection") != 0 &&
         strcmp(name, "functionsection") != 0)
      {
        subsectionNo ++;

        SetCurrentOutput(Contents);
        if (DocumentStyle == LATEX_REPORT)
          fprintf(Contents, "\n\\pard\\tab\\tab %d.%d.%d\\tab ", chapterNo, sectionNo, subsectionNo);
        else
          fprintf(Contents, "\n\\pard\\tab %d.%d\\tab ", sectionNo, subsectionNo);
      } else SetCurrentOutput(NULL);

      if (startedSections)
      {
        if (winHelp)
          fprintf(Subsections, "\\page\n");
        else
          fprintf(Chapters, "\\par\n");
      }
      startedSections = TRUE;

      if (winHelp)
        fprintf(Subsections, "\n${\\footnote ");
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());

      if (!winHelp)
        AddTexRef(topicName, NULL, "section", chapterNo, sectionNo, subsectionNo);

      if (winHelp)
        fprintf(Sections, "}{\\v %s}\\par\\pard\n", topicName);
      else if (strcmp(name, "subsection*") != 0 && strcmp(name, "membersection") != 0 &&
         strcmp(name, "functionsection") != 0)
        fprintf(Contents, "\\par\\pard\n");

      SetCurrentOutput(winHelp ? Subsections : Chapters);
      if (winHelp)
      {
        fprintf(Subsections, "}\n#{\\footnote %s}\n", topicName);
        fprintf(Subsections, "+{\\footnote c}\n");
      }

      fprintf(winHelp ? Subsections : Chapters, "\\pard{\\b\\fs%d ", subsectionFont*2);
      if (!winHelp &&
        (strcmp(name, "subsection*") != 0 && strcmp(name, "membersection") != 0 &&
         strcmp(name, "functionsection") != 0))
      {
        if (DocumentStyle == LATEX_REPORT)
          fprintf(Chapters, "%d.%d.%d. ", chapterNo, sectionNo, subsectionNo);
        else
          fprintf(Chapters, "%d.%d. ", sectionNo, subsectionNo);
      }
      TraverseChildrenFromChunk(currentSection); // Repeat section header
      TexOutput("}\n");
//      if (winHelp) TexOutput("\\pard");
    }
  }
  else if (strcmp(name, "subsubsection") == 0)
  {
    if (start)
    {
      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }

      if (winHelp)
      {
        SetCurrentOutputs(Subsections, Subsubsections);
        fprintf(Subsections, "\n{\\uldb ");
      }
      else if (strcmp(name, "subsubsection*") != 0)
      {
        subsubsectionNo ++;
        if (DocumentStyle == LATEX_ARTICLE)
        {
          SetCurrentOutput(Contents);
          fprintf(Contents, "\n\\tab\\tab %d.%d.%d\\tab ",
                             sectionNo, subsectionNo, subsubsectionNo);
	}
      }
      else
        SetCurrentOutput(NULL);

      if (startedSections)
      {
        if (winHelp)
          fprintf(Subsubsections, "\\page\n");
        else
          fprintf(Chapters, "\\par\n");
      }

      startedSections = TRUE;

      if (winHelp)
        fprintf(Subsubsections, "\n${\\footnote ");
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());

      if (!winHelp)
        AddTexRef(topicName, NULL, "section", chapterNo, sectionNo, subsectionNo, subsubsectionNo);

      if (winHelp)
        fprintf(Subsections, "}{\\v %s}\\par\\pard\n", topicName);
      else if ((DocumentStyle == LATEX_ARTICLE) && strcmp(name, "subsubsection*") != 0)
        fprintf(Contents, "\\par\\pard\n");
        
      SetCurrentOutput(winHelp ? Subsubsections : Chapters);
      if (winHelp)
      {
        fprintf(Subsubsections, "}\n#{\\footnote %s}\n", topicName);
        fprintf(Subsubsections, "+{\\footnote c}\n");
      }

      fprintf(winHelp ? Subsubsections : Chapters, "\\pard{\\b\\fs%d ", subsectionFont*2);
      if (!winHelp && (DocumentStyle == LATEX_ARTICLE))
        fprintf(Chapters, "%d.%d.%d. ", sectionNo, subsectionNo, subsubsectionNo);
      
      TraverseChildrenFromChunk(currentSection); // Repeat section header
      TexOutput("}\n");
//      if (winHelp) TexOutput("\\pard");
    }
  }
  else if (strcmp(name, "caption") == 0 || strcmp(name, "caption*") == 0)
  {
    if (start)
    {
      figureNo ++;

      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }

      char figBuf[40];
      if (DocumentStyle != LATEX_ARTICLE)
        sprintf(figBuf, "Figure %d.%d: ", chapterNo, figureNo);
      else
        sprintf(figBuf, "Figure %d: ", figureNo);

      TexOutput("\\pard\\qc{\\b ");
      TexOutput(figBuf);
    }
    else
    {
      TexOutput("}\\par\\pard\n");
      WriteEnvironmentStyles();

      char *topicName = FindTopicName(GetNextChunk());

      if (!winHelp)
        AddTexRef(topicName, NULL, "figure",
           ((DocumentStyle != LATEX_ARTICLE) ? chapterNo : figureNo),
            ((DocumentStyle != LATEX_ARTICLE) ? figureNo : 0));
    }
  }
  else if ((strcmp(name, "func") == 0) || (strcmp(name, "pfunc") == 0))
  {
    SetCurrentOutput(winHelp ? Subsections : Chapters);
    if (start)
    {
      TexOutput("{");
    }
    else
    {
      TexOutput("}\n");
      if (winHelp)
      {
        fprintf(Subsections, "K{\\footnote ");
        suppressNameDecoration = TRUE;
        TraverseChildrenFromChunk(currentMember);
        suppressNameDecoration = FALSE;
        fprintf(Subsections, "}\n");
      }
    }
  }
  else if (strcmp(name, "clipsfunc") == 0)
  {
    SetCurrentOutput(winHelp ? Subsections : Chapters);
    if (start)
    {
      TexOutput("{");
    }
    else
    {
      TexOutput("}\n");
      if (winHelp)
      {
        fprintf(Subsections, "K{\\footnote ");
        suppressNameDecoration = TRUE;  // Necessary so don't print "(\\bf" etc.
        TraverseChildrenFromChunk(currentMember);
        suppressNameDecoration = FALSE;
        fprintf(Subsections, "}\n");
      }
    }
  }
  else if (strcmp(name, "member") == 0)
  {
    SetCurrentOutput(winHelp ? Subsections : Chapters);
    if (start)
    {
      TexOutput("{\\b ");
    }
    else
    {
      TexOutput("}\n");
      if (winHelp)
      {
        fprintf(Subsections, "K{\\footnote ");
        TraverseChildrenFromChunk(currentMember);
        fprintf(Subsections, "}\n");
      }
    }
  }
  else if (strcmp(name, "document") == 0)
  {
    if (start)
      SetCurrentOutput(Chapters);
  }
  else if (strcmp(name, "tableofcontents") == 0)
  {
    if (start)
    {
//      fprintf(Contents, "{\n\\par\\par\\par\n\\b\\fs%d Contents}\\par\\par\\pard\n\n",
//        (isReport ? chapterFont : sectionFont) * 2);

      FILE *fd = fopen(ContentsName, "r");
      if (fd)
      {
        char ch = getc(fd);
        while (ch != EOF)
        {
          putc(ch, Chapters);
          ch = getc(fd);
        }
        fclose(fd);
      }
      else
      {
        TexOutput("{\\i RUN TEX2RTF AGAIN FOR CONTENTS PAGE}\\par\n");
        OnInform("Run Tex2RTF again to include contents page.");
      }
    }
  }
  else if ((strcmp(name, "void") == 0) && start)
    TexOutput("{\\b void}");
  else if ((strcmp(name, "hardy") == 0) && start)
    TexOutput("{\\scaps HARDY}");
  else if ((strcmp(name, "wxclips") == 0) && start)
    TexOutput("wxCLIPS");
  else if ((strcmp(name, "_&") == 0) && start)
  {
    if (inTable)
      TexOutput("\\tab\n");
    else
      TexOutput("&");
  }
  else if ((strcmp(name, "\\") == 0) && start)
  {
    if (inTable)
//      TexOutput("\\cell\n\\row\\pard\n\\intbl\n");
    {
      if (tableVerticalLineLeft)
        TexOutput("\\brdrl\\brdrs");
      if (tableVerticalLineRight)
        TexOutput("\\brdrr\\brdrs");

      TexOutput("\\par\\pard\n");

      // Calculate a rough size for each column
      int colSize = 6000/(noColumns-1);
      int colPos = colSize;
      for (int j = 0; j < noColumns; j++)
      {
        sprintf(buf, "\\tx%d", colPos);
        TexOutput(buf);
        colPos += colSize;
      }
      TexOutput("\n");
    }
    else
      TexOutput("\\line\n");
  }
  else if ((strcmp(name, ">") == 0) && start)
  {
    TexOutput("\tab ");
  }
  else if ((strcmp(name, "rtfsp") == 0) && start) // Explicit space, RTF only
    TexOutput(" ");
  else if ((strcmp(name, "itemize") == 0) ||
           (strcmp(name, "enumerate") == 0) ||
           (strcmp(name, "description") == 0))
  {
    if (start)
    {
//      tabCount ++;

      if (indentLevel > 0)
        TexOutput("\\par\\par\n");
      indentLevel ++;
      TexOutput("\\fi0\n");
      int listType;
      if (strcmp(name, "enumerate") == 0)
        listType = LATEX_ENUMERATE;
      else if (strcmp(name, "itemize") == 0)
        listType = LATEX_ITEMIZE;
      else
        listType = LATEX_DESCRIPTION;
      itemizeStack.Insert(new ItemizeStruc(listType));

      int indentSize = (int)(indentLevel*360);
      sprintf(buf, "\\tx%d\\li%d", indentSize, indentSize);
      PushEnvironmentStyle(buf);
    }
    else
    {
      indentLevel --;
//      tabCount --;
      PopEnvironmentStyle();

      if (indentLevel == 0)
      {
        TexOutput("\\par\\pard\n");
        WriteEnvironmentStyles();
      }
      if (itemizeStack.First())
      {
        ItemizeStruc *struc = (ItemizeStruc *)itemizeStack.First()->Data();
        delete struc;
        delete itemizeStack.First();
      }
    }
  }
  else if (strcmp(name, "item") == 0)
  {
    wxNode *node = itemizeStack.First();
    if (node)
    {
      ItemizeStruc *struc = (ItemizeStruc *)node->Data();
      if (!start)
      {
        struc->currentItem += 1;
        char indentBuf[30];

        int indentSize = (int)(indentLevel*360);

        TexOutput("\n");
        if (struc->currentItem > 1)
        {
          TexOutput("\\par\\par");
//          WriteEnvironmentStyles();
        }

        sprintf(buf, "\\tx%d\\li%d\\fi-360\n", indentSize, indentSize);
        TexOutput(buf);

        switch (struc->listType)
        {
          case LATEX_ENUMERATE:
          {
            sprintf(indentBuf, "{\\b %d.}\\tab", struc->currentItem);
            TexOutput(indentBuf);
            break;
          }
          case LATEX_ITEMIZE:
          {
            sprintf(indentBuf, "{\\b o}\\tab");
            TexOutput(indentBuf);
            break;
          }
          default:
          case LATEX_DESCRIPTION:
          {
            if (descriptionItemArg)
            {
              TexOutput("{\\b ");
              TraverseChildrenFromChunk(descriptionItemArg);
              TexOutput("}  ");
              descriptionItemArg = NULL;
            }
            break;
          }
	}
      }
    }
  }
  else if (strcmp(name, "verbatim") == 0)
  {
    if (start)
    {
      sprintf(buf, "\\pard{\\f3\\fs16 ");
      TexOutput(buf);
    }
    else
    {
      TexOutput("}\\par\\pard\n");
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(name, "centerline") == 0 || strcmp(name, "center") == 0)
  {
    if (start)
    {
      TexOutput("\\fi0\\qc ");
      forbidParindent ++;
      PushEnvironmentStyle("\\qc");
    }
    else
    {
      TexOutput("\\par\\pard\n");
      forbidParindent --;
      PopEnvironmentStyle();
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(name, "flushleft") == 0)
  {
    if (start)
    {
      TexOutput("\\fi0\\ql ");
      forbidParindent ++;
      PushEnvironmentStyle("\\ql");
    }
    else
    {
      TexOutput("\\par\\pard\n");
      forbidParindent --;
      PopEnvironmentStyle();
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(name, "flushright") == 0)
  {
    if (start)
    {
      TexOutput("\\fi0\\qr ");
      forbidParindent ++;
      PushEnvironmentStyle("\\qr");
    }
    else
    {
      TexOutput("\\par\\pard\n");
      forbidParindent --;
      PopEnvironmentStyle();
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(name, "small") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", smallFont*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "tiny") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", tinyFont*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "normalsize") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", normalFont*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "large") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", largeFont1*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "Large") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", LargeFont2*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "LARGE") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", LARGEFont3*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "huge") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", hugeFont1*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "Huge") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", HugeFont2*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "HUGE") == 0)
  {
    if (start)
    {
      sprintf(buf, "{\\fs%d\n", HUGEFont3*2);
      TexOutput(buf);
    }
    else TexOutput("}\n");
  }
  else if (strcmp(name, "bf") == 0)
  {
    if (start)
    {
      TexOutput("{\\b ");
    }
    else TexOutput("}");
  }
  else if (strcmp(name, "underline") == 0)
  {
    if (start)
    {
      TexOutput("{\\ul ");
    }
    else TexOutput("}");
  }
  else if (strcmp(name, "it") == 0 || strcmp(name, "em") == 0)
  {
    if (start)
    {
      TexOutput("{\\i ");
    }
    else TexOutput("}");
  }
  else if (strcmp(name, "rm") == 0)
  {
/*    
    if (start)
    {
      TexOutput("{\\plain ");
    }
    else TexOutput("}");
 */
  }
  else if (strcmp(name, "sc") == 0)
  {
    if (start)
    {
      TexOutput("{\\scaps ");
    }
    else TexOutput("}");
  }
  else if (strcmp(name, "tt") == 0)
  {
    if (start)
    {
      TexOutput("{\\f3 ");
    }
    else TexOutput("}");
  }
  else if ((strcmp(name, "{") == 0) && start)
    TexOutput("\\{");
  else if ((strcmp(name, "}") == 0) && start)
    TexOutput("\\}");
  else if ((strcmp(name, "backslash") == 0) && start)
    TexOutput("\\\\");
  else if (strcmp(name, "par") == 0)
  {
    if (start)
    {
      TexOutput("\\par");

      TexOutput("\\pard\n");

      // Extra par if parskip is more than zero (usually looks best.)
      if (!inTable && (ParSkip > 0))
        TexOutput("\\par");

      if (!inTable && (ParIndent > 0) && (forbidParindent == 0))
      {
        sprintf(buf, "\\fi%d ", ParIndent*20);
        TexOutput(buf);
      }

      // Ought to tab if we're in a list or tab count is > 0
      if (tabCount > 0)
        TexOutput("\\tab");
      WriteEnvironmentStyles();
      TexOutput("\n");
    }
  }
  else if (strcmp(name, "newpage") == 0)
  {
    // In Windows Help, no newpages until we've started some chapters or sections!
    if (!(winHelp && !startedSections))
      if (start)
        TexOutput("\\page\n");
  }
  else if (strcmp(name, "maketitle") == 0)
  {
    if (start && DocumentTitle && DocumentAuthor)
    {
      TexOutput("\\pard\\par\\par\\qc{\\fs36\\b ");
      TraverseChildrenFromChunk(DocumentTitle);
      TexOutput("}\\par\\par\\par\\pard\n\\qc{\\fs32 ");
      TraverseChildrenFromChunk(DocumentAuthor);
      TexOutput("}\\par\\par\\pard\n");
      if (DocumentDate)
      {
        TexOutput("\\qc{\\fs32 ");
        TraverseChildrenFromChunk(DocumentDate);
        TexOutput("}\\par\\pard\n");
      }
    }
  }
  else if ((strcmp(name, "addcontentsline") == 0) && !start)
  {
    if (contentsLineSection && contentsLineValue)
    {
      if (strcmp(contentsLineSection, "chapter") == 0)
      {
        fprintf(Contents, "\\par\n{\\b %s}\\par\n", contentsLineValue);
      }
      else if (strcmp(contentsLineSection, "section") == 0)
      {
        if (DocumentStyle != LATEX_ARTICLE)
          fprintf(Contents, "\n\\tab%s\\par\n", contentsLineValue);
        else
          fprintf(Contents, "\\par\n{\\b %s}\\par\n", contentsLineValue);
      }
    }
  }
  else if (strcmp(name, "hrule") == 0)
  {
    if (start)
    {
      TexOutput("\\brdrb\\brdrs\\par\\pard\n");
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(name, "hline") == 0)
  {
    if (start)
    {
      TexOutput("\\brdrt\\brdrs\n");
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(name, "bibitem") == 0)
  {
    if (start)
      TexOutput("\\li260\\fi-260 "); // Indent from 2nd line
    else
      TexOutput("\\par\\pard\\par\n\n");
  }
  else DefaultOnMacro(name, no_args, start);
}

// Called on start/end of argument examination
Bool RTFOnArgument(char *macro_name, int arg_no, Bool start)
{
  char buf[300];
  if ((strcmp(macro_name, "chapter") == 0) ||
      (strcmp(macro_name, "chapter*") == 0) ||
      (strcmp(macro_name, "myheading") == 0) ||
      (strcmp(macro_name, "section") == 0) ||
      (strcmp(macro_name, "section*") == 0) ||
      (strcmp(macro_name, "subsection") == 0) ||
      (strcmp(macro_name, "subsection*") == 0) ||
      (strcmp(macro_name, "subsubsection") == 0) ||
      (strcmp(macro_name, "subsubsection*") == 0) ||
      (strcmp(macro_name, "gloss") == 0) ||
      (strcmp(macro_name, "membersection") == 0) ||
      (strcmp(macro_name, "functionsection") == 0))
  {
    if (!start && (arg_no == 1))
      currentSection = GetArgChunk();
  }
  else if (strcmp(macro_name, "func") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("\\pard\\li260\\fi-260{\\b ");

    if (!start && (arg_no == 1))
      TexOutput("} ");

    if (start && (arg_no == 2))
    {
      if (!suppressNameDecoration) TexOutput("{\\b ");
      currentMember = GetArgChunk();
    }
    if (!start && (arg_no == 2))
    {
      if (!suppressNameDecoration) TexOutput("}");
    }
    
    if (start && (arg_no == 3))
      TexOutput("(");
    if (!start && (arg_no == 3))
    {
      TexOutput(")\\li0\\fi0");
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(macro_name, "clipsfunc") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("\\pard\\li260\\fi-260{\\b ");
    if (!start && (arg_no == 1))
      TexOutput("} ");

    if (start && (arg_no == 2))
    {
      if (!suppressNameDecoration) TexOutput("({\\b ");
      currentMember = GetArgChunk();
    }
    if (!start && (arg_no == 2))
    {
      if (!suppressNameDecoration) TexOutput("}");
    }

    if (!start && (arg_no == 3))
    {
      TexOutput(")\\li0\\fi0");
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(macro_name, "pfunc") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("\\pard\\li260\\fi-260");

    if (!start && (arg_no == 1))
      TexOutput(" ");

    if (start && (arg_no == 2))
      TexOutput("(*");
    if (!start && (arg_no == 2))
      TexOutput(")");

    if (start && (arg_no == 2))
      currentMember = GetArgChunk();

    if (start && (arg_no == 3))
      TexOutput("(");
    if (!start && (arg_no == 3))
    {
      TexOutput(")\\li0\\fi0");
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(macro_name, "param") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("{\\b ");
    if (!start && (arg_no == 1))
      TexOutput("}");
    if (start && (arg_no == 2))
    {
      TexOutput("{\\i ");
    }
    if (!start && (arg_no == 2))
    {
      TexOutput("}");
    }
  }
  else if (strcmp(macro_name, "cparam") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("{\\b ");
    if (!start && (arg_no == 1))
      TexOutput("} ");  // This is the difference from param - one space!
    if (start && (arg_no == 2))
    {
      TexOutput("{\\i ");
    }
    if (!start && (arg_no == 2))
    {
      TexOutput("}");
    }
  }
  else if (strcmp(macro_name, "member") == 0)
  {
    if (!start && (arg_no == 1))
      TexOutput(" ");

    if (start && (arg_no == 2))
      currentMember = GetArgChunk();
  }
  else if (strcmp(macro_name, "helpref") == 0 || strcmp(macro_name, "helprefn") == 0)
  {
    if (winHelp)
    {
      if ((GetNoArgs() - arg_no) == 1)
      {
        if (start)
          TexOutput("{\\uldb ");
        else
          TexOutput("}");
      }
      if ((GetNoArgs() - arg_no) == 0) // Arg = 2, or 3 if first is optional
      {
        if (start)
          TexOutput("{\\v ");
        else TexOutput("}");
      }
    }
    else // If a linear document, must resolve the references ourselves
    {
      if ((GetNoArgs() - arg_no) == 1)
      {
        // In a linear document we display the anchor text in bold plus
        // the section/figure number.
        if (start)
          TexOutput("{\\b ");
        else
          TexOutput("}");
        return TRUE;
      }
      else if ((GetNoArgs() - arg_no) == 0) // Arg = 2, or 3 if first is optional
      {
        if (strcmp(macro_name, "helprefn") != 0)
        {
          if (start)
          {
            TexOutput(" (");
            char *refName = GetArgData();
            if (refName)
            {
              wxNode *node = TexReferences.Find(refName);
              if (node)
              {
                TexRef *texRef = (TexRef *)node->Data();
                TexOutput(texRef->sectionNumber);
              }
              else
              {
                TexOutput("??");
                sprintf(buf, "Warning: unresolved reference %s.", refName); 
                OnInform(buf);
              }
            }
            else TexOutput("??");
          }
          else TexOutput(")");
        }
        return FALSE;
      }
    }
  }
  else if (strcmp(macro_name, "addcontentsline") == 0)
  {
    if (start && !winHelp)
    {
      if (arg_no == 2)
        contentsLineSection = copystring(GetArgData());
      else if (arg_no == 3)
        contentsLineValue = copystring(GetArgData());
      return FALSE;
    }
    else return FALSE;
  }
  else if (strcmp(macro_name, "image") == 0 || strcmp(macro_name, "psboxto") == 0)
  {
    if (start && (arg_no == 2 || !IsArgOptional()))
    {
      char *filename = copystring(GetArgData());
      strcpy(buf, filename);
      StripExtension(buf);
      strcat(buf, ".bmp");
      char *f = TexPathList.FindValidPath(buf);
      if (f)
      {
        FILE *fd = fopen(f, "r");
        if (OutputBitmapHeader(fd, winHelp))
          OutputBitmapData(fd);
      }
      else
      {
        TexOutput("(Insert image file ");
        TexOutput(filename);
        TexOutput(")\n");
        sprintf(buf, "Warning: could not find a BMP equivalent for %s.", filename);
        OnInform(buf);
      }
      return FALSE;
    }
    else
      return FALSE;
  }
  else if (strcmp(macro_name, "tabular") == 0 || strcmp(macro_name, "supertabular") == 0)
  {
    if (arg_no == 1)
    {
      if (start)
      {
        inTable = TRUE;
        startRows = TRUE;
        tableVerticalLineLeft = FALSE;
        tableVerticalLineRight = FALSE;

        char *alignString = copystring(GetArgData());

        // Count the number of columns
        noColumns = 0;
        int len = strlen(alignString);
        if (len > 0)
        {
          if (alignString[0] == '|')
            tableVerticalLineLeft = TRUE;
          if (alignString[len-1] == '|')
            tableVerticalLineRight = TRUE;
        }

        for (int i = 0; i < len; i++)
          if (isalpha(alignString[i]))
            noColumns ++;

      // Experimental
      TexOutput("\\brdrt\\brdrs");
      if (tableVerticalLineLeft)
        TexOutput("\\brdrl\\brdrs");
      if (tableVerticalLineRight)
        TexOutput("\\brdrr\\brdrs");

      // Calculate a rough size for each column
      int colSize = 6000/(noColumns-1);
      int colPos = colSize;
      for (int j = 0; j < noColumns; j++)
      {
        sprintf(buf, "\\tx%d ", colPos);
        TexOutput(buf);
        colPos += colSize;
      }

/*
        // Calculate a rough size for each column
        int colSize = 6000/(noColumns-1);
        int colPos = colSize;
        for (int j = 0; j < noColumns; j++)
        {
          sprintf(buf, "%d", colPos);
          TexOutput("\\colx"); TexOutput(buf);
          colPos += colSize;
        }
        TexOutput("\\brdrb\\brdrs\n\\intbl\n");
*/
        return FALSE;
      }
    }
    else if (arg_no == 2 && !start)
    {
      TexOutput("\\par\\pard\n");
      WriteEnvironmentStyles();
      inTable = FALSE;
    }
  }
  else if (strcmp(macro_name, "quote") == 0 || strcmp(macro_name, "verse") == 0)
  {
    if (start)
    {
      TexOutput("\\li360\n");
      forbidParindent ++;
      PushEnvironmentStyle("\\li360");
    }
    else
    {
      TexOutput("\\par\\pard\n");
      forbidParindent --;
      PopEnvironmentStyle();
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(macro_name, "quotation") == 0)
  {
    if (start)
    {
      TexOutput("\\li360\n");
      PushEnvironmentStyle("\\li360");
    }
    else
    {
      TexOutput("\\par\\pard\n");
      PopEnvironmentStyle();
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(macro_name, "boxit") == 0 || strcmp(macro_name, "framebox") == 0 ||
           strcmp(macro_name, "fbox") == 0 || strcmp(macro_name, "mbox") == 0)
  {
    if (start)
    {
      TexOutput("\\box\n");
      PushEnvironmentStyle("\\box");
    }
    else
    {
      TexOutput("\\par\\pard\n");
      PopEnvironmentStyle();
      WriteEnvironmentStyles();
    }
  }
  else if (strcmp(macro_name, "helpfontsize") == 0)
  {
    if (start)
    {
      char *data = GetArgData();
      if (strcmp(data, "10") == 0)
        SetFontSizes(10);
      else if (strcmp(data, "11") == 0)
        SetFontSizes(11);
      else if (strcmp(data, "12") == 0)
        SetFontSizes(12);
      sprintf(buf, "\\fs%d\n", normalFont*2);
      TexOutput(buf);
      TexOutput(buf);
      return FALSE;
    }
  }
  else if (strcmp(macro_name, "helpfontfamily") == 0)
  {
    if (start)
    {
      char *data = GetArgData();
      if (strcmp(data, "Swiss") == 0)
        TexOutput("\\f2\n");
      else if (strcmp(data, "Symbol") == 0)
        TexOutput("\\f1\n");
      else if (strcmp(data, "Times") == 0)
        TexOutput("\\f0\n");

      return FALSE;
    }
  }
  else if (strcmp(macro_name, "parindent") == 0)
  {
    if (start && arg_no == 1)
    {
      char *data = GetArgData();
      ParIndent = ParseUnitArgument(data);
      if (ParIndent == 0 || forbidParindent == 0)
      {
        sprintf(buf, "\\fi%d\n", ParIndent*20);
        TexOutput(buf);
      }
      return FALSE;
    }
  }
  else if (strcmp(macro_name, "item") == 0)
  {
    if (start && IsArgOptional())
    {
      descriptionItemArg = GetArgChunk();
      return FALSE;
    }
  }
  else return DefaultOnArgument(macro_name, arg_no, start);
  return TRUE;
}

Bool RTFGo(void)
{
  // Reset variables
  tabCount = 0;
  indentLevel = 0;
  forbidParindent = 0;
  contentsLineSection = NULL;
  contentsLineValue = NULL;
  descriptionItemArg = NULL;
  inTable = FALSE;
  startRows = FALSE;
  tableVerticalLineLeft = FALSE;
  tableVerticalLineRight = FALSE;
  noColumns = 0;
  startedSections = FALSE;
  inVerbatim = FALSE;

  if (InputFile && OutputFile)
  {
    // Do some RTF-specific transformations on all the strings,
    // recursively
    Text2RTF(GetTopLevelChunk());

    Contents = fopen(TmpContentsName, "w");
    Chapters = fopen("chapters.rtf", "w");
    if (winHelp)
    {
      Sections = fopen("sections.rtf", "w");
      Subsections = fopen("subsections.rtf", "w");
      Subsubsections = fopen("subsubsections.rtf", "w");
    }

    WriteRTFHeader(Chapters);

    // By default, Swiss, 10 point.
    fprintf(Chapters, "\\f2\\fs20\n");

/*
    fprintf(Contents, "#{\\footnote contents}\n${\\footnote %s}\n",
      contentsString ? contentsString : "WXHELPCONTENTS");
    fprintf(Contents, "K{\\footnote Contents}\n+{\\footnote a}\n");
    fprintf(Contents, "{\\b\\fs%d %s\\sa240\\par\\pard}\n", LARGEFont3*2,
      contentsString ? contentsString : "WXHELPCONTENTS");
*/
    SetCurrentOutput(Chapters);

    OnInform("Converting...");
    TraverseDocument();

    if (winHelp)
    {
//      fprintf(Contents, "\\page\n");
      fprintf(Chapters, "\\page\n");
      fprintf(Sections, "\\page\n");
      fprintf(Subsections, "\\page\n");
      fprintf(Subsubsections, "\\page\n}\n");
    }

/*
    TexOutput("\n\\info{\\doccomm Document created by Julian Smart's Tex2RTF.}\n");
    if (DocumentTitle)
    {
      TexOutput("{\\title ");
      TraverseChildrenFromChunk(DocumentTitle);
      TexOutput("}\n");
    }
    if (DocumentAuthor)
    {
      TexOutput("{\\author ");
      TraverseChildrenFromChunk(DocumentAuthor);
      TexOutput("}\n");
    }
*/
    if (!winHelp)
      TexOutput("}\n");

    fclose(Contents);
    fclose(Chapters);
    if (winHelp)
    {
      fclose(Sections);
      fclose(Subsections);
      fclose(Subsubsections);
    }

    if (winHelp)
    {
      wxConcatFiles("chapters.rtf", "sections.rtf", "tmp1.rtf");
      wxConcatFiles("tmp1.rtf", "subsections.rtf", "tmp2.rtf");
      wxConcatFiles("tmp2.rtf", "subsubsections.rtf", OutputFile);

      wxRemoveFile("tmp1.rtf");
      wxRemoveFile("tmp2.rtf");
    }
    else
    {
      if (FileExists(OutputFile)) wxRemoveFile(OutputFile);
      wxCopyFile("chapters.rtf", OutputFile);
    }
    
    if (FileExists(ContentsName)) wxRemoveFile(ContentsName);
    wxRenameFile(TmpContentsName, ContentsName);

    wxRemoveFile("chapters.rtf");
      
    if (winHelp)
    {
      wxRemoveFile("sections.rtf");
      wxRemoveFile("subsections.rtf");
      wxRemoveFile("subsubsections.rtf");
    }
    return TRUE;
  }
  return FALSE;
}

