PROGRAM RHFC; { Ramon Help File Compiler }

{## todo: popups? We can use a normal topic right now, but might want }
{                 to disable cursor movements??                       }

{ this program creates the WaterGate help file }

{ History:

17-10-93 First version
18-10-93 Added header info, RH1
08-08-98 Changes for NEWHELP.INC, RH2

}

{ NOTE
  You can add the compiler to the BP Tools Menu of the IDE.
  In the command line field, fill in "$EDNAME $MEM(100)".
  This frees up at least 100Kb before it starts the compiler.
  The argument will be the file that is open in the editor.
}

(*

The input is a text file with the following format. The output
is a binary file and an optional pascal include file that declares
all the constants for accessing the topics.

Format:
Each line that starts with a semi-colon is a comment line

First line must be HLPname <output name> to define the name of the
binary output file. Example: HLPname wtrgate.hlp

Second line can be INCname <output name> to define the name of the
pascal include file to create. Example: INCname wtrhelp.inc

The rest of the file contains text and keywords. The keywords always
start with a hash ("#") character followed by the keyword and an
optional argument after at least one space.

Text is not shown as formatted in the text file, but is formatted by
the reader. The source file can indicate where breaks must be forced,
with the exception that an empty line implicitly indicates a break.
Otherwise, use #BREAK on a separate line.

The following keywords are supported:

#HLPNAME(filename)
  This keyword may be present only once and must be present on the
  first line of the source file. The filename defines the binary output
  file that will be created by the compiler.
  Example: #HLPNAME(wtrgate.hlp)

#INCNAME(filename)
  This keyword is optional, but must not be present more than once. It
  defines the name of the pascal include file that will be created by
  the compiler.
  Example: #INCNAME(wtrhelp.inc)

#INCLUDE(filename)
  Includes another file.

#TOPIC(reference text)
  Starts a new topic. The reference text will be used to create a
  constant in the pascal include file and must be used when referring
  to this topic from another topic.
  Example: #TOPIC(System Settings)
  This creates the pascal symbol htr_System_Settings

#SUBTOPIC(reference text)
  Same as topic, but is used to create sub-topics. Help can be opened
  in a sub-topic and a link can point to a sub-topic. The entire topic
  will be loaded, with the focus on the sub-topic.
  Example: #SUBTOPIC(FTN inbound)
  This creates the pascal symbol htr_FTN_inbound

#END
  Terminates a topic. Must be used before the next #TOPIC.
  Example: #END

#TITLE(title text)
  Sets the title for the topic. Each topic has only one title. The
  title is shown in a different color and must be the first entry
  in the topic.
  Example: #TITLE(System Configuration Settings)

#LINEBREAK
  This keyword forces the following text to start on a new line,
  after an empty line.
  A space at the start of a line is implicitly interpreted as a
  #linebreak.
  Example: #LINEBREAK

#BREAK
  As #linebreak, but inserts an empty line as well.
  An empty line between #(sub)topic and #end is implicitly interpreted
  as a #break.
  Example: #BREAK

#LINK(reference)(text)
  This is the only keyword that can be present in the middle of the
  text and does not have to start in the left colomn. The first
  argument is the reference to the topic or sub-topic and the second
  argument is the text that will be shown in a different color by
  the reader.
  Example: See #LINK(FTN inbound,inbound path) for more details.

#HL(text)
  (HL = highlight)
  Gives the text another color to show it is more important than the
  rest of the text.
*)

USES Ramon;

{$I KEYSDEF.INC}
{$I HLPSTRUC.INC}

TYPE TopicRecordPtr = ^TopicRecord;
     TopicRecord = RECORD
                         TopicNr      : LONGINT;
                         RefStrPtr    : ^STRING;
                         IndexPos     : LONGINT;
                         NextTopicPtr : TopicRecordPtr;
                   END;

VAR HelpPath      : STRING;
    HlpIsOpen     : BOOLEAN;
    IncFile       : TEXT;
    IncIsOpen     : BOOLEAN;
    IncFileCRC    : LONGINT;
    Fatal         : BOOLEAN;
    Pass          : BYTE;
    InBlock       : BOOLEAN;
    TopicNr       : LONGINT;
    FirstTopicPtr : TopicRecordPtr;
    LastTopicPtr  : TopicRecordPtr;
    LastWasBreak  : BOOLEAN;
    Warnings      : WORD;
    HasTitle      : BOOLEAN;

{--------------------------------------------------------------------------}
{ DestroyTopicList                                                         }
{                                                                          }
{ This routine destroys the linked topics list that is craeted by          }
{ CreateTopic.                                                             }
{                                                                          }
PROCEDURE DestroyTopicList;

VAR EraseTopicPtr : TopicRecordPtr;

BEGIN
     WHILE (FirstTopicPtr <> NIL) DO
     BEGIN
          EraseTopicPtr:=FirstTopicPtr;
          FirstTopicPtr:=FirstTopicPtr^.NextTopicPtr;
          FreeMem (EraseTopicPtr^.RefStrPtr,Length (EraseTopicPtr^.RefStrPtr^)+1);
          FreeMem (EraseTopicPtr,SizeOf (TopicRecord));
     END;
END;


{--------------------------------------------------------------------------}
{ CreateTopic                                                              }
{                                                                          }
{ This function is called to create a new topic. This is done in the first }
{ pass when all #TOPIC and #SUBTOPIC keywords are processed. The topic     }
{ number and text are stored in a linked list.                             }
{ Returns FALSE if the topic is a duplicate.                               }
{                                                                          }
FUNCTION CreateTopic (TopicNr : LONGINT; Regel : STRING) : BOOLEAN;

VAR P           : BYTE;
    NewTopicPtr : TopicRecordPtr;
    TopicPtr    : TopicRecordPtr;
    UpRefStr    : STRING;

BEGIN
     IF (Pass = 2) THEN
     BEGIN
          WriteLn ('Bug: CreateTopic in second pass');
          Halt;
     END;

     UpRefStr:=UpCaseString (Regel);
     TopicPtr:=FirstTopicPtr;
     WHILE (TopicPtr <> NIL) DO
     BEGIN
          IF (UpCaseString (TopicPtr^.RefStrPtr^) = UpRefStr) THEN
          BEGIN
               CreateTopic:=FALSE; { duplicate! }
               Exit;
          END;

          TopicPtr:=TopicPtr^.NextTopicPtr;
     END;

     CreateTopic:=TRUE; { not a duplicate }

     GetMem (NewTopicPtr,SizeOf (TopicRecord));
     NewTopicPtr^.TopicNr:=TopicNr;
     GetMem (NewTopicPtr^.RefStrPtr,Length (Regel)+1);
     NewTopicPtr^.RefStrPtr^:=Regel;
     NewTopicPtr^.IndexPos:=0;
     NewTopicPtr^.NextTopicPtr:=NIL;

     IF (FirstTopicPtr = NIL) THEN
        FirstTopicPtr:=NewTopicPtr
     ELSE
         LastTopicPtr^.NextTopicPtr:=NewTopicPtr;

     LastTopicPtr:=NewTopicPtr;

     Regel:='htr_'+Regel;
     REPEAT
           P:=Pos (' ',Regel);
           IF (P > 0) THEN
              Regel[P]:='_';
     UNTIL (P = 0);

     IF IncIsOpen THEN
     BEGIN
          UpRefStr:='CONST '+Regel+' = $'+Long2HexString (TopicNr)+';';
          WriteLn (IncFile,UpRefStr);
          IncFileCRC:=UpdateCRC32(IncFileCRC,UpRefStr[1],Length (UpRefStr));
     END;
END;


{--------------------------------------------------------------------------}
{ SetTopicOffset                                                           }
{                                                                          }
{ This routine is called in the second pass when a TOPIC or SUBTOPIC       }
{ keyword is found. The current file position is filled in for the given   }
{ topic.                                                                   }
{                                                                          }
PROCEDURE SetTopicOffset (TopicNr : LONGINT; Offset : LONGINT);

VAR TopicPos : LONGINT;
    TopicPtr : TopicRecordPtr;
    HelpRec  : HelpIndexRecord;

BEGIN
     TopicPtr:=FirstTopicPtr;
     WHILE (TopicPtr <> NIL) DO
     BEGIN
          IF (TopicPtr^.TopicNr = TopicNr) THEN
          BEGIN
               Seek (HlpFile,TopicPtr^.IndexPos);
               BlockRead (HlpFile,HelpRec,SizeOf (HelpIndexRecord));

               HelpRec.Offset:=Offset;

               Seek (HlpFile,TopicPtr^.IndexPos);
               BlockWrite (HlpFile,HelpRec,SizeOf (HelpIndexRecord));

               Exit;
          END;

          TopicPtr:=TopicPtr^.NextTopicPtr;
     END;

     WriteLn ('Bug: TopicNr $'+Long2HexString (TopicNr)+' not found');
     Halt;
END;


{--------------------------------------------------------------------------}
{ GetTopicNrByRefStr                                                       }
{                                                                          }
{ This routine searches the linked list of topics for the reference string }
{ and returns the TopicNr and TRUE when found.                             }
{                                                                          }
FUNCTION GetTopicNrByRefStr (RefStr : STRING; VAR TopicNr : LONGINT) : BOOLEAN;

VAR TopicPtr : TopicRecordPtr;
    UpRefStr : STRING;

BEGIN
     UpRefStr:=UpCaseString (RefStr);
     TopicPtr:=FirstTopicPtr;
     WHILE (TopicPtr <> NIL) DO
     BEGIN
          IF (UpCaseString (TopicPtr^.RefStrPtr^) = UpRefStr) THEN
          BEGIN
               TopicNr:=TopicPtr^.TopicNr;
               GetTopicNrByRefStr:=TRUE;
               Exit;
          END;

          TopicPtr:=TopicPtr^.NextTopicPtr;
     END;

     WriteLn ('Topic not found: ',RefStr);
     Inc (Warnings);

     GetTopicNrByRefStr:=FALSE;
END;


{--------------------------------------------------------------------------}
{ AddToOutput                                                              }
{                                                                          }
{ This routine writes the given text to the helpfile, converting it first  }
{ from the source format to the format the reader understands.             }
{                                                                          }
PROCEDURE AddToOutput (Regel : STRING);
BEGIN
     IF (Pass = 1) THEN
     BEGIN
          WriteLn ('AddToOutput: called during first pass!');
          Halt;
     END;

     IF (Regel = '') THEN
        Exit;

     LastWasBreak:=(Regel[Length (Regel)] = #10);

     Seek (HlpFile,FileSize (HlpFile));
     BlockWrite (HlpFile,Regel[1],Length (Regel));
END;


PROCEDURE ProcessTextFile (Filename : STRING); FORWARD;

{--------------------------------------------------------------------------}
{ HandleKeyword                                                            }
{                                                                          }
{ This routine handles the keywords present in the source file. Any text   }
{ that follows the keyword is returned.                                    }
{                                                                          }
FUNCTION HandleKeyword (Regel,OrigTextRegel,Ref : STRING) : STRING;

VAR Keyword : STRING[20];
    Arg     : STRING;

    FUNCTION GetArgument : BOOLEAN;

    VAR Skip : BYTE;
        Lp   : BYTE;

    BEGIN
         Skip:=0;

         IF (Regel <> '') AND (Regel[1] = '(') THEN
            FOR Lp:=1 TO Length (Regel) DO
                IF (Regel[Lp] = ')') THEN
                BEGIN
                     Dec (Skip);

                     IF (Skip = 0) THEN
                     BEGIN
                          Arg:=Copy (Regel,2,Lp-2);
                          Delete (Regel,1,Lp);
                          GetArgument:=TRUE;
                          Exit;
                     END;
                END ELSE
                    IF (Regel[Lp] = '(') THEN
                       Inc (Skip);

         WriteLn (Ref,'Fatal: Argument missing in "'+OrigTextRegel+'"');
         Fatal:=TRUE;
         GetArgument:=FALSE;
    END;

VAR P      : BYTE;
    Known  : BOOLEAN;
    IORes  : BYTE;
    Header : STRING[20];

BEGIN
     HandleKeyword:=''; { in case of errors }

     IF (Regel[1] <> '#') THEN
     BEGIN
          WriteLn (Ref,'Keyword line does not start with #: '+OrigTextRegel);
          Fatal:=TRUE;
          Exit;
     END;

     Delete (Regel,1,1);

     { extract keyword }
     P:=Pos ('(',Regel);
     IF (P = 0) THEN
     BEGIN
          P:=Pos (' ',Regel);
          IF (P > 0) THEN
          BEGIN
               IF (Pass = 1) THEN
               BEGIN
                    WriteLn (Ref,'Old format: ',Regel);
                    Inc (Warnings);
               END;

               Regel[P]:='(';
               Regel:=Regel+')';
          END;
     END;

     IF (P > 0) THEN
     BEGIN
          Keyword:=Copy (Regel,1,P-1);
          Delete (Regel,1,P-1);
          Regel:=DeleteFrontSpaces (Regel);
     END ELSE
     BEGIN
          Keyword:=Regel;
          Regel:='';
     END;

     Keyword:=UpCaseString (Keyword);

     Known:=FALSE;

     IF (Keyword = 'INCLUDE') THEN
     BEGIN
          Known:=TRUE;

          IF (NOT GetArgument) THEN
             Exit;

          ProcessTextFile(Arg);
     END;

     IF (Keyword = 'HLPNAME') THEN
     BEGIN
          Known:=TRUE;

          IF (Pass = 1) THEN
          BEGIN
               IF (HlpIsOpen) THEN
               BEGIN
                    WriteLn (Ref,'Second #HLPNAME found');
                    Fatal:=TRUE;
                    Exit;
               END;

               IF (NOT GetArgument) THEN
                  Exit;

               Assign (HlpFile,Arg);
               {$I-} ReWrite (HlpFile,1); {$I+} IORes:=IOResult;
               IF (IORes <> 0) THEN
               BEGIN
                    WriteLn (Ref,'Failed to create help file ',Arg,' (error ',IORes,')');
                    Fatal:=TRUE;
                    Exit;
               END;

               HlpIsOpen:=TRUE;

               Header:='Online Help File'#26'RH2';
               BlockWrite (HlpFile,Header[1],20);

               { will be replaced later }
               BlockWrite (HlpFile,IncFileCRC,4);
          END;
     END;

     IF (Keyword = 'INCNAME') THEN
     BEGIN
          Known:=TRUE;

          IF (Pass = 1) THEN
          BEGIN
               IF (IncIsOpen) THEN
               BEGIN
                    WriteLn (Ref,'Second #INCNAME found');
                    Fatal:=TRUE;
                    Exit;
               END;

               IF (NOT GetArgument) THEN
                  Exit;

               Assign (IncFile,Arg);
               {$I-} ReWrite (IncFile); {$I+} IORes:=IOResult;
               IF (IORes <> 0) THEN
               BEGIN
                    WriteLn ('Failed to create include file ',Arg,' (error ',IORes,')');
                    Fatal:=TRUE;
                    Exit;
               END;

               IncIsOpen:=TRUE;

               WriteLn (IncFile,'{ ',arg,' }');
               WriteLn (IncFile);
               WriteLn (IncFile,'{ contents: help file reference symbols }');
               WriteLn (IncFile,'{ automatically generated by RHFC }');
               WriteLn (IncFile);
          END;
     END;

     IF (NOT Known) AND (NOT HlpIsOpen) THEN
     BEGIN
          WriteLn (Ref,'HLPNAME keyword required before '+Keyword);
          Fatal:=TRUE;
          Exit;
     END;

     IF (Keyword = 'TOPIC') THEN
     BEGIN
          Known:=TRUE;

          HasTitle:=FALSE;

          IF InBlock THEN
          BEGIN
               WriteLn (Ref,'Fatal: Missing #END before #TOPIC');
               Fatal:=TRUE;
               Exit;
          END;

          IF (NOT GetArgument) THEN
             Exit;

          IF (Pass = 1) THEN
          BEGIN
               IF (Arg = 'Help on Help') THEN
               BEGIN
                    IF (NOT CreateTopic ($FFFF0000,Arg)) THEN
                    BEGIN
                         WriteLn (Ref,'Duplicate topic found: ',Arg);
                         Fatal:=TRUE;
                         Exit;
                    END;
               END ELSE
                   IF (Arg = 'File Manager') THEN
                   BEGIN
                        IF (NOT CreateTopic ($FFFC0000,Arg)) THEN
                        BEGIN
                             WriteLn (Ref,'Duplicate topic found: ',Arg);
                             Fatal:=TRUE;
                             Exit;
                        END;
                   END ELSE
                   BEGIN
                        { reset sub-topic counter }
                        TopicNr:=TopicNr AND $FFFF0000;
                        Inc (TopicNr,$00010000);
                        IF (NOT CreateTopic (TopicNr,Arg)) THEN
                        BEGIN
                             WriteLn (Ref,'Duplicate topic found: ',Arg);
                             Fatal:=TRUE;
                             Exit;
                        END;
                   END;
          END;

          InBlock:=TRUE;

          IF (Pass = 2) THEN
          BEGIN
               LastWasBreak:=TRUE;

               IF (NOT GetTopicNrByRefStr (Arg,TopicNr)) THEN
                  Exit;

               SetTopicOffset (TopicNr,FileSize (HlpFile));
          END;
     END;

     IF (Keyword = 'SUBTOPIC') THEN
     BEGIN
          Known:=TRUE;

          IF (NOT GetArgument) THEN
             Exit;

          IF (Pass = 1) AND (NOT HasTitle) THEN
          BEGIN
               WriteLn (Ref,'Warning: No title found');
               Inc (Warnings);
          END;

          HasTitle:=FALSE;

          IF (Pass = 1) THEN
          BEGIN
               Inc (TopicNr,1);
               IF (NOT CreateTopic (TopicNr,Arg)) THEN
               BEGIN
                    WriteLn (Ref,'Fatal: Duplicate topic found: ',Arg);
                    Fatal:=TRUE;
                    Exit;
               END;
          END;

          IF (Pass = 2) THEN
          BEGIN
               IF (NOT GetTopicNrByRefStr (Arg,TopicNr)) THEN
                  Exit;

               SetTopicOffset (TopicNr,FileSize (HlpFile));

               IF (NOT LastWasBreak) THEN
                  AddToOutput (#10);

               AddToOutput (#255+ccSubTopic+
                            Long2HexString (TopicNr));

               LastWasBreak:=TRUE;
          END;
     END;

     IF (Keyword = 'END') THEN
     BEGIN
          Known:=TRUE;

          IF (Pass = 1) AND (NOT HasTitle) THEN
          BEGIN
               WriteLn (Ref,'Warning: No title found');
               Inc (Warnings);
          END;

          IF (NOT InBlock) THEN
          BEGIN
               WriteLn (Ref,'Fatal: Found lonely #END');
               Fatal:=TRUE;
               Exit;
          END;

          InBlock:=FALSE;

          IF (Pass = 2) THEN
          BEGIN
               { finish topic }
               AddToOutput (#0);
          END;
     END;

     IF (Keyword = 'BREAK') THEN
     BEGIN
          Known:=TRUE;

          IF (Pass = 2) THEN
             AddToOutput (#10);
     END;

     IF (Keyword = 'LINEBREAK') THEN
     BEGIN
          Known:=TRUE;

          IF (Pass = 2) THEN
             AddToOutput (#13);
     END;

     IF (Keyword = 'LINK') THEN
     BEGIN
          Known:=TRUE;

          IF (Pass = 2) THEN
          BEGIN
               IF (NOT GetArgument) THEN
                  Exit;

               IF (NOT GetTopicNrByRefStr (Arg,TopicNr)) THEN
                  Exit;

               IF (NOT GetArgument) THEN
                  Exit;

               AddToOutput (#255+ccLink+
                            Long2HexString (TopicNr)+
                            Arg+
                            #255+ccNormal);
          END;
     END;

     IF (Keyword = 'HIGHLIGHT') OR (Keyword = 'HL') THEN
     BEGIN
          Known:=TRUE;

          IF (Pass = 2) THEN
          BEGIN
               IF (NOT GetArgument) THEN
                  Exit;

               AddToOutput (#255+ccHighlight+Arg+#255+ccNormal);
          END;
     END;

     IF (Keyword = 'TITLE') THEN
     BEGIN
          Known:=TRUE;
          HasTitle:=TRUE;

          IF (Pass = 2) THEN
          BEGIN
               IF (NOT GetArgument) THEN
                  Exit;

               IF (NOT LastWasBreak) THEN
                  AddToOutput (#10);

               AddToOutput (#255+ccTitle+Arg+#255+ccNormal+#10);
          END;
     END;

     IF (NOT Known) THEN
     BEGIN
          WriteLn (Ref,'Unknown keyword "'+Keyword+'"');
          Fatal:=TRUE;
          Exit;
     END;

     { return the rest - needed for #LINK }
     HandleKeyword:=Regel;
END;


{--------------------------------------------------------------------------}
{ ProcessTextFile                                                          }
{                                                                          }
{ This routine processes the entire input file. It actually does this      }
{ twice and the Pass variable indicates which run this is.                 }
{ The input file is opened and closed by this file.                        }
{ The first time, the HLPNAME and INCNAME are processed and the output     }
{ files created. The TOPIC and SUBTOPIC keywords are processed and topics  }
{ created that later can be referred to.                                   }
{                                                                          }
PROCEDURE ProcessTextFile (Filename : STRING);

VAR TextRegel : STRING;
    TextFile  : TEXT;
    IORes     : BYTE;
    P         : BYTE;
    OrigRegel,
    UpRegel   : STRING;
    LineNr    : WORD;
    Ref       : STRING;

BEGIN
     IF Fatal THEN
        Exit;

     Filename:=LoCaseString (Filename);

     Assign (TextFile,HelpPath+Filename);
     {$I-} Reset (TextFile); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          WriteLn ('Fatal: Failed to open ',HelpPath+Filename,' (error ',IORes,')');
          Fatal:=TRUE;
          Exit;
     END;

     IF (Pass = 1) THEN
        WriteLn ('Reading ',Filename);

     LineNr:=0;
     InBlock:=FALSE;
     WHILE (NOT Eof (TextFile)) DO
     BEGIN
          IF Fatal THEN
             Exit;

          ReadLn (TextFile,TextRegel);
          Inc (LineNr);
          OrigRegel:=TextRegel;

          TextRegel:=CleanTabs (TextRegel,1);
          TextRegel:=DeleteBackSpaces (TextRegel);

          IF (TextRegel = '') AND InBlock THEN
             TextRegel:='#break';

          IF (TextRegel <> '') THEN
          BEGIN
               IF (TextRegel[1] = ';') THEN
                  Continue;

               IF (TextRegel[1] = '#') THEN
               BEGIN
                    Ref:='('+Filename+':'+Word2String (LineNr)+') ';
                    TextRegel:=HandleKeyword (TextRegel,OrigRegel,Ref);
                    IF (TextRegel = '') THEN
                       Continue;
               END ELSE
                   IF (TextRegel[1] = ' ') AND (NOT LastWasBreak) THEN
                   BEGIN
                        Ref:='('+Filename+':'+Word2String (LineNr)+') ';
                        HandleKeyword ('#linebreak',OrigRegel,Ref);
                   END ELSE
                       IF (NOT LastWasBreak) THEN
                          TextRegel:=' '+TextRegel; { continuation line }
          END;

          { not a comment line or a line starting with keyword }
          IF (Pass = 2) AND InBlock THEN
          BEGIN
               { is already deletebackspace'd }
               {TextRegel:=TextRegel+' ';}

               WHILE (TextRegel <> '') DO
               BEGIN
                    UpRegel:=UpCaseString (TextRegel);

                    P:=Pos ('#LINK(',UpRegel);
                    IF (P = 0) THEN
                       P:=Pos ('#HL(',UpRegel);
                    IF (P = 0) THEN
                       P:=Pos ('#HIGHLIGHT(',UpRegel);

                    IF (P > 0) THEN
                    BEGIN
                         AddToOutput (Copy (TextRegel,1,P-1));
                         Delete (TextRegel,1,P-1);
                         Ref:='('+Filename+':'+Word2String (LineNr)+') ';
                         TextRegel:=HandleKeyword (TextRegel,OrigRegel,Ref);
                         {AddToOutput (TextRegel);}
                    END ELSE
                    BEGIN
                         AddToOutput (TextRegel);
                         TextRegel:='';
                    END;
               END; { while }
          END; { if }

     END; { while }

     { nu moet het laatste block afgesloten zijn en kan de null-handle }
     { toegevoegd worden aan de index tabel.                           }
     IF InBlock THEN
     BEGIN
          WriteLn ('Warning: Last block not closed with a #END');
          Inc (Warnings);
     END;

     Close (TextFile);
END;


{--------------------------------------------------------------------------}
{ CreateTopicIndex                                                         }
{                                                                          }
{ This routine creates and writes the topic index to the help file.        }
{                                                                          }
PROCEDURE CreateTopicIndex;

VAR TopicPtr   : TopicRecordPtr;
    HelpRec    : HelpIndexRecord;
    TopicCount : WORD;

BEGIN
     IF Fatal THEN
        Exit;

     IF (NOT HlpIsOpen) THEN
     BEGIN
          WriteLn ('Missing HLPNAME keyword');
          Fatal:=TRUE;
          Exit;
     END;

     IF (FileSize (HlpFile) <> 24) THEN
     BEGIN
          WriteLn ('CreateTopicIndex: Invalid header length');
          Halt;
     END;

     TopicCount:=0;

     TopicPtr:=FirstTopicPtr;
     WHILE (TopicPtr <> NIL) DO
     BEGIN
          TopicPtr^.IndexPos:=FilePos (HlpFile);

          HelpRec.TopicNr:=TopicPtr^.TopicNr;
          HelpRec.Offset:=0;
          BlockWrite (HlpFile,HelpRec,SizeOf (HelpIndexRecord));
          Inc (TopicCount);

          TopicPtr:=TopicPtr^.NextTopicPtr;
     END;

     { add one more to indicate end of index }
     HelpRec.TopicNr:=0;
     HelpRec.Offset:=0;
     BlockWrite (HlpFile,HelpRec,SizeOf (HelpIndexRecord));

     WriteLn (TopicCount,' topics');
END;


{--------------------------------------------------------------------------}
{ main                                                                     }
{                                                                          }

VAR TextFilename : STRING[79];

BEGIN
     WriteLn ('RHFC v2.2');
     WriteLn ('Copyright (c) Ramon van der Winkel 1993-1999');

     IF (ParamCount <> 1) THEN
     BEGIN
          WriteLn;
          WriteLn ('Usage: RHFC <text helpfile name>');
          Halt;
     END;

     TextFilename:=UpcaseString (UNC_FExpand (ParamStr (1)));

     HelpPath:=LoCaseString (TextFilename);
     WHILE (HelpPath <> '') AND (HelpPath[Length (HelpPath)] <> '\') DO
           Delete (HelpPath,Length (HelpPath),1);

     WHILE (Pos ('\',TextFilename) > 0) DO
           Delete (TextFilename,1,Pos ('\',TextFilename));

     FirstTopicPtr:=NIL;
     LastTopicPtr:=NIL;
     HlpIsOpen:=FALSE;
     IncIsOpen:=FALSE;
     IncFileCRC:=$FFFFFFFF;
     Fatal:=FALSE;
     Warnings:=0;

     WriteLn;
     WriteLn ('First pass...');
     Pass:=1;
     LastWasBreak:=FALSE;
     ProcessTextFile (TextFilename);

     IF (NOT Fatal) AND (Warnings > 0) THEN
        WriteLn (Warnings,' warnings');

     CreateTopicIndex;

     WriteLn;
     WriteLn ('Second pass...');
     Pass:=2;
     LastWasBreak:=FALSE;
     ProcessTextFile (TextFilename);

     IF Fatal THEN
     BEGIN
          IF HlpIsOpen THEN
          BEGIN
               Close (HlpFile);
               Erase (HlpFile);
          END;

          IF IncIsOpen THEN
          BEGIN
               Close (IncFile);
               Erase (IncFile);
          END;
     END ELSE
     BEGIN
          IF IncIsOpen THEN
          BEGIN
               WriteLn (IncFile);
               WriteLn (IncFile,'CONST HTR_HELP_VERSION_CRC : LONGINT = $'+Long2HexString (IncFileCRC)+';');
               WriteLn (IncFile);
               WriteLn (IncFile,'{ end of file }');
               Close (IncFile);

               { update the CRC in the help file }
               IF (HlpIsOpen) THEN
               BEGIN
                    Seek (HlpFile,20);
                    BlockWrite (HlpFile,IncFileCRC,4);
               END;
          END;

          IF HlpIsOpen THEN
             Close (HlpFile);
     END;

     DestroyTopicList;

     WriteLn ('Done');
     WriteLn;
END.

