]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/tex2rtf/src/htmlutil.cpp
corrections to dynamic loading for Darwin
[wxWidgets.git] / utils / tex2rtf / src / htmlutil.cpp
index a67bc10be43078086408862a8d567c1c6d992555..2ba127957600876c576f980b3ae44ecfd9e961af 100644 (file)
 #include "tex2rtf.h"
 #include "table.h"
 
+
+extern wxHashTable TexReferences;
+
+
 extern void DecToHex(int, char *);
 void GenerateHTMLIndexFile(char *fname);
+
+void GenerateHTMLWorkshopFiles(char *fname);
+void HTMLWorkshopAddToContents(int level, char *s, char *file);
+void HTMLWorkshopStartContents();
+void HTMLWorkshopEndContents();
+
 void OutputContentsFrame(void);
 
 #include "readshg.h" // Segmented hypergraphics parsing
@@ -70,6 +80,11 @@ static bool inTable = FALSE;
 // This is defined in the Tex2Any library.
 extern char *BigBuffer;
 
+// DHS Two-column table dimensions.
+static int TwoColWidthA = -1;
+static int TwoColWidthB = -1;
+
+
 class HyperReference: public wxObject
 {
  public:
@@ -125,7 +140,7 @@ void SetCurrentChapterName(char *s, char *file)
   CurrentChapterFile = copystring(file);
 
   currentFileName = CurrentChapterFile;
-  
+
   SetCurrentTopic(s);
 }
 void SetCurrentSectionName(char *s, char *file)
