/*
 * htmlutil.cc
 *
 * Utility functions for helping convert Latex files
 * into HTML files.
 * files.
 *
 * Julian Smart September 1993
 *
 */

#include <wx.h>
#include "tex2any.h"
#include "tex2rtf.h"

char *ChaptersName = NULL;
char *SectionsName = NULL;
char *SubsectionsName = NULL;
char *SubsubsectionsName = NULL;

static TexChunk *descriptionItemArg = NULL;
static TexChunk *helpRefFilename = NULL;
static TexChunk *helpRefText = NULL;
static int indentLevel = 0;
extern FILE *Contents;
FILE *Titlepage = NULL;
int fileId = 0;

// Are we in verbatim mode? If so, format differently.
static Bool inVerbatim = FALSE;

// This is defined in the Tex2Any library.
extern char *BigBuffer;

class HyperReference: public wxObject
{
 public:
  char *refName;
  char *refFile;
  HyperReference(char *name, char *file)
  {
    if (name) refName = copystring(name);
    if (file) refFile = copystring(file);
  }

};

/*
 * Close former filedescriptor and reopen using another filename.
 *
 */

void ReopenFile(FILE **fd, char **fileName)
{
  if (*fd)
  {
    fclose(*fd);
  }
  fileId ++;
  char buf[200];
  sprintf(buf, "%s%d.html", FileRoot, fileId);
  if (*fileName) delete[] *fileName;
  *fileName = copystring(FileNameFromPath(buf));
  *fd = fopen(buf, "w");
}

/*
 * Given a TexChunk with a string value, scans through the string
 * converting Latex-isms into HTML-isms, such as 2 newlines -> <P>.
 *
 */
 
void ProcessText2HTML(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];

    // 2 newlines means \par
    if (!inVerbatim && chunk->value[i] == 10 && ((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, "<P>\n\n"); ptr += 5;
      i += 2;
      changed = TRUE;
    }
    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
    {
      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 ProcessText2HTML to convert Latex-isms to RTF-isms.
 * This should be called after Tex2Any has parsed the file,
 * and before TraverseDocument is called.
 *
 */
 
void Text2HTML(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();
        Text2HTML(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();
        Text2HTML(child_chunk);
        node = node->Next();
      }

      break;
    }
    case CHUNK_TYPE_STRING:
    {
      if (chunk->value)
        ProcessText2HTML(chunk);
      break;
    }
  }
}

