diff help2html/mhh6.syn @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help2html/mhh6.syn	Sat Dec 22 17:52:45 2007 -0500
@@ -0,0 +1,1060 @@
+/*
+ * October 30, 2007. mhh6: use C, not C++.
+ *
+ * Sept 5, 2006. mhh5.syn modified for XML_OUTPUT option.
+ *
+ * June 20, 2001. mhh5.syn
+ *   Modifying mhh4 to create HTML output
+ *   (mhh4 sorts a help.src file case-insensitively by title line while 
+ *   cleaning it up a bit.)
+ *
+ * June 16 2001 
+ *   Unlike mhh3b, mhh4 stores and sorts title *lines*, not titles, 
+ *   from help.src. Another AgStringDirectory has been added to hold
+ *   topic bodies.
+ *
+ * Change mhh3b.syn to store title lines in string dicts.
+ * Change mhh3a.syn to use AgStringDictionary for titles.
+ * Jun 8/01 Change mhh3.syn to add main and some reduc. procedures
+ *
+ * June 8, 2001 - mhh3.syn now parses Jerry's current help.src (b8)
+ * with no conflicts or keyword anomalies but spaces (and tabs) are
+ * not allowed in blank lines. Why the eof line tolerates spaces is
+ * something of a mystery.
+ */
+
+// -- CONFIGURATION SECTION ----------------------------
+[
+  pointer input
+  no cr           // no carr. ret. in output parser
+  parser file name = "#.c"
+  line numbers
+]
+//------------------------------------------------------
+
+
+eof = 0
+char = ~eof
+lead title char = char - blank - tab - ',' - bullet - '\n' - '\r'
+title char = char - ',' - bullet - '\n' - '\r'
+lead topic char = char - blank - tab - bullet - '\n' - '\r'
+text char = char - bullet - '\n' - '\r'
+table char = char  - tab - '\n' - '\r'
+
+blank = 0x20
+tab = 9
+bullet = 7
+
+//blank line
+//      -> blank?..., '\n'
+blank line
+      -> '\n'   /* Don't allow spaces in line */
+      -> '\r','\n'
+
+eof line
+      -> blank?..., eof
+
+eol
+      -> '\n'
+      -> '\r','\n'
+
+(void) help sourcefile $                 // ** Grammar token **
+      -> topic..., blank line?, eof line
+
+
+topic
+      -> blank line?..., title line, eol, blank line?..., topic lines, 
+	 end topic
+
+title line
+      -> title line too              = {
+		title_line_count++; 
+                //  buffer_append(&titleLine, "</h3>\n<p>"); 
+                saveTitleLine();
+         }
+
+title line too
+      -> title                                 = title_count++, putTitle();
+      -> title line too, ',', blank?..., title = title_count++, appendTitle();
+
+title
+      -> lead title char:c   = 
+		buffer_start(&title, c), buffer_start(&title1, toupper(c));
+      -> title, title char:c = 
+		buffer_add(&title, c), buffer_add(&title1, toupper(c));
+
+end topic
+      -> "##", blank?..., eol
+      -> "\n##", blank?..., eol   
+      -> "\r\n##", blank?..., eol   
+
+topic lines
+      -> topic lines too                               = { saveTopicBody(); }
+
+topic lines too
+      -> text parag                           =buffer_append(&topicBody,"\n"); 
+      -> topic lines too, blank line..., parag=buffer_append(&topicBody,"\n"); 
+
+parag
+      -> text parag
+      -> table parag
+      -> list1 parag           = finishList(Tlist1);
+      -> list2 parag           = finishList(Tlist2);
+      -> listtab parag         = finishList(Tlisttab);
+      -> code parag
+
+
+text parag
+      -> partial text parag
+      -> partial text parag, table parag
+      -> text block, list1 parag                = finishList(Tlist1);
+      -> text block, listtab parag              = finishList(Tlisttab);
+      -> text block, code parag
+      -> text block, code parag, text block
+
+
+partial text parag
+      -> text block
+      -> partial text parag, table parag, text block
+
+
+
+text block
+      -> !buffer_append(&topicBody, "<p>");, 
+	 first text line, other text line?... = 
+		buffer_append(&topicBody, "</p>");
+
+
+table parag
+      -> table parag too         = buffer_append(&topicBody, "\n</table>\n\n");
+
+table parag too
+      -> first table line
+      -> table parag too,  other table line
+
+
+list1 parag
+      -> list1 block, list1 block?...
+
+list1 block
+      -> first list1 line, other list1 line?... =
+		buffer_append(&topicBody, "</li>\n");
+      -> first list1 line, other list1 line?..., table parag =
+		buffer_append(&topicBody, "</li>\n");
+      -> first list1 line, other list1 line?..., code parag =
+		buffer_append(&topicBody, "</li>\n");
+
+
+list2 parag
+      -> first list2 line, other list2 line?... =
+		buffer_append(&topicBody, "</li>\n");
+ 
+listtab parag
+      -> listtab block, listtab block?...
+
+listtab block
+      -> first listtab line, other listtab line?... =
+		buffer_append(&topicBody, "</li>\n");
+      -> first listtab line, other listtab line?..., table parag =
+		buffer_append(&topicBody, "</li>\n");
+
+code parag
+      -> code parag too                         = 
+		buffer_append(&topicBody, "\n</pre>");
+
+code parag too
+      -> first code line
+      -> code parag too,  other code line
+
+
+first text line
+      -> lead topic char:c, text frag?, eol         = {
+		total1sttextline++;
+		appendEnd(c);
+	 } 
+      -> blank, lead topic char:c, text frag?,eol   = {
+		total1sttextlineb++;
+                buffer_add(&topicBody, 0x20);
+		appendEnd(c);
+	 }
+other text line
+      -> lead topic char:c, text frag?, eol              = appendEnd(c);
+
+
+//################# OLD ####################################################
+//first table line
+//      -> tab seq, blank seq?, lead topic char:c, text frag?, '\n'  = {
+//		total1sttableline++;
+//              buffer_append(&topicBody, "\n<pre>  ");
+//              appendEnd(c);
+//		buffer_clear(&tabFrag);
+//		buffer_clear(&blankFrag);
+//	 }
+//
+//other table line
+//      -> tab seq, blank seq?, lead topic char:c, text frag?, '\n'  = {
+//		buffer_append(&topicBody, "  ");
+//		appendEnd(c);
+//		buffer_clear(&tabFrag);
+//		buffer_clear(&blankFrag);
+//	 }
+//############################################################################
+
+
+
+
+first table line
+      -> first table line body, eol         =  
+		buffer_append(&topicBody, "</td></tr>"); 
+
+first table line body
+      -> tab seq, blank seq?, lead topic char:c, table frag?     = { 
+		total1sttableline++;
+                buffer_append(&topicBody,
+  "\n\n<table cellpadding=\"7\" cellspacing=\"2\" >\n<tr><td>  ");
+                appendTableCell(c);
+		buffer_clear(&tabFrag);
+		buffer_clear(&blankFrag);
+	}
+ 
+      -> first table line body, tab seq, blank seq?, lead topic char:c, 
+	 table frag?    = {
+		buffer_append(&topicBody, "</td>\n<td>  ");
+		appendTableCell(c); 
+		buffer_clear(&tabFrag);
+		buffer_clear(&blankFrag);
+	 }
+
+other table line
+      -> other table line body, eol         =  
+		buffer_append(&topicBody, "</td></tr>");
+
+other table line body
+      -> tab seq, blank seq?, lead topic char:c, table frag?     = {
+		buffer_append(&topicBody, "\n\n<tr><td>  ");
+		appendTableCell(c);
+		buffer_clear(&tabFrag);
+		buffer_clear(&blankFrag);
+	 }
+ 
+      -> other table line body, tab seq, blank seq?, lead topic char:c, 
+	 table frag?    = {
+		buffer_append(&topicBody, "</td>\n<td>  ");
+		appendTableCell(c);
+		buffer_clear(&tabFrag);
+		buffer_clear(&blankFrag);
+	 }
+
+  
+
+first list1 line
+      -> bullet, blank, lead topic char:c, text frag?, eol   = {
+		total1stlist1line++;
+	        if (intstack_top(&paragType) != Tlist1) {
+		  intstack_push(&paragType, Tlist1);
+		  buffer_append(&topicBody, "\n<ul>");
+		}
+        	buffer_append(&topicBody, "\n<li>");
+		buffer_add(&topicBody, 0x20);
+		appendEnd(c);
+	 }
+
+other list1 line
+      -> lead topic char:c, text frag?, eol                   = appendEnd(c);
+
+
+first list2 line
+      -> bullet, blank, blank, lead topic char:c, text frag?, eol = {
+		total1stlist2line++;
+		if (intstack_top(&paragType) != Tlist2) {
+		  intstack_push(&paragType, Tlist2);
+		  buffer_append(&topicBody, "\n<ul>");
+		}
+ 		buffer_append(&topicBody, "\n<li>");
+		buffer_append(&topicBody, "  ");
+		appendEnd(c);
+	 }           
+
+other list2 line
+      -> lead topic char:c, text frag?, eol                  = appendEnd(c);
+
+
+first listtab line
+      -> bullet, tab:t, lead topic char:c, text frag?, eol   = {
+		total1stlisttabline++;
+  		if (intstack_top(&paragType) != Tlisttab) {
+		  intstack_push(&paragType, Tlisttab);
+		  buffer_append(&topicBody, "\n<ul>");
+		}
+		buffer_append(&topicBody, "\n<li>");
+		buffer_add(&topicBody, t);
+		appendEnd(c);
+	 }
+
+other listtab line
+      -> lead topic char:c, text frag?, eol                    = appendEnd(c);
+
+
+
+first code line
+      -> "  ", lead topic char:c, text frag?, eol           = {
+		total1stcodeline++;
+		buffer_append(&topicBody, "\n<pre>  ");
+		appendEnd(c);
+	 }
+      -> "   ", lead topic char:c, text frag?, eol          = {
+		total1stcodeline++;
+		buffer_append(&topicBody, "\n<pre>   ");
+		appendEnd(c);
+	 }
+      -> "    ", lead topic char:c, text frag?, eol         = {
+		total1stcodeline++;
+		buffer_append(&topicBody, "\n<pre>    ");
+		appendEnd(c); 
+	 }
+      -> "     ", lead topic char:c, text frag?, eol        = {
+		total1stcodeline++;
+		buffer_append(&topicBody, "\n<pre>     ");
+		appendEnd(c); 
+	 } 
+      -> "      ", lead topic char:c, text frag?, eol       = { 
+		total1stcodeline++;
+		buffer_append(&topicBody, "\n<pre>      ");
+		appendEnd(c);
+	 }
+      -> "        ", lead topic char:c, text frag?, eol     = {
+		total1stcodeline++;
+		buffer_append(&topicBody, "\n<pre>        ");
+		appendEnd(c);
+	 }
+      -> "          ", lead topic char:c, text frag?, eol   = { 
+		total1stcodeline++;
+		buffer_append(&topicBody, "\n<pre>          ");
+		appendEnd(c);
+	 }
+
+
+other code line
+      -> "  ", lead topic char:c, text frag?, eol         = {
+		buffer_append(&topicBody, "  ");
+		appendEnd(c);
+	 }
+      -> "   ", lead topic char:c, text frag?, eol        = {
+		buffer_append(&topicBody, "   ");
+		appendEnd(c);
+	 }
+      -> "    ", lead topic char:c, text frag?, eol       = {
+		buffer_append(&topicBody, "    ");
+		appendEnd(c);
+	 }
+      -> "     ", lead topic char:c, text frag?, eol      = {
+		buffer_append(&topicBody, "     ");
+		appendEnd(c);
+	 }
+      -> "      ", lead topic char:c, text frag?, eol     = {
+		buffer_append(&topicBody, "      ");
+		appendEnd(c);
+	 }
+      -> "        ", lead topic char:c, text frag?, eol   = {
+		buffer_append(&topicBody, "        ");
+		appendEnd(c);
+	 }
+      -> "          ", lead topic char:c, text frag?, eol = {
+		buffer_append(&topicBody, "          ");
+		appendEnd(c);
+	 }
+
+text frag
+      -> text char:c                   = buffer_start(&topicFrag, c);
+      -> text frag, text char:c        = buffer_add(&topicFrag, c);
+
+table frag
+      -> table char:c                  = buffer_start(&topicFrag, c);
+      -> table frag, table char:c      = buffer_add(&topicFrag, c);
+
+
+tab seq
+      -> tab:t                         = buffer_start(&tabFrag, t);
+      -> tab seq, tab:t                = buffer_add(&tabFrag, t);
+
+blank seq
+      -> blank                         = buffer_start(&blankFrag, 0x20);
+      -> blank seq, blank              = buffer_add(&blankFrag, 0x20);
+
+
+
+
+{ /* ----- Embedded C --------------------------------------------*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <assert.h>
+#include <ctype.h>
+#include <assert.h>
+#include <err.h>
+#include "uintarray.h"
+#include "support.h"
+#include "buffer.h"
+#include "stringdict.h"
+#include "must.h"
+
+  int verbose = 0;
+
+  int total1sttextline = 0;
+  int total1sttextlineb = 0;
+  int total1sttableline = 0;
+  int total1stlist1line = 0;
+  int total1stlist2line = 0;
+  int total1stlisttabline = 0;
+  int total1stcodeline = 0;
+
+  int title_count =0;
+  int title_line_count = 0;
+
+  char *helpentStr;
+  struct buffer title;
+  struct buffer title1;
+  struct buffer titleLine;
+  struct buffer titleLine1;
+  struct stringdict *titleDict;
+  struct stringdict *titleDict1;             // upper case
+  struct stringdict *titleLineDict;
+  struct stringdict *titleLineDict1;         // upper case
+  struct buffer topicFrag;
+  struct buffer tabFrag;
+  struct buffer blankFrag;
+  struct buffer topicBody;
+  struct stringdict *topicBodyDict;
+  struct uintarray titleToTitleLine;
+  struct intstack paragType;
+
+  enum paragTypes {Tnone=0, Ttext=1, Ttable=2, Tlist1=3, Tlist2=4, 
+        Tlisttab=5, Tcode=6};
+
+  char *charToEntity(const char *instring);
+  void putTitle(void);
+  void appendTitle(void);
+  void saveTitleLine(void);
+  void appendEnd(int c);
+  void removeFinalNewline(void);
+  void saveTopicBody(void);
+  void printDict(const struct stringdict *dictionary);
+  void writeSortedHtml(FILE *output);
+  void writeFullTopics(FILE *output, const struct stringdict *dictionary,
+		       const struct stringdict *dictionary1,
+		       const struct stringdict *dictionaryb);
+  void writeTitles(FILE *output, const struct stringdict *dictionary,
+                   const struct stringdict *dictionary1); 
+  int processLinkString(FILE *filein, FILE *fileout);
+
+
+  // replace  &, <, > in S with entities 
+  char *charToEntity(const char *s) {
+    char *ret;
+    int i, j, len=0;
+
+    for (i=0; s[i]; i++) {
+      if (s[i] == '&') len += 5; /* &amp; */
+      else if (s[i] == '<') len += 4; /* &lt; */
+      else if (s[i] == '>') len += 4; /* &gt; */
+      else len++;
+    }
+
+    ret = malloc(len+1);
+    if (!ret) {
+      errx(1, "Out of memory");
+    }
+
+    for (i=j=0; s[i]; i++) {
+      if (s[i] == '&')       { strcpy(ret+j, "&amp;"); j += 5; }
+      else if (s[i] == '<' ) { strcpy(ret+j, "&lt;"); j += 4; }
+      else if (s[i] == '>' ) { strcpy(ret+j, "&gt;"); j += 4; }
+      else ret[j++] = s[i];
+    }
+    ret[j] = 0;
+
+    return ret;
+  }
+
+  // Save title both ways, make map entry for title<--->title line
+  void saveTitle(void) {
+    if (stringdict_exists(titleDict, title.text)) {
+      fprintf( stderr, "Warning: Repeated title %s\n", title.text );
+    }
+#if 0
+    else if (!strcmp(title.text, "Secret of Life")) {
+      // Do not save "Secret of Life" title
+      return;
+    }
+#endif
+    else {
+      // Save title in dictionary
+      unsigned titleIndex = stringdict_intern(titleDict, title.text);
+
+      // Save title in upper case dictionary
+      stringdict_intern(titleDict1, title1.text);
+
+      // count() should give next index
+      unsigned titleLineIndex = stringdict_count(titleLineDict);
+
+      // use an array for this (the keys are array indexes anyway)
+      if (titleIndex >= uintarray_num(&titleToTitleLine)) {
+        unsigned x, old = uintarray_num(&titleToTitleLine);
+        uintarray_setsize(&titleToTitleLine, titleIndex+1);
+        for (x=old; x<titleIndex; x++) {
+          uintarray_set(&titleToTitleLine, x, (unsigned) -1);
+        }
+      }
+      // Store indices in map
+      uintarray_set(&titleToTitleLine, titleIndex, titleLineIndex);
+    } 
+  }
+
+
+  void putTitle(void) {
+    // Save title itself in both reg. and upper case title dicts
+    saveTitle();         
+    buffer_append(&titleLine, title.text);
+    buffer_append(&titleLine1, title1.text);
+  }
+
+
+  void appendTitle() {
+    // Save title itself in both reg. and upper case title dicts
+    saveTitle();
+    buffer_append(&titleLine, ", ");
+    buffer_append(&titleLine1, ", ");
+    buffer_append(&titleLine, title.text);
+    buffer_append(&titleLine1, title1.text);
+  }
+
+
+  void saveTitleLine() {
+#if 0
+    static int foundSoL=0;
+    if (stringdict_count(titleLineDict)==0 && 
+	strcmp(titleLine.text, "Secret of Life")!=0 && foundSoL==0) {
+      fprintf(stderr, "Warning: Secret of Life does not lead file!\n");
+    }
+#endif
+
+#if 0
+    if (!strcmp(titleLine.text, "Secret of Life")) {
+      //  Don't save title line in dicts.
+      // Should be at beginning of help file
+      assert(stringdict_count(titleLineDict)==0);
+      foundSoL = 1;
+      if (verbose) {
+        printf( "\n  Found Secret of Life!\n\n" );
+      }
+    }
+    else
+#endif
+    if ( stringdict_exists(titleLineDict, titleLine.text) ) {
+      fprintf( stderr, "Warning: Repeated title line %s\n",
+	       titleLine.text );
+    }
+    else {
+      // Save title line in dictionary
+      stringdict_intern(titleLineDict, titleLine.text);
+      // Save title line in upper case dictionary
+      stringdict_intern(titleLineDict1, titleLine1.text);
+    }
+    buffer_clear(&titleLine);
+    buffer_clear(&titleLine1);
+  }
+
+
+  // Append the latter part of the line
+  void appendEnd(int c) {
+    buffer_add(&topicBody, c);
+    buffer_append(&topicBody, topicFrag.text);
+    buffer_append(&topicBody,  "\n" );
+    buffer_clear(&topicFrag);
+  }
+
+  // Append a cell to the table row
+  void appendTableCell(int c) {
+    // Could insert <pre> </pre>  or <code> </code> tags here for cell
+    buffer_append(&topicBody, "<code> " );
+    buffer_add(&topicBody, c);
+    buffer_append(&topicBody, topicFrag.text);
+    buffer_append(&topicBody, "</code>" );
+    //buffer_append(&topicBody, "\n" );
+    buffer_clear(&topicFrag);
+  }
+
+   void removeFinalNewline(void) {
+     int x = topicBody.len;
+     assert(topicBody.text[x-2]=='\n' && topicBody.text[x-1]=='\n');
+     topicBody.text[x-1] = 0; 
+   }
+
+   void saveTopicBody(void) {
+#if 0
+     // do not save Secret of Life topic body
+     if (stringdict_count(titleLineDict) != 0) {
+#endif
+       // save topic body
+       stringdict_intern(topicBodyDict, topicBody.text);
+#if 0
+     }
+#endif
+     buffer_clear(&topicBody);
+   }
+
+/*
+  void startTable(void) {
+    // If we don't currently have table, start a new one
+    if (paragType.top() != Ttable) {
+      // Start table
+      paragType.push( Ttable );
+    }
+  }
+*/
+
+  void finishList(int listtype){
+    //printf( "\nfinishList() - top type = %d, listtype = %d, "
+    //        "stack size = %d\n"
+    //        "  titleLineDict size = %d\n",
+    //        paragType.top(), listtype, paragType.size(), 
+    //        titleLineDict.size() );
+    assert(intstack_top(&paragType) == listtype);
+    intstack_pop(&paragType);
+    buffer_append(&topicBody, "\n</ul>");
+  }
+
+  void printDict(const struct stringdict *dictionary) {
+    unsigned i;
+    for (i=0; i<stringdict_count(dictionary); i++) {
+      printf("%4d: %s\n", i, stringdict_getbynum(dictionary, i));
+    }
+  }
+
+  char *SqueezeWS(const char *Input) {
+    /* return a (strdup()-like) copy of Input, with whitespace squeezed out */
+    char *copy;
+    int cnt, outcnt;
+
+    copy = must_malloc(strlen(Input)+1);
+
+    for (cnt=0, outcnt=0; Input[cnt]; cnt++) {
+      unsigned char ch = Input[cnt];
+      if (!isspace(ch)) {
+	copy[outcnt]=ch;
+	outcnt++;
+      }
+    }
+    copy[outcnt]=0;
+
+    return copy;
+  }
+
+  void writeFullTopics(FILE *output,
+		       const struct stringdict *dictionary, /* title lines */
+		       const struct stringdict *dictionary1, /* UC titlelines*/
+		       const struct stringdict *dictionaryb) /* topic bodies */
+  {
+    unsigned i;
+
+#if 0
+    /* Write "Secret of Life" topic at beginning of topics */
+    //fprintf(output, "Secret of Life>\n\n");
+    //fprintf(output, "No help message for this topic.\n##\n");
+#endif
+
+    assert( stringdict_count(dictionary) == stringdict_count(dictionary1) );
+    struct permutation *perm = mySort(dictionary1); // Sort  dictionary1
+
+
+    /* Write out topics in a definition list <dl> */
+    fprintf( output, "\n\n<dl>\n\n" );
+
+    // write dictionary, sorted according to dict1
+    for (i = 0; i < stringdict_count(dictionary); i++) {  
+      //fprintf(output, "<dt><b><a name=\"%04d\">%s</a></b></dt>\n"
+      //                "<dd>%s\n</dd><br/>\n\n",
+      //  perm->v[i], 
+      //  stringdict_getbynum(dictionary, perm->v[i]),
+      //  stringdict_getbynum(dictionaryb, perm->v[i])  );
+
+      char *anchorname=SqueezeWS(stringdict_getbynum(dictionary, perm->v[i]));
+      fprintf(output, "<dt><b><a name=\"%s\">%s</a></b></dt>\n"
+	              "<dd>%s\n</dd>\n\n",
+	      anchorname, 
+	      stringdict_getbynum(dictionary, perm->v[i]),
+	      stringdict_getbynum(dictionaryb, perm->v[i])  );
+      free(anchorname);
+    }
+    fprintf( output, "\n\n</dl>\n\n" );
+    permutation_destroy(perm);
+  }
+
+  void writeTitles(FILE *output,
+		   const struct stringdict *dictionary, /* titles */
+		   const struct stringdict *dictionary1) /* uppercase titles */
+  {
+    assert( stringdict_count(dictionary) == stringdict_count(dictionary1) );
+    struct permutation *perm = mySort(dictionary1);   // Sort  dictionary1
+
+    /* Write 2-column table of titles */
+    /*
+      // n_t is true title count w/o Secret of Life
+      int n_t = stringdict_count(dictionary);
+      // we better have some titles
+      assert( n_t >= 2 );
+      // n_t1 is #titles in 1st column
+      int n_t1 = n_t%2 ? n_t/2 +1 : n_t/2;
+      // n_t2 is #titles in 2nd column
+      int n_t2 = n_t%2;
+      int i;         	
+      fprintf( output, "\n\n<table width=\"100%%\" "
+      		       "style=\"margin-left: auto ; margin-right: auto\" \n"
+                       "  cellpadding=\"15\" cellspacing=\"5\" >\n"
+		       "<tr align=\"left\">\n"
+		       "<td valign=\"top\" style=\"white-space: nowrap\">"
+		       "\n\n\n");
+
+     // Write out dictionary sorted acc. to dictionary1 
+     // write out the first half, sorted
+     for (i = 0; i < n_t1; i++) {
+       fprintf(output, " \xA9%s\xAA\n<br/>",
+               stringdict_getbynum(dictionary, perm->v[i]));
+     }
+
+     fprintf(output, "</td>\n\n");
+     fprintf(output, "<td valign=\"top\" style=\"white-space: nowrap\">\n\n");
+
+     // write out the last half, sorted
+     for ( i = n_t1; i < n_t; i++) {
+       fprintf(output, " \xA9%s\xAA\n<br/>",
+               stringdict_getbynum(dictionary, perm->v[i]));
+     }
+
+     fprintf(output, "</td>\n</tr>\n</table>\n\n<hr><br/><br/>\n\n" );
+    */
+
+    /* Write 1-column list of titles */
+     
+    // n_t is true title count w/o Secret of Life
+    unsigned n_t = stringdict_count(dictionary);
+    // we better have some titles
+    assert( n_t >= 2 );                        
+    unsigned i;         	
+
+    fprintf(output, "<h2>Help Topic Index</h2>\n\n" );
+    // Write out the index, sorted acc. to dictionary1 
+    for (i = 0; i < n_t; i++) {
+      fprintf(output, "\xA9%s\xAA\n<br/>",
+	      stringdict_getbynum(dictionary, perm->v[i]));
+    }
+  }
+
+  void writeSortedHtml( FILE *output ) {
+    /* Leading HTML */
+
+#ifdef XML_OUTPUT
+    fprintf(output, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+	    "<?xml-stylesheet type=\"text/xsl\" href=\"../ag_web.xml\"?>\n"
+	    "\n"
+	    "<body rootdir=\"..\" navname=\"Documentation: AnaGram Help\">\n");
+ 
+#else
+    fprintf(output, "<html>\n<head>\n");
+    fprintf(output, "<title>AnaGram Help Topics - HTML version</title>\n");
+    fprintf(output, "</head>\n\n\n");
+    fprintf(output, "<body bgcolor=\"#ffffff\" text=\"#000000\"");
+    fprintf(output, " link=\"#0033CC\" vlink=\"#CC0033\" alink=\"#CC0099\">");
+    fprintf(output, "\n\n\n");
+#endif
+
+    /* Write page title */
+#ifdef XML_OUTPUT
+    fprintf(output, "<h1>AnaGram Help</h1>\n\n");
+#else
+    fprintf(output, "<hr><h2>AnaGram Help Topics - HTML Version</h2><hr>\n\n");
+#endif
+    /* Write 2-column table of titles */
+    writeTitles( output, titleDict, titleDict1 );
+
+    /* Write full topics in single- column table */
+    //fprintf( output, "\n\n<table width=\"100%%\">\n<tr><td>\n<p>\n\n");
+    //writeFullTopics( output, titleLineDict, titleLineDict1, topicBodyDict );
+    //fprintf( output, "</td></tr>\n</table>\n" );
+
+    /* Write full topics directly to the output page */
+    writeFullTopics( output, titleLineDict, titleLineDict1, topicBodyDict );
+
+#ifdef XML_OUTPUT
+    fprintf(output,"\n</body>\n");
+#else 
+    /* Ending HTML */
+    fprintf( output, "\n<p><br/><address><a "
+	     "NAME=\"copyright\">AnaGram Help Topics, HTML version.</a>\n"
+	     "<br> Copyright &copy; Parsifal Software, 2001.<br>\n"
+	     "All Rights Reserved.</address>" 
+	     "\n\n</body>\n</html>\n\n" );
+#endif
+  }
+
+  int processLinkString( FILE *filein, FILE *fileout ) {
+    struct buffer linkString;                   // lower case
+    struct buffer linkString1;                  // upper case version
+    unsigned index;
+    int c;
+    int wspaceFlag =0;
+
+    buffer_init(&linkString);
+    buffer_init(&linkString1);
+
+    while ( (c=fgetc(filein)) != EOF ) {
+    
+      if ( c != 0xAA) {                            // test for end of link char
+	if ( c == 0x20 || c == 0x0D || c == 0x0A ) {
+	  // don't append these chars
+	  wspaceFlag = 1;  
+	}
+	else {
+	  if (wspaceFlag) {
+            // Replace space, cr, lf with single space
+	    buffer_add(&linkString, 0x20);
+	    buffer_add(&linkString1, toupper(0x20));         
+	  }
+	  buffer_add(&linkString, c);
+	  buffer_add(&linkString1, toupper(c));
+	  wspaceFlag = 0;
+	}
+      }
+      else {
+	// end of link - look up using upper case string
+	if (!stringdict_exists(titleDict1, linkString1.text)) {
+	  // try match w/o final S
+	  if ( linkString1.text[linkString1.len - 1] == 'S' ) {
+	    linkString1.text[linkString1.len - 1] = 0;
+	    if (stringdict_exists(titleDict1, linkString1.text)) {
+	      goto matched;      // Eccch - a goto!
+	    }
+	  }
+
+	  fprintf(stderr, "Can't find this link in titleDict1: %s\n",
+		 linkString1.text);
+	  return 21; 
+	}
+
+        /* find corresp. index in title line direc. */      
+    matched:
+
+	index = stringdict_findbyname(titleDict1, linkString1.text);
+
+	unsigned ilink = uintarray_get(&titleToTitleLine, index);
+	assert(ilink != (unsigned) -1);
+
+	// Write out string, linked to title line
+	char *linkname=SqueezeWS(stringdict_getbynum(titleLineDict, ilink));
+	//fprintf(fileout, "<a href=\"#%04d\">%s</a>", ilink, linkString.text);
+	fprintf( fileout, "<a href=\"#%s\">%s</a>", linkname, linkString.text);
+	free(linkname);
+
+	buffer_cleanup(&linkString);
+	buffer_cleanup(&linkString1);
+
+	return 0;            // normal return - have found  and written link 
+      }
+    }
+    // Error - unexpected end of file
+    fprintf(stderr, "Error: EOF detected while searching for end of link.\n");
+    fprintf(stderr, "  Current link string is: %s\n", linkString.text );
+    return 23;
+  }
+
+  static void init(void) {
+    buffer_init(&title);
+    buffer_init(&title1);
+    buffer_init(&titleLine);
+    buffer_init(&titleLine1);
+    titleDict = stringdict_create();
+    titleDict1 = stringdict_create();
+    titleLineDict = stringdict_create();
+    titleLineDict1 = stringdict_create();
+    topicBodyDict = stringdict_create();
+    buffer_init(&topicFrag);
+    buffer_init(&tabFrag);
+    buffer_init(&blankFrag);
+    buffer_init(&topicBody);
+    intstack_init(&paragType);
+    uintarray_init(&titleToTitleLine);
+  }
+
+/* -- Main Program -- */
+
+int main(int argc, char *argv[]) {
+
+  FILE *input;
+
+  long fileLength;
+  size_t stringLength;
+  char *helpsrcString;
+
+  init();
+
+  if (verbose) {
+    printf( "\n  This program reads a help.src-type file, "
+	    "replaces &, <, > with entities,\n"
+	    "sorts in a case-insensitive manner and writes "
+	    "to output file as HTML\n"
+	    "with a preceding list of the help topics. \n\n" );
+  }
+
+  /* Check for enough arguments */
+  if (argc != 3) {
+    fprintf(stderr, "Usage: mhh6 helpdata.src help.html\n");
+    return 1;
+  }
+
+  /* Open input file */
+  input = fopen(argv[1],"r");
+  if (input == NULL) {
+    fprintf(stderr, "Cannot open %s\n", argv[1]);
+    return 2;
+  }
+
+  /* find out how big the input file is */
+  if (fseek(input, SEEK_SET, SEEK_END)) {
+    fprintf(stderr, "Strange problems with %s\n", argv[1]);
+    return 3;
+  }
+  fileLength = ftell(input);
+  if (fileLength < 0 ) {    // -1L is error return
+    fprintf(stderr, "Error getting file length (%ld) of %s\n",
+	    fileLength, argv[1]);
+    return 4;
+  }
+
+  /* fseek to beginning of file */
+  if (fseek(input, 0, SEEK_SET)) {
+    fprintf(stderr, "Strange problems with %s\n", argv[1]);
+    return 5;
+  }
+
+  /* Allocate storage for input string */
+  helpsrcString = must_malloc(fileLength + 1);
+
+  /* read file */
+  stringLength = fread(helpsrcString, 1, (unsigned)fileLength, input);
+  if (stringLength == 0) {
+    fprintf(stderr, "Unable to read %s\n", argv[1]);
+    free(helpsrcString);
+    fclose(input);
+    return 7;
+  }
+  // Terminate string with null
+  helpsrcString[stringLength] = 0;
+
+  /* first, replace < > & with entities */
+  helpentStr = charToEntity( helpsrcString ); 
+
+  /* no more need for input string or file */
+  free(helpsrcString);
+  fclose(input);
+
+  /* initialize stack of parag types */
+  intstack_push(&paragType, Tnone);
+ 
+  /* call parser */
+  PCB.pointer = (unsigned char *)(const char *)helpentStr;
+  mhh6();
+
+  /* Print file statistics */
+  if (verbose) {
+    printf("No. of title lines in line dict.= %d\n",
+	   stringdict_count(titleLineDict) );
+    printDict(titleLineDict);              // print title lines
+    printf( "\n\n" );
+
+    printf( "title count = %d, includes Secret of Life \n\n", title_count );
+    printf( "title line count = %d, includes Secret of Life \n\n", 
+	    title_line_count );
+    printf( "total1sttextline = %d, \n", total1sttextline );
+    printf( "total1sttextlineb = %d \n", total1sttextlineb  );
+    printf( "total1sttableline = %d \n", total1sttableline  );
+    printf( "total1stlist1line = %d \n", total1stlist1line  );
+    printf( "total1stlist2line = %d \n", total1stlist2line  );
+    printf( "total1stlisttabline = %d \n", total1stlisttabline  );
+    printf( "total1stcodeline = %d \n", total1stcodeline  );
+  }
+
+  /* check for error */
+  if (verbose) {
+    printf( "PCB.exit_flag = %d (%d for success)\n", PCB.exit_flag,
+	    AG_SUCCESS_CODE);
+  }
+  if (PCB.exit_flag != AG_SUCCESS_CODE) {
+    fprintf(stderr, "File %s: error at line %d, column %d\n",
+	    argv[1],
+	    PCB.line,
+	    PCB.column);
+    return 8;
+  }
+
+  // Write sorted title lines & topics as HTML to intermediate file
+  FILE *intermed;
+  const char *filename = "intermed.html";
+  /* Open intermediate file */
+  intermed = fopen(filename ,"w+");  // create intermediate text file 
+  if (intermed == NULL) {
+    fprintf(stderr, "Cannot open %s\n", filename);
+    return 9;
+  }
+  if (verbose) {
+    printf( "Writing sorted title lines & topic bodies to "
+	    "intermediate file in HTML format...\n");
+  }
+  writeSortedHtml(intermed); 
+  rewind(intermed);
+
+  /* Create output HTML file, inserting links */
+  FILE *output;
+  /* Open output file */
+  output = fopen(argv[2] ,"w");   
+  if (output == NULL) {
+    fprintf(stderr, "Cannot open %s\n", argv[2]);
+    return 10;
+  }
+
+  if (verbose) {
+    printf( "Writing output file with HTML links...\n");
+  }
+
+  int c = 0;
+  int ctest = 0;
+  
+  while ( (c=fgetc(intermed)) != EOF ){
+
+    if ( c == 0xA9 ) {            // begins link string
+      //  printf( "\n Found beginning of link" );
+      int itest = processLinkString(intermed, output);
+      if (itest !=0) return itest;    // error return
+    }
+    else {
+      ctest = fputc( c, output );    // write out current character
+      if (ctest == EOF) return 11;
+    }
+  }  
+
+  fclose(intermed);
+  fclose(output);
+
+
+  /* done */
+  if (verbose) {
+    printf( "All done.\n" );
+  }
+  return 0;                          // normal return 
+
+}  /* -- End of main() function -- */
+
+} /* ---- End of embedded C ----------------------------------------- */
+
+