Category : EmTeX is a TeX/LaTeX document editor
Archive   : TEX2RTF.ZIP
Filename : HTMLUTIL.CC

 
Output of file : HTMLUTIL.CC contained in archive : TEX2RTF.ZIP
/*
* htmlutil.cc
*
* Utility functions for helping convert Latex files
* into HTML files.
* files.
*
* Julian Smart September 1993
*
*/

#include
#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 ->

.
*
*/

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, "

\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("");<br /> TraverseChildrenFromChunk(currentSection);<br /> TexOutput("\n");

SetCurrentOutputs(Contents, Chapters);
fprintf(Contents, "\n

  • \n", ChaptersName, topicName);

    fprintf(Chapters, "
    \n

    ", topicName);
    TraverseChildrenFromChunk(currentSection);
    fprintf(Contents, "\n
    \n");
    fprintf(Chapters, "

    \n\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("");<br /> TraverseChildrenFromChunk(currentSection);<br /> TexOutput("\n");

    FILE *jumpFrom = ((DocumentStyle == LATEX_ARTICLE) ? Contents : Chapters);

    SetCurrentOutputs(jumpFrom, Sections);
    if (DocumentStyle == LATEX_ARTICLE)
    fprintf(jumpFrom, "\n
  • \n", SectionsName, topicName);
    else
    fprintf(jumpFrom, "\n
    \n", SectionsName, topicName);

    fprintf(Sections, "
    \n

    ", topicName);
    TraverseChildrenFromChunk(currentSection);

    if (DocumentStyle == LATEX_ARTICLE)
    fprintf(jumpFrom, "\n
    \n");
    else
    fprintf(jumpFrom, "
    \n

    \n");
    fprintf(Sections, "

    \n\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("References\n");

    char *topicName = "references";
    SetCurrentOutputs(Contents, jumpTo);
    fprintf(Contents, "\n
  • \n", jumpToName, topicName);

    fprintf(jumpTo, "
    \n

    ", topicName);
    TexOutput("References");
    fprintf(Contents, "\n
    \n");
    fprintf(jumpTo, "

    \n\n");

    SetCurrentOutput(jumpTo);
    TexOutput("
    \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("");<br /> TraverseChildrenFromChunk(currentSection);<br /> TexOutput("\n");

    SetCurrentOutputs(Sections, Subsections);
    fprintf(Sections, "\n\n", SubsectionsName, topicName);
    fprintf(Subsections, "
    \n

    ", topicName);
    TraverseChildrenFromChunk(currentSection);
    fprintf(Sections, "
    \n

    \n");
    fprintf(Subsections, "

    \n\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("");<br /> TraverseChildrenFromChunk(currentSection);<br /> TexOutput("\n");

    SetCurrentOutputs(Subsections, Subsubsections);
    fprintf(Subsections, "\n\n", SubsubsectionsName, topicName);
    fprintf(Subsubsections, "
    \n

    ", topicName);
    TraverseChildrenFromChunk(currentSection);
    fprintf(Subsections, "
    \n

    \n");
    fprintf(Subsubsections, "

    \n\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("void");
    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("&");
    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("
      \n");
      break;
      case LATEX_ENUMERATE:
      TexOutput("
        \n");
        break;
        case LATEX_DESCRIPTION:
        TexOutput("
        \n");
        break;
        }
        }
        else
        {
        indentLevel --;
        if (itemizeStack.First())
        {
        ItemizeStruc *struc = (ItemizeStruc *)itemizeStack.First()->Data();
        switch (struc->listType)
        {
        case LATEX_ITEMIZE:
        TexOutput("
    \n");
    break;
    case LATEX_ENUMERATE:
    TexOutput("\n");
    break;
    case LATEX_DESCRIPTION:
    TexOutput("
    \n");
    break;
    }

    delete struc;
    delete itemizeStack.First();
    }
    }
    }
    else if (strcmp(name, "par") == 0)
    {
    if (start)
    TexOutput("

    \n");
    }
    else if (strcmp(name, "verbatim") == 0)
    {
    if (start)
    {
    char buf[100];
    sprintf(buf, "

    \n");
    TexOutput(buf);
    }
    else TexOutput("
    \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("

    ");
    }
    else TexOutput("

    ");
    }
    else if (strcmp(name, "Large") == 0)
    {
    if (start)
    {
    TexOutput("

    ");
    }
    else TexOutput("

    ");
    }
    else if (strcmp(name, "bf") == 0)
    {
    if (start)
    {
    TexOutput("");
    }
    else TexOutput("
    ");
    }
    else if (strcmp(name, "it") == 0)
    {
    if (start)
    {
    TexOutput("");
    }
    else TexOutput("
    ");
    }
    else if (strcmp(name, "tt") == 0)
    {
    if (start)
    {
    TexOutput("");
    }
    else TexOutput("
    ");
    }
    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("

    \n");
    if (struc->listType == LATEX_DESCRIPTION)
    {
    if (descriptionItemArg)
    {
    TexOutput("

    ");
    TraverseChildrenFromChunk(descriptionItemArg);
    TexOutput("\n");
    descriptionItemArg = NULL;
    }
    TexOutput("
    ");
    }
    else
    TexOutput("
  • ");
    }
    }
    }
    else if (strcmp(name, "maketitle") == 0)
    {
    if (start && DocumentTitle && DocumentAuthor)
    {
    TexOutput("

    ");
    TraverseChildrenFromChunk(DocumentTitle);
    TexOutput("

    \n\n");
    TexOutput("

    ");
    TraverseChildrenFromChunk(DocumentAuthor);
    TexOutput("

    \n\n");
    if (DocumentDate)
    {
    TexOutput("

    ");
    TraverseChildrenFromChunk(DocumentDate);
    TexOutput("

    \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("\n");
    }
    }
    else if (strcmp(name, "hrule") == 0)
    {
    if (start)
    {
    TexOutput("

    ------------------------------------------------------------------

    \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("");

    if (!start && (arg_no == 1))
    TexOutput("
    ");

    if (start && (arg_no == 2))
    {
    if (!suppressNameDecoration) TexOutput("");
    currentMember = GetArgChunk();
    }
    if (!start && (arg_no == 2))
    {
    if (!suppressNameDecoration) TexOutput("
    ");
    }

    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("");
    if (!start && (arg_no == 1))
    TexOutput("
    ");

    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("");
    if (!start && (arg_no == 1))
    TexOutput("
    ");
    if (start && (arg_no == 2))
    {
    TexOutput("");
    }
    if (!start && (arg_no == 2))
    {
    TexOutput("
    ");
    }
    }
    else if (strcmp(macro_name, "cparam") == 0)
    {
    if (start && (arg_no == 1))
    TexOutput("");
    if (!start && (arg_no == 1))
    TexOutput("
    "); // This is the difference from param - one space!
    if (start && (arg_no == 2))
    {
    TexOutput("");
    }
    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 (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(" // 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("
    ");
    }
    }
    else TexOutput("??");
    }
    return FALSE;
    }
    }
    else if (strcmp(macro_name, "psboxto") == 0 || strcmp(macro_name, "image") == 0)
    {
    if (arg_no == 2)
    {
    if (start)
    TexOutput(" else
    TexOutput("\">Picture

    \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

    ");
    if (arg_no == 2 && start)
    TexOutput("\n
    ");
    if (arg_no == 2 && !start)
    TexOutput("

    \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, "

    Contents

    \n");

    fprintf(Contents, "

      \n");

      SetCurrentOutput(Titlepage);
      OnInform("Converting...");

      TraverseDocument();

      if (DocumentTitle)
      {
      SetCurrentOutput(Titlepage);
      TexOutput("\n");<br /> TraverseChildrenFromChunk(DocumentTitle);<br /> TexOutput("\n");
      }
      else
      {
      if (contentsString)
      fprintf(Titlepage, "%s\n\n", contentsString);
      else
      fprintf(Titlepage, "%s\n\n", FileNameFromPath(FileRoot));
      }

      fprintf(Contents, "
    \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;
    }



  •   3 Responses to “Category : EmTeX is a TeX/LaTeX document editor
    Archive   : TEX2RTF.ZIP
    Filename : HTMLUTIL.CC

    1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

    2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

    3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/