// Called on start/end of macro examination
void HTMLOnMacro(char *name, int no_args, Bool start)
{
  if (strcmp(name, "chapter") == 0 || strcmp(name, "chapter*") == 0 || strcmp(name, "myheading") == 0)
  {
    if (start)
    {
      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }
      ReopenFile(&Chapters, &ChaptersName);

      SetCurrentOutput(NULL);
      startedSections = TRUE;
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());
      AddTexRef(topicName, ChaptersName, "chapter");

      SetCurrentOutput(Chapters);
      TexOutput("<title>");
      TraverseChildrenFromChunk(currentSection);
      TexOutput("</title>\n");

      SetCurrentOutputs(Contents, Chapters);
      fprintf(Contents, "\n<LI><A HREF=\"%s#%s\">\n", ChaptersName, topicName);

      fprintf(Chapters, "<A NAME=\"%s\">\n<H2>", topicName);
      TraverseChildrenFromChunk(currentSection);
      fprintf(Contents, "\n</A>\n");
      fprintf(Chapters, "</H2>\n</A>\n");

      SetCurrentOutput(Chapters);
    }
  }
  else if (strcmp(name, "section") == 0 || strcmp(name, "section*") == 0 ||
           strcmp(name, "gloss") == 0 || strcmp(name, "problem") == 0)
  {
    if (start)
    {
      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }
      ReopenFile(&Sections, &SectionsName);
      SetCurrentOutput(NULL);
      startedSections = TRUE;
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());
      AddTexRef(topicName, SectionsName, "section");

      SetCurrentOutput(Sections);
      TexOutput("<title>");
      TraverseChildrenFromChunk(currentSection);
      TexOutput("</title>\n");

      FILE *jumpFrom = ((DocumentStyle == LATEX_ARTICLE) ? Contents : Chapters);

      SetCurrentOutputs(jumpFrom, Sections);
      if (DocumentStyle == LATEX_ARTICLE)
        fprintf(jumpFrom, "\n<LI><A HREF=\"%s#%s\">\n", SectionsName, topicName);
      else
        fprintf(jumpFrom, "\n<A HREF=\"%s#%s\">\n<B>", SectionsName, topicName);

      fprintf(Sections, "<A NAME=\"%s\">\n<H2>", topicName);
      TraverseChildrenFromChunk(currentSection);

      if (DocumentStyle == LATEX_ARTICLE)
        fprintf(jumpFrom, "\n</A>\n");
      else
        fprintf(jumpFrom, "</B>\n</A><P>\n");
      fprintf(Sections, "</H2>\n</A>\n");

      SetCurrentOutput(Sections);
    }
  }
  else if (strcmp(name, "references") == 0)
  {
    char *jumpToName;
    FILE *jumpTo;
    if (DocumentStyle == LATEX_ARTICLE)
    {
      jumpToName = SectionsName;
      jumpTo = Sections;
    }
    else
    {
      jumpToName = ChaptersName;
      jumpTo = Chapters;
    }
    if (start)
    {
      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }
      ReopenFile(&jumpTo, &jumpToName);

      startedSections = TRUE;

      SetCurrentOutput(jumpTo);
      TexOutput("<title>References</title>\n");

      char *topicName = "references";
      SetCurrentOutputs(Contents, jumpTo);
      fprintf(Contents, "\n<LI><A HREF=\"%s#%s\">\n", jumpToName, topicName);

      fprintf(jumpTo, "<A NAME=\"%s\">\n<H2>", topicName);
      TexOutput("References");
      fprintf(Contents, "\n</A>\n");
      fprintf(jumpTo, "</H2>\n</A>\n");

      SetCurrentOutput(jumpTo);
      TexOutput("<DL>\n");
    }
  }
  else if (strcmp(name, "subsection") == 0 || strcmp(name, "subsection*") == 0 ||
           strcmp(name, "membersection") == 0 || strcmp(name, "functionsection") == 0)
  {
    if (start)
    {
      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }
      ReopenFile(&Subsections, &SubsectionsName);

      SetCurrentOutput(NULL);
      startedSections = TRUE;
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());
      AddTexRef(topicName, SubsectionsName, "subsection");

      SetCurrentOutput(Subsections);
      TexOutput("<title>");
      TraverseChildrenFromChunk(currentSection);
      TexOutput("</title>\n");

      SetCurrentOutputs(Sections, Subsections);
      fprintf(Sections, "\n<A HREF=\"%s#%s\">\n<B>", SubsectionsName, topicName);
      fprintf(Subsections, "<A NAME=\"%s\">\n<H2>", topicName);
      TraverseChildrenFromChunk(currentSection);
      fprintf(Sections, "</B>\n</A><P>\n");
      fprintf(Subsections, "</H2>\n</A>\n");

      SetCurrentOutput(Subsections);
    }
  }
  else if (strcmp(name, "subsubsection") == 0)
  {
    if (start)
    {
      if (CurrentLabel)
      {
        delete[] CurrentLabel;
        CurrentLabel = NULL;
      }
      ReopenFile(&Subsubsections, &SubsubsectionsName);
      SetCurrentOutput(NULL);
      startedSections = TRUE;
    }
    else
    {
      char *topicName = FindTopicName(GetNextChunk());
      AddTexRef(topicName, SubsubsectionsName, "subsubsection");

      SetCurrentOutput(Subsubsections);
      TexOutput("<title>");
      TraverseChildrenFromChunk(currentSection);
      TexOutput("</title>\n");

      SetCurrentOutputs(Subsections, Subsubsections);
      fprintf(Subsections, "\n<A HREF=\"%s#%s\">\n<B>", SubsubsectionsName, topicName);
      fprintf(Subsubsections, "<A NAME=\"%s\">\n<H3>", topicName);
      TraverseChildrenFromChunk(currentSection);
      fprintf(Subsections, "</B>\n</A><P>\n");
      fprintf(Subsubsections, "</H3>\n</A>\n");

      SetCurrentOutput(Subsubsections);
    }
  }
  else if ((strcmp(name, "func") == 0) || (strcmp(name, "pfunc") == 0))
  {
    SetCurrentOutput(Subsections);
    if (start)
    {
    }
    else
    {
    }
  }
  else if (strcmp(name, "clipsfunc") == 0)
  {
    SetCurrentOutput(Subsections);
    if (start)
    {
    }
    else
    {
    }
  }
  else if (strcmp(name, "member") == 0)
  {
    SetCurrentOutput(Subsections);
    if (start)
    {
    }
    else
    {
    }
  }
  else if ((strcmp(name, "void") == 0) && start)
    TexOutput("<B>void</B>");
  else if ((strcmp(name, "hardy") == 0) && start)
    TexOutput("HARDY");
  else if ((strcmp(name, "wxclips") == 0) && start)
    TexOutput("wxCLIPS");
  else if ((strcmp(name, "&") == 0) && start)
    TexOutput("&amp");
  else if ((strcmp(name, "\\") == 0) && start)
    TexOutput("\n");
  else if ((strcmp(name, "rtfsp") == 0) && start) // Explicit space, RTF only
    {}
  else if ((strcmp(name, "itemize") == 0) ||
           (strcmp(name, "enumerate") == 0) ||
           (strcmp(name, "description") == 0))
  {
    if (start)
    {
      indentLevel ++;

      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));
      switch (listType)
      {
        case LATEX_ITEMIZE:
          TexOutput("<UL>\n");
          break;
        case LATEX_ENUMERATE:
          TexOutput("<OL>\n");
          break;
        case LATEX_DESCRIPTION:
          TexOutput("<DL>\n");
          break;
      }
    }
    else
    {
      indentLevel --;
      if (itemizeStack.First())
      {
        ItemizeStruc *struc = (ItemizeStruc *)itemizeStack.First()->Data();
        switch (struc->listType)
        {
          case LATEX_ITEMIZE:
            TexOutput("</UL>\n");
            break;
          case LATEX_ENUMERATE:
            TexOutput("</OL>\n");
            break;
          case LATEX_DESCRIPTION:
            TexOutput("</DL>\n");
            break;
        }

        delete struc;
        delete itemizeStack.First();
      }
    }
  }
  else if (strcmp(name, "par") == 0)
  {
    if (start)
      TexOutput("<P>\n");
  }
  else if (strcmp(name, "verbatim") == 0)
  {
    if (start)
    {
      char buf[100];
      sprintf(buf, "<PRE>\n");
      TexOutput(buf);
    }
    else TexOutput("</PRE>\n");
  }
  else if (strcmp(name, "centerline") == 0 || strcmp(name, "center") == 0)
  {
/*
    if (start)
    {
      TexOutput("{\\qc ");
    }
    else TexOutput("}\\par\\pard\n");
*/
  }
  else if (strcmp(name, "flushleft") == 0)
  {
/*
    if (start)
    {
      TexOutput("{\\ql ");
    }
    else TexOutput("}\\par\\pard\n");
*/
  }
  else if (strcmp(name, "flushright") == 0)
  {
/*
    if (start)
    {
      TexOutput("{\\qr ");
    }
    else TexOutput("}\\par\\pard\n");
*/
  }
  else if (strcmp(name, "small") == 0)
  {
/*
    if (start)
    {
      TexOutput("{\\fs16\n");
    }
    else TexOutput("}\n");
*/
  }
  else if (strcmp(name, "tiny") == 0)
  {
/*
    if (start)
    {
      TexOutput("{\\fs12\n");
    }
    else TexOutput("}\n");
*/
  }
  else if (strcmp(name, "normalsize") == 0)
  {
/*
    if (start)
    {
      TexOutput("{\\fs20\n");
    }
    else TexOutput("}\n");
*/
  }
  else if (strcmp(name, "large") == 0)
  {
/*
    if (start)
    {
      TexOutput("{\\fs24\n");
    }
    else TexOutput("}\n");
*/
  }
  else if (strcmp(name, "LARGE") == 0)
  {
    if (start)
    {
      TexOutput("<H1>");
    }
    else TexOutput("</H1>");
  }
  else if (strcmp(name, "Large") == 0)
  {
    if (start)
    {
      TexOutput("<H1>");
    }
    else TexOutput("</H1>");
  }
  else if (strcmp(name, "bf") == 0)
  {
    if (start)
    {
      TexOutput("<B>");
    }
    else TexOutput("</B>");
  }
  else if (strcmp(name, "it") == 0)
  {
    if (start)
    {
      TexOutput("<I>");
    }
    else TexOutput("</I>");
  }
  else if (strcmp(name, "tt") == 0)
  {
    if (start)
    {
      TexOutput("<TT>");
    }
    else TexOutput("</TT>");
  }
  else if (strcmp(name, "sc") == 0)
  {
  }
  else if (strcmp(name, "item") == 0)
  {
    if (start)
    {
      wxNode *node = itemizeStack.First();
      if (node)
      {
        ItemizeStruc *struc = (ItemizeStruc *)node->Data();
        struc->currentItem += 1;
//        if (struc->currentItem > 1)
//          TexOutput("<P>\n");
        if (struc->listType == LATEX_DESCRIPTION)
        {
          if (descriptionItemArg)
          {
            TexOutput("<DT>");
            TraverseChildrenFromChunk(descriptionItemArg);
            TexOutput("\n");
            descriptionItemArg = NULL;
          }
          TexOutput("<DD>");
        }
        else
          TexOutput("<LI>");
      }
    }
  }
  else if (strcmp(name, "maketitle") == 0)
  {
    if (start && DocumentTitle && DocumentAuthor)
    {
      TexOutput("<H1>");
      TraverseChildrenFromChunk(DocumentTitle);
      TexOutput("</H1><P>\n\n");
      TexOutput("<H3>");
      TraverseChildrenFromChunk(DocumentAuthor);
      TexOutput("</H3><P>\n\n");
      if (DocumentDate)
      {
        TexOutput("<H3>");
        TraverseChildrenFromChunk(DocumentDate);
        TexOutput("</H3><P>\n\n");
      }
    }
  }
  else if (strcmp(name, "helpref") == 0 || strcmp(name, "helprefn") == 0)
  {
    if (start)
    {
      helpRefFilename = NULL;
      helpRefText = NULL;
    }
  }
  else if (strcmp(name, "bibliography") == 0)
  {
    if (start)
    {
      DefaultOnMacro(name, no_args, start);
    }
    else
    {
      DefaultOnMacro(name, no_args, start);
      TexOutput("</DL>\n");
    }
  }
  else if (strcmp(name, "hrule") == 0)
  {
    if (start)
    {
      TexOutput("<P>------------------------------------------------------------------<P>\n");
    }
  }
  else if (strcmp(name, "tableofcontents") == 0)
  {
    if (start)
    {
      FILE *fd = fopen(ContentsName, "r");
      if (fd)
      {
        char ch = getc(fd);
        while (ch != EOF)
        {
          putc(ch, Titlepage);
          ch = getc(fd);
        }
        fclose(fd);
      }
      else
      {
        TexOutput("RUN TEX2RTF AGAIN FOR CONTENTS PAGE\n");
        OnInform("Run Tex2RTF again to include contents page.");
      }
    }
  }
  else DefaultOnMacro(name, no_args, start);
}