@@ -166,7 +181,7 @@ void ReopenFile(FILE **fd, char **fileName)
 {
   if (*fd)
   {
-    fprintf(*fd, "\n</BODY></HTML>\n");
+    fprintf(*fd, "\n</FONT></BODY></HTML>\n");
     fclose(*fd);
   }
   fileId ++;
@@ -219,7 +234,7 @@ void ReopenSectionContentsFile(void)
  * converting Latex-isms into HTML-isms, such as 2 newlines -> <P>.
  *
  */
+
 void ProcessText2HTML(TexChunk *chunk)
 {
   bool changed = FALSE;
@@ -291,7 +306,7 @@ void ProcessText2HTML(TexChunk *chunk)
  * and before TraverseDocument is called.
  *
  */
+
 void Text2HTML(TexChunk *chunk)
 {
   Tex2RTFYield();
@@ -368,7 +383,7 @@ void AddBrowseButtons(char *upLabel, char *upFilename,
     contentsReference = contentsReferenceBuf;
     sprintf(contentsReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Contents\">", ConvertCase("contents.gif"));
   }
-  
+
   char *upReference = NULL;
   if (htmlBrowseButtons == HTML_BUTTONS_TEXT)
     upReference = UpNameString;
@@ -378,7 +393,7 @@ void AddBrowseButtons(char *upLabel, char *upFilename,
     upReference = upReferenceBuf;
     sprintf(upReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Up\">", ConvertCase("up.gif"));
   }
-  
+
   char *backReference = NULL;
   if (htmlBrowseButtons == HTML_BUTTONS_TEXT)
     backReference = "&lt;&lt;";
@@ -388,7 +403,7 @@ void AddBrowseButtons(char *upLabel, char *upFilename,
     backReference = backReferenceBuf;
     sprintf(backReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Previous\">", ConvertCase("back.gif"));
   }
-  
+
   char *forwardReference = NULL;
   if (htmlBrowseButtons == HTML_BUTTONS_TEXT)
     forwardReference = "&gt;&gt;";
@@ -398,9 +413,9 @@ void AddBrowseButtons(char *upLabel, char *upFilename,
     forwardReference = forwardReferenceBuf;
     sprintf(forwardReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Next\">", ConvertCase("forward.gif"));
   }
-  
+
   TexOutput("<CENTER>");
-  
+
   char buf[200];
 
   /*
@@ -550,9 +565,9 @@ char *ParseColourString(char *bkStr, bool *isPicture)
         int red = atoi(tok1);
         int green = atoi(tok2);
         int blue = atoi(tok3);
-        
+
         strcpy(resStr, "#");
-        
+
         char buf[3];
         DecToHex(red, buf);
         strcat(resStr, buf);
@@ -568,6 +583,17 @@ char *ParseColourString(char *bkStr, bool *isPicture)
   else return NULL;
 }
 
+void OutputFont(void)
+{
+  // Output <FONT FACE=...>
+  TexOutput("<FONT FACE=\"");
+  if (htmlFaceName)
+       TexOutput(htmlFaceName);
+  else
+       TexOutput("Times New Roman");
+  TexOutput("\">\n");
+}
+
 // Output start of <BODY> block
 void OutputBodyStart(void)
 {
@@ -590,7 +616,7 @@ void OutputBodyStart(void)
       TexOutput(" BGCOLOR="); TexOutput(s);
     }
   }
-    
+
   // Set foreground text colour, if one is specified
   if (textColourString)
   {
@@ -622,6 +648,8 @@ void OutputBodyStart(void)
     }
   }
   TexOutput(">\n");
+
+  OutputFont();
 }
 
 // Called on start/end of macro examination
@@ -650,6 +678,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
       AddTexRef(topicName, ChaptersName, ChapterNameString);
 
       SetCurrentChapterName(topicName, ChaptersName);
+      if (htmlWorkshopFiles) HTMLWorkshopAddToContents(0, topicName, ChaptersName);
 
       SetCurrentOutput(Chapters);
 
@@ -665,7 +694,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
         sprintf(titleBuf, "%s_contents.html", FileNameFromPath(FileRoot));
 
       fprintf(Chapters, "<A NAME=\"%s\"></A>", topicName);
-      
+
       AddBrowseButtons("", titleBuf, // Up
                        lastTopic, lastFileName,  // Last topic
                        topicName, ChaptersName); // This topic
@@ -710,7 +739,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
 
       if (macroId != ltSECTIONSTAR)
         sectionNo ++;
-        
+
       SetCurrentOutput(NULL);
       startedSections = TRUE;
 
@@ -719,6 +748,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
       AddTexRef(topicName, SectionsName, SectionNameString);
 
       SetCurrentSectionName(topicName, SectionsName);
+      if (htmlWorkshopFiles) HTMLWorkshopAddToContents(1, topicName, SectionsName);
 
       SetCurrentOutput(Sections);
       TexOutput("<head><title>");
@@ -811,6 +841,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
             ReopenFile(&Subsections, &SubsectionsName);
             AddTexRef(topicName, SubsectionsName, SubsectionNameString);
             SetCurrentSubsectionName(topicName, SubsectionsName);
+            if (htmlWorkshopFiles) HTMLWorkshopAddToContents(2, topicName, SubsectionsName);
             SetCurrentOutput(Subsections);
 
             TexOutput("<head><title>");
@@ -837,6 +868,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
           {
             AddTexRef(topicName, SectionsName, SubsectionNameString);
             SetCurrentSubsectionName(topicName, SectionsName);
+
 //            if ( subsectionNo != 0 )
             fprintf(Sections, "\n<HR>\n");
 
@@ -851,6 +883,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
             OutputCurrentSection();
             TexOutput("</A><BR>\n");
 
+            if (htmlWorkshopFiles) HTMLWorkshopAddToContents(2, topicName, SectionsName);
             SetCurrentOutput(Sections);
           }
           // Add this section title to the list of keywords
@@ -888,6 +921,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
             ReopenFile(&Subsubsections, &SubsubsectionsName);
             AddTexRef(topicName, SubsubsectionsName, SubsubsectionNameString);
             SetCurrentSubsubsectionName(topicName, SubsubsectionsName);
+            if (htmlWorkshopFiles) HTMLWorkshopAddToContents(3, topicName, SubsubsectionsName);
 
             SetCurrentOutput(Subsubsections);
             TexOutput("<head><title>");
@@ -926,6 +960,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
             OutputCurrentSection();
             TexOutput("</A><BR>");
 */
+            if (htmlWorkshopFiles) HTMLWorkshopAddToContents(2, topicName, SectionsName);
             SetCurrentOutput(Sections);
         }
 
@@ -1005,8 +1040,9 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
       if (inTabular)
       {
         // End cell, start cell
-        TexOutput("</TD>");
-        
+
+        TexOutput("</FONT></TD>");
+
         // Start new row and cell, setting alignment for the first cell.
         if (currentColumn < noColumns)
           currentColumn ++;
@@ -1020,7 +1056,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
         {
           // Convert from points * 20 into pixels.
           int points = TableData[currentColumn].width / 20;
-        
+
           // Say the display is 100 DPI (dots/pixels per inch).
           // There are 72 pts to the inch. So 1pt = 1/72 inch, or 100 * 1/72 dots.
           int pixels = (int)(points * 100.0 / 72.0);
@@ -1029,6 +1065,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
         else
           sprintf(buf, "\n<TD ALIGN=LEFT>");
         TexOutput(buf);
+               OutputFont();
       }
       else
         TexOutput("&amp;");
@@ -1057,7 +1094,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
     if (start)
     {
       currentColumn = 0;
-      
+
       // Start new row and cell, setting alignment for the first cell.
       char buf[100];
       if (TableData[currentColumn].justification == 'c')
@@ -1068,7 +1105,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
       {
         // Convert from points * 20 into pixels.
         int points = TableData[currentColumn].width / 20;
-        
+
         // Say the display is 100 DPI (dots/pixels per inch).
         // There are 72 pts to the inch. So 1pt = 1/72 inch, or 100 * 1/72 dots.
         int pixels = (int)(points * 100.0 / 72.0);
@@ -1077,12 +1114,13 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
       else
         sprintf(buf, "<TR>\n<TD ALIGN=LEFT>");
       TexOutput(buf);
+         OutputFont();
     }
     else
     {
       // End cell and row
       // Start new row and cell
-      TexOutput("</TD>\n</TR>\n");
+      TexOutput("</FONT></TD>\n</TR>\n");
     }
     break;
   }
@@ -1176,8 +1214,12 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
   {
     if ( start )
         TexOutput("\n<TABLE>\n");
-    else
+    else {
         TexOutput("\n</TABLE>\n");
+    // DHS 
+        TwoColWidthA = -1;
+        TwoColWidthB = -1;
+    }
     break;
   }
   case ltPAR:
@@ -1466,7 +1508,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
       if (htmlFrameContents && FrameContents)
       {
         SetCurrentOutput(FrameContents);
-        
+
         // Add a special label for the contents page.
         TexOutput("<CENTER>\n");
         TexOutput("<H3>\n");
@@ -1486,7 +1528,7 @@ void HTMLOnMacro(int macroId, int no_args, bool start)
         }
         TexOutput("\n</CENTER>\n");
         TexOutput("<P><HR><P>\n");
-        
+
         SetCurrentOutput(Titlepage);
       }
 */
@@ -1688,7 +1730,7 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
     {
       if (!suppressNameDecoration) TexOutput("</B>");
     }
-    
+
     if (start && (arg_no == 3))
       TexOutput("(");
     if (!start && (arg_no == 3))
@@ -1780,7 +1822,7 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
     if (start)
     {
       char *sec = NULL;
-      
+
       char *refName = GetArgData();
       if (refName)
       {
@@ -1880,7 +1922,11 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
           {
             if (helpRefText)
               TraverseChildrenFromChunk(helpRefText);
-            TexOutput(" (REF NOT FOUND)");
+            if (!ignoreBadRefs)
+              TexOutput(" (REF NOT FOUND)");
+            wxString errBuf;
+            errBuf.Printf("Warning: unresolved reference '%s'", refName);
+            OnInform((char *)errBuf.c_str());
           }
         }
         else TexOutput("??");
@@ -1903,11 +1949,11 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
           alignment = " align=left";
         else if  (macroId == ltIMAGER)
           alignment = " align=right";
-        
+
         // Try to find an XBM or GIF image first.
         char *filename = copystring(GetArgData());
         char buf[500];
-        
+
         strcpy(buf, filename);
         StripExtension(buf);
         strcat(buf, ".xbm");
@@ -1920,6 +1966,23 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
           strcat(buf, ".gif");
           f = TexPathList.FindValidPath(buf);
         }
+
+        if (f == "") // Try for a JPEG instead
+        {
+          strcpy(buf, filename);
+          StripExtension(buf);
+          strcat(buf, ".jpg");
+          f = TexPathList.FindValidPath(buf);
+        }
+
+        if (f == "") // Try for a PNG instead
+        {
+          strcpy(buf, filename);
+          StripExtension(buf);
+          strcat(buf, ".png");
+          f = TexPathList.FindValidPath(buf);
+        }
+
         if (f != "")
         {
           char *inlineFilename = copystring(f);
@@ -1968,7 +2031,7 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
       // Try to find an XBM or GIF image first.
       char *filename = copystring(GetArgData());
       char buf[500];
-        
+
       strcpy(buf, filename);
       StripExtension(buf);
       strcat(buf, ".xbm");
@@ -1991,7 +2054,7 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
       if (imageFile)
         delete[] imageFile;
       imageFile = NULL;
-      if (f)
+      if (!f.IsEmpty())
       {
         imageFile = copystring(f);
       }
@@ -2047,6 +2110,7 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
       descriptionItemArg = GetArgChunk();
       return FALSE;
     }
+    return TRUE;
   }
   case ltTWOCOLITEM:
   case ltTWOCOLITEMRULED:
@@ -2059,17 +2123,31 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
 */
     if (arg_no == 1)
     {
-        if ( start )
-            TexOutput("\n<TR><TD VALIGN=TOP>\n");
-        else
-            TexOutput("\n</TD>\n");
+      if ( start ) {
+        // DHS
+       if (TwoColWidthA > -1) {
+          char buf[100];
+          sprintf(buf,"\n<TR><TD VALIGN=TOP WIDTH=%d>\n",TwoColWidthA);
+          TexOutput(buf);
+        } else
+          TexOutput("\n<TR><TD VALIGN=TOP>\n");
+               OutputFont();
+      }  else
+            TexOutput("\n</FONT></TD>\n");
     }
     if (arg_no == 2)
     {
-        if ( start )
-            TexOutput("\n<TD VALIGN=TOP>\n");
-        else
-            TexOutput("\n</TD></TR>\n");
+      // DHS
+      if ( start ) {
+       if (TwoColWidthB > -1) {
+          char buf[100];
+          sprintf(buf,"\n<TD VALIGN=TOP WIDTH=%d>\n",TwoColWidthB);
+          TexOutput(buf);
+        } else 
+           TexOutput("\n<TD VALIGN=TOP>\n");
+               OutputFont();
+      }  else
+           TexOutput("\n</FONT></TD></TR>\n");
     }
     return TRUE;
     break;
@@ -2123,6 +2201,30 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
       TexOutput("<HR><P>\n");
     break;
   }