// Called on start/end of argument examination
Bool HTMLOnArgument(char *macro_name, int arg_no, Bool start)
{
  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("<B>");

    if (!start && (arg_no == 1))
      TexOutput("</B> ");

    if (start && (arg_no == 2))
    {
      if (!suppressNameDecoration) TexOutput("<B>");
      currentMember = GetArgChunk();
    }
    if (!start && (arg_no == 2))
    {
      if (!suppressNameDecoration) TexOutput("</B>");
    }
    
    if (start && (arg_no == 3))
      TexOutput("(");
    if (!start && (arg_no == 3))
     TexOutput(")");
  }
  else if (strcmp(macro_name, "clipsfunc") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("<B>");
    if (!start && (arg_no == 1))
      TexOutput("</B> ");

    if (start && (arg_no == 2))
    {
      if (!suppressNameDecoration) TexOutput("( ");
      currentMember = GetArgChunk();
    }
    if (!start && (arg_no == 2))
    {
    }

    if (!start && (arg_no == 3))
     TexOutput(")");
  }
  else if (strcmp(macro_name, "pfunc") == 0)
  {
    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(")");
  }
  else if (strcmp(macro_name, "param") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("<B>");
    if (!start && (arg_no == 1))
      TexOutput("</B>");
    if (start && (arg_no == 2))
    {
      TexOutput("<I>");
    }
    if (!start && (arg_no == 2))
    {
      TexOutput("</I>");
    }
  }
  else if (strcmp(macro_name, "cparam") == 0)
  {
    if (start && (arg_no == 1))
      TexOutput("<B>");
    if (!start && (arg_no == 1))
      TexOutput("</B> ");  // This is the difference from param - one space!
    if (start && (arg_no == 2))
    {
      TexOutput("<I>");
    }
    if (!start && (arg_no == 2))
    {
      TexOutput("</I>");
    }
  }
  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 (IsArgOptional())
    {
      if (start)
        helpRefFilename = GetArgChunk();
      return FALSE;
    }
    else if ((GetNoArgs() - arg_no) == 1)
    {
      if (start)
        helpRefText = GetArgChunk();
      return FALSE;
    }
    else if ((GetNoArgs() - arg_no) == 0) // Arg = 2, or 3 if first is optional
    {
      if (start)
      {
        char *refName = GetArgData();
        char *refFilename = NULL;

        if (refName)
        {
          wxNode *node = TexReferences.Find(refName);
          if (node)
          {
            TexRef *texRef = (TexRef *)node->Data();
            if (texRef->refFile && strcmp(texRef->refFile, "??") != 0)
              refFilename = texRef->refFile;

            TexOutput("<A HREF=\"");
            // If a filename is supplied, use it, otherwise try to
            // use the filename associated with the reference (from this document).
            if (helpRefFilename)
	    {
              TraverseChildrenFromChunk(helpRefFilename);
              TexOutput("#");
	    }
            else if (refFilename)
	    {
              TexOutput(refFilename);
              TexOutput("#");
	    }
            TexOutput(refName);
            TexOutput("\">");
            if (helpRefText)
              TraverseChildrenFromChunk(helpRefText);
            TexOutput("</A>");
          }
        }
        else TexOutput("??");
      }
      return FALSE;
    }
  }
  else if (strcmp(macro_name, "psboxto") == 0 || strcmp(macro_name, "image") == 0)
  {
    if (arg_no == 2)
    {
      if (start)
        TexOutput("<A HREF=\"");
      else
        TexOutput("\">Picture<P>\n");
    }
    else return FALSE;
  }
  else if (strcmp(macro_name, "item") == 0)
  {
    if (start && IsArgOptional())
    {
      descriptionItemArg = GetArgChunk();
      return FALSE;
    }
  }
  else if (strcmp(macro_name, "bibitem") == 0)
  {
    if (arg_no == 1 && start)
      TexOutput("\n<DT>");
    if (arg_no == 2 && start)
      TexOutput("\n<DD>");
    if (arg_no == 2 && !start)
      TexOutput("<P>\n");
  }
  else return DefaultOnArgument(macro_name, arg_no, start);
  return TRUE;
}


Bool HTMLGo(void)
{
  fileId = 0;
  inVerbatim = FALSE;
  indentLevel = 0;

  if (InputFile && OutputFile)
  {
    // Do some HTML-specific transformations on all the strings,
    // recursively
    Text2HTML(GetTopLevelChunk());

    char buf[300];
    sprintf(buf, "%s_contents.html", FileRoot);
    Titlepage = fopen(buf, "w");

    Contents = fopen(TmpContentsName, "w");
    if (!Titlepage || !Contents)
    {
      OnError("Cannot open output file!");
      return FALSE;
    }

    fprintf(Contents, "<P><P><H1>Contents</H1><P><P>\n");

    fprintf(Contents, "<UL>\n");

    SetCurrentOutput(Titlepage);
    OnInform("Converting...");

    TraverseDocument();

    if (DocumentTitle)
    {
      SetCurrentOutput(Titlepage);
      TexOutput("\n<TITLE>");
      TraverseChildrenFromChunk(DocumentTitle);
      TexOutput("</TITLE>\n");
    }
    else
    {
      if (contentsString)
        fprintf(Titlepage, "<TITLE>%s</TITLE>\n\n", contentsString);
      else
        fprintf(Titlepage, "<TITLE>%s</TITLE>\n\n", FileNameFromPath(FileRoot));
    }

    fprintf(Contents, "</UL>\n\n");
    if (Titlepage)
      fclose(Titlepage);
    if (Contents)
      fclose(Contents);
    if (Chapters)
      fclose(Chapters);
    if (Sections)
      fclose(Sections);
    if (Subsections)
      fclose(Subsections);
    if (Subsubsections)
      fclose(Subsubsections);

    if (FileExists(ContentsName)) wxRemoveFile(ContentsName);
    wxRenameFile(TmpContentsName, ContentsName);

    return TRUE;
  }
  return FALSE;
}