+  // DHS
+  case ltTWOCOLWIDTHA:
+  {
+    if (start)
+    {
+      char *val = GetArgData();
+      float points = ParseUnitArgument(val);
+      TwoColWidthA = (int)((points * 100.0) / 72.0);
+    }
+    return FALSE;
+    break;
+  }
+  // DHS
+  case ltTWOCOLWIDTHB:
+  {
+    if (start)
+    {
+      char *val = GetArgData();
+      float points = ParseUnitArgument(val);
+      TwoColWidthB = (int)((points * 100.0) / 72.0);
+    }
+    return FALSE;
+    break;
+  }
   /*
    * Accents
    *
@@ -2522,7 +2624,7 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
       return FALSE;
     break;
   }
-*/  
+*/
   case ltTABULAR:
   case ltSUPERTABULAR:
   {
@@ -2547,6 +2649,7 @@ bool HTMLOnArgument(int macroId, int arg_no, bool start)
         if (compatibilityMode)
         {
           TexOutput("<TR>\n<TD>");
+                 OutputFont();
 /*
           for (int i = 0; i < noColumns; i++)
           {
@@ -2771,7 +2874,7 @@ bool HTMLGo(void)
     if (TitlepageName) delete[] TitlepageName;
     TitlepageName = copystring(buf);
     Titlepage = fopen(buf, "w");
-    
+
     if (truncateFilenames)
       sprintf(buf, "%s_fc.htm", FileRoot);
     else
@@ -2800,6 +2903,7 @@ bool HTMLGo(void)
     fprintf(Contents, "<UL>\n");
 
     SetCurrentOutput(Titlepage);
+    if (htmlWorkshopFiles) HTMLWorkshopStartContents();
     OnInform("Converting...");
 
     TraverseDocument();
@@ -2825,25 +2929,25 @@ bool HTMLGo(void)
 
     if (Chapters)
     {
-      fprintf(Chapters, "\n</BODY></HTML>\n");
+      fprintf(Chapters, "\n</FONT></BODY></HTML>\n");
       fclose(Chapters);
       Chapters = NULL;
     }
     if (Sections)
     {
-      fprintf(Sections, "\n</BODY></HTML>\n");
+      fprintf(Sections, "\n</FONT></BODY></HTML>\n");
       fclose(Sections);
       Sections = NULL;
     }
     if (Subsections && !combineSubSections)
     {
-      fprintf(Subsections, "\n</BODY></HTML>\n");
+      fprintf(Subsections, "\n</FONT></BODY></HTML>\n");
       fclose(Subsections);
       Subsections = NULL;
     }
     if (Subsubsections && !combineSubSections)
     {
-      fprintf(Subsubsections, "\n</BODY></HTML>\n");
+      fprintf(Subsubsections, "\n</FONT></BODY></HTML>\n");
       fclose(Subsubsections);
       Subsubsections = NULL;
     }
@@ -2876,7 +2980,7 @@ bool HTMLGo(void)
         else
           fprintf(tmpTitle, "<HEAD><TITLE>%s</TITLE></HEAD>\n\n", FileNameFromPath(FileRoot));
       }
-      
+
       // Output frame information
       if (htmlFrameContents)
       {
@@ -2891,13 +2995,13 @@ bool HTMLGo(void)
         fprintf(tmpTitle, "<FRAME SRC=\"%s\">\n", ConvertCase(FileNameFromPath(contentsFrameName)));
         fprintf(tmpTitle, "<FRAME SRC=\"%s\" NAME=\"mainwindow\">\n", ConvertCase(FileNameFromPath(firstFileName)));
         fprintf(tmpTitle, "</FRAMESET>\n");
-        
+
         fprintf(tmpTitle, "<NOFRAMES>\n");
       }
 
       // Output <BODY...> to temporary title page
       OutputBodyStart();
-      
+
       // Concat titlepage
       FILE *fd = fopen(TitlepageName, "r");
       if (fd)
@@ -2911,7 +3015,7 @@ bool HTMLGo(void)
         fclose(fd);
       }
 
-      fprintf(tmpTitle, "\n</BODY>\n");
+      fprintf(tmpTitle, "\n</FONT></BODY>\n");
 
       if (htmlFrameContents)
       {
@@ -2949,8 +3053,17 @@ bool HTMLGo(void)
       GenerateHTMLIndexFile(htmlIndexName);
     }
 
+    // Generate HTML Help Workshop files if requested
+    if (htmlWorkshopFiles)
+    {
+      HTMLWorkshopEndContents();
+      GenerateHTMLWorkshopFiles(FileRoot);
+    }
+
+
     return TRUE;
   }
+
   return FALSE;
 }
 
@@ -2980,3 +3093,171 @@ void GenerateHTMLIndexFile(char *fname)
   }
   fclose(fd);
 }
+
+
+
+
+
+
+
+// output .hpp, .hhc and .hhk files:
+
+
+void GenerateHTMLWorkshopFiles(char *fname)
+{
+  FILE *f;
+  char buf[300];
+
+  /* Generate project file : */
+
+  sprintf(buf, "%s.hhp", fname);
+  f = fopen(buf, "wt");
+  fprintf(f,
+      "[OPTIONS]\n"
+      "Compatibility=1.1\n"
+      "Full-text search=Yes\n"
+      "Contents file=%s.hhc\n"
+      "Compiled file=%s.chm\n"
+      "Default Window=%sHelp\n"
+      "Default topic=%s\n"
+      "Index file=%s.hhk\n"
+      "Title=",
+      FileNameFromPath(fname),
+      FileNameFromPath(fname),
+      FileNameFromPath(fname),
+      FileNameFromPath(TitlepageName),
+      FileNameFromPath(fname)
+      );
+
+  if (DocumentTitle) {
+    SetCurrentOutput(f);
+    TraverseChildrenFromChunk(DocumentTitle);
+  }
+  else fprintf(f, "(unknown)");
+
+  fprintf(f, "\n\n[WINDOWS]\n"
+          "%sHelp=,\"%s.hhc\",\"%s.hhk\",\"%s\",,,,,,0x2420,,0x380e,,,,,0,,,",
+          FileNameFromPath(fname),
+          FileNameFromPath(fname),
+          FileNameFromPath(fname),
+          FileNameFromPath(TitlepageName));
+
+
+  fprintf(f, "\n\n[FILES]\n");
+  fprintf(f, "%s\n", FileNameFromPath(TitlepageName));
+  for (int i = 1; i <= fileId; i++) {
+    if (truncateFilenames)
+      sprintf(buf, "%s%d.htm", FileNameFromPath(FileRoot), i);
+    else
+      sprintf(buf, "%s%d.html", FileNameFromPath(FileRoot), i);
+    fprintf(f, "%s\n", buf);
+  }
+  fclose(f);
+
+  /* Generate index file : */
+
+  sprintf(buf, "%s.hhk", fname);
+  f = fopen(buf, "wt");
+
+  fprintf(f,
+      "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
+      "<HTML>\n"
+      "<HEAD>\n"
+      "<meta name=\"GENERATOR\" content=\"tex2rtf\">\n"
+      "<!-- Sitemap 1.0 -->\n"
+      "</HEAD><BODY>\n"
+      "<OBJECT type=\"text/site properties\">\n"
+      " <param name=\"ImageType\" value=\"Folder\">\n"
+      "</OBJECT>\n"
+      "<UL>\n");
+
+  TopicTable.BeginFind();
+  wxNode *node = NULL;
+  while ((node = TopicTable.Next()))
+  {
+    TexTopic *texTopic = (TexTopic *)node->Data();
+    const char *topicName = node->GetKeyString();
+    if (texTopic->filename && texTopic->keywords)
+    {
+      wxNode *node1 = texTopic->keywords->First();
+      while (node1)
+      {
+        char *s = (char *)node1->Data();
+        fprintf(f,
+            " <LI> <OBJECT type=\"text/sitemap\">\n"
+            "  <param name=\"Local\" value=\"%s#%s\">\n"
+            "  <param name=\"Name\" value=\"%s\">\n"
+            "  </OBJECT>\n",
+           texTopic->filename, topicName, s);
+        node1 = node1->Next();
+      }
+    }
+  }
+
+  fprintf(f, "</UL>\n");
+  fclose(f);
+}
+
+
+
+static FILE *HTMLWorkshopContents = NULL;
+static int HTMLWorkshopLastLevel = 0;
+
+void HTMLWorkshopAddToContents(int level, char *s, char *file)
+{
+  int i;
+
+  if (level > HTMLWorkshopLastLevel)
+    for (i = HTMLWorkshopLastLevel; i < level; i++)
+      fprintf(HTMLWorkshopContents, "<UL>");
+  if (level < HTMLWorkshopLastLevel)
+    for (i = level; i < HTMLWorkshopLastLevel; i++)
+      fprintf(HTMLWorkshopContents, "</UL>");
+
+  SetCurrentOutput(HTMLWorkshopContents);
+  fprintf(HTMLWorkshopContents,
+            " <LI> <OBJECT type=\"text/sitemap\">\n"
+            "  <param name=\"Local\" value=\"%s#%s\">\n"
+            "  <param name=\"Name\" value=\"",
+           file, s);
+  OutputCurrentSection();
+  fprintf(HTMLWorkshopContents,
+           "\">\n"
+            "  </OBJECT>\n");
+  HTMLWorkshopLastLevel = level;
+}
+
+
+void HTMLWorkshopStartContents()
+{
+  char buf[300];
+  sprintf(buf, "%s.hhc", FileRoot);
+  HTMLWorkshopContents = fopen(buf, "wt");
+  HTMLWorkshopLastLevel = 0;
+
+  fprintf(HTMLWorkshopContents,
+      "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
+      "<HTML>\n"
+      "<HEAD>\n"
+      "<meta name=\"GENERATOR\" content=\"tex2rtf\">\n"
+      "<!-- Sitemap 1.0 -->\n"
+      "</HEAD><BODY>\n"
+      "<OBJECT type=\"text/site properties\">\n"
+      " <param name=\"ImageType\" value=\"Folder\">\n"
+      "</OBJECT>\n"
+      "<UL>\n"
+      "<LI> <OBJECT type=\"text/sitemap\">\n"
+      "<param name=\"Local\" value=\"%s\">\n"
+      "<param name=\"Name\" value=\"Contents\">\n</OBJECT>\n",
+      FileNameFromPath(TitlepageName)
+      );
+
+}
+
+
+void HTMLWorkshopEndContents()
+{
+  for (int i = HTMLWorkshopLastLevel; i >= 0; i--)
+    fprintf(HTMLWorkshopContents, "</UL>\n");
+  fclose(HTMLWorkshopContents);
+}