home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / programming / misc_programming / inthelp.arj / INTHELP.PAS < prev    next >
Pascal/Delphi Source File  |  1991-10-26  |  20KB  |  467 lines

  1. Program IntHelp;
  2.  
  3. uses GLOBAL, OPSTRING, OPROOT, UserInterFace;
  4. var
  5.     {First of all some general (mostly dummy) variables}
  6.   DummyStr, InputF,
  7.   OutputF         : String;
  8.   DummyLst        : SingleListPtr;
  9.   DummyInt        : Integer;
  10.   DummyNode,
  11.   DummyNode2      : IntDataPtr;
  12.   DummyBool, InINT: Boolean;
  13.   Counter, CurInt : Byte;
  14.   LineCount       : LongInt;
  15.   LastTopic       : Word;
  16.   OutFile, InFile : Text;
  17.  
  18.     {We use the following datastructure to keep the information about the
  19.      INT's (in order to be able to X-reference) : 
  20.      1. an array (IntArray) containing (per INT number) a list of items 
  21.         (different values of registers, ... for the same INT) ;
  22.      2. a list (IntList) containing all the items in the same order as
  23.         they were encountered in the inputfile.
  24.  
  25.      Remark : In fact there is one long list (IntList) and the array 
  26.               (IntArray) contains pointers, pointing into this one list.}
  27.  
  28.   IntArray        : Array[0..255] of SingleListPtr;
  29.   IntList         : SingleListPtr;
  30.  
  31.   {--------------------------------------------------------------------}
  32.   function SeeAlso(InThe : String):SingleListPtr;
  33.    {InThe is supposed to be a string with X-references to other INT items.
  34.     This X-references should obey the syntax rules of the Ralph Brown
  35.     INT list of 1/5/91. The code should be changed according to changes
  36.     of these rules
  37.  
  38.     The result of this function is a list containing the X-refs in a
  39.     'formal' way (a record).
  40.  
  41.     X-references are supposed to be separated by a comma.  Each X-ref is
  42.     called 'Item' in this function                                       }
  43.  
  44.  
  45.   const
  46.     Laatste : Byte = Byte(InThe[0]);
  47.                               {Index of the last character in 'InThe'}
  48.   var
  49.     Result      : SingleListPtr;
  50.     TempNode,                 {Dummy, used when copying last node}
  51.     DummyNode   : IntDataPtr; {'Running' node to find Result}
  52.     ItemNr,                   {Sequence number of Item}
  53.     NextOne     : Byte;       {Sequence number of next part in item}
  54.     LastName,                 {Name of last part that has been dealt with}
  55.     Name        : String[2];  {Name of part that is being dealt with}
  56.     Item, Value,              {Item which is to be (or being) dealt with and 
  57.                               value of current subpart}
  58.     Main, Sub1,
  59.     Sub2        : String;     {Subparts of the item that is being dealt with}
  60.     {------------------------------------------------------------------}
  61.     procedure FillDummy (Name, Value : String);
  62.       {This procedure is rather self-explanatory}
  63.     begin
  64.       if Name = 'AX' then
  65.         DummyNode^.AX := Value
  66.       else
  67.         if Name = 'AH' then
  68.           DummyNode^.AX := Value + '00'
  69.         else
  70.           if Name = 'AL' then
  71.             DummyNode^.AX := '00' + Value
  72.           else begin
  73.             DummyNode^.Other.Name  := Name;
  74.             if Length (Value) = 2 then
  75.               DummyNode^.Other.Value := Value + '  '
  76.             else
  77.               DummyNode^.Other.Value := Value;
  78.           end{if};
  79.     end{FillDummy};
  80.     {------------------------------------------------------------------}
  81.   begin
  82.   {Initialization part}
  83.     New(Result, Init);
  84.     ItemNr   := 1 ;          {start with the first item}
  85.     LastName := '';          {we haven't dealt with items yet, so we 
  86.                               haven't got a name to remember either.
  87.  
  88.                               Get the first item                       }
  89.     Item := Trim (ExtractWord (ItemNr, InThe, [',']));
  90.     while Item <> '' do begin   {While there are still items in 'InThe'}
  91.       New (DummyNode, Init);    {Initialize a dummy node}
  92.       DummyNode^.Text := ExtractWord (2, Item, ['"']);
  93.                                 {Each item can consist of 3 parts, so 
  94.                                 get these parts                       }
  95.       Main := Trim (ExtractWord (1, Item, ['/']));
  96.       Sub1 := Trim (ExtractWord (2, Item, ['/']));
  97.       Sub2 := Trim (ExtractWord (3, Item, ['/']));
  98.  
  99.       {Deal with the main part (which certainly exists)}
  100.  
  101.       if Main[1] = 'I' then begin
  102.                                 {Main == 'INT ##' and it is followed by
  103.                                 a space or a quote                    }
  104.         DummyNode^.INT := ExtractWord (2, Main, [' ','"']);
  105.         LastName       := '';   {No name to recall                     } 
  106.       end else begin            {if it's not 'INT ......'              }
  107.             if WordCount (Main, ['=']) = 1 then begin
  108.                                 {No name given for the main part, so 
  109.                                 the name is 'inherited' from the previous
  110.                                 Item                                  }
  111.               Name     := LastName;
  112.               NextOne  := 1;
  113.               TempNode := IntDataPtr (Result^.Tail);
  114.                                 {Almost all the values must be copied
  115.                                 from the last X-ref                   }
  116.               DummyNode^.INT        := TempNode^.INT;
  117.               DummyNode^.AX         := TempNode^.AX;
  118.               DummyNode^.Other.Name := TempNode^.Other.Name;
  119.             end else begin      {Jot down the new name for main element}
  120.               Name     := Trim (ExtractWord (1, Main, ['=']));
  121.               LastName := Name;
  122.               NextOne  := 2;
  123.             end{if};
  124.             {Find the value of the main element (when it's not INT)    }
  125.             Value := Trim (ExtractWord (NextOne, Main, ['h','"','=']));
  126.             {And finally note the name and value of the main part      }
  127.             FillDummy (Name, Value);
  128.       end{if};
  129.  
  130.       {Deal with the second part, if present}
  131.  
  132.       if Sub1 <> '' then begin
  133.         Name     := Trim (ExtractWord (1, Sub1, ['=']));
  134.         Value    := Trim (ExtractWord (2, Sub1, ['=','h','"']));
  135.         LastName := Name;
  136.         FillDummy (Name, Value);
  137.       end{if};
  138.  
  139.       {And finally the third part, if present}
  140.  
  141.       if Sub2 <> '' then begin
  142.         DummyNode^.Other.Name  := Trim (ExtractWord (1, Sub2, ['=']));
  143.         DummyNode^.Other.Value := Trim (ExtractWord (2, Sub2, ['=','"','h']));
  144.       end{if};
  145.  
  146.       Result^.Append (SingleNodePtr (DummyNode));
  147.       Inc(ItemNr);              {Get the following X-ref}
  148.       Item := Trim (ExtractWord (ItemNr, InThe, [',']));
  149.     end{while};
  150.     SeeAlso := Result;
  151.   end{SeeAlso};
  152.   {--------------------------------------------------------------------}
  153.   function Parse  (INT : String):IntDataPtr;
  154.     {Interprets the 'useful' part of the line containing information
  155.      about the following INT item (the line starting with '----------'
  156.      and returns that information in a record (pointer to a ...)}
  157.   var
  158.     Result       : IntDataPtr;
  159.     AH, AL, Name : String[2];
  160.     Value        : String;
  161.   begin
  162.     New (Result, Init);
  163.  
  164.       {Determine the value of AX, supposing that no value will be given
  165.       to AL without supplying a value for AH (Ralph ?)                }
  166.  
  167.     if INT[13] = '-' then begin {if AH isn't supplied then             }
  168.       AH := '  ';               {  it's value is empty                 }
  169.       AL := '  ';               {  and so is AL's                      }
  170.     end else begin              {Otherwise                             }
  171.       AH := INT[13] + INT[14];  {  take note of its value and          }
  172.       if INT[15] <> '-' then    {  see if AL has been specified        }
  173.         AL := INT[15] + INT[16] {    if so : take note of its value    }
  174.       else
  175.         AL := '00';             {    else give it a '00' value         }
  176.     end{if};
  177.  
  178.       {If applicable : take note of the name and type of other register}
  179.  
  180.     if INT[17] <> '-' then begin{if another register has been specified}
  181.       Name := INT[17] + INT[18];{  Note name and value                 }
  182.       if INT[21] = '-' then begin
  183.                                 {If the value has only two figures then}
  184.         Value := INT[19] + INT[20];         {- jot down the value      }
  185.         if (Name = 'AL') then begin         {- and if it's al then :   }
  186.           AL    := INT[19] + INT[20];       {  * note the value in AL  }
  187.           Name  := '  ';                    {  * and strike out the    }
  188.           Value := '   ';                   {    noted name and value  }
  189.           if AH = '  ' then                 {  * change AH if necessary}
  190.             AH := '00';
  191.         end{if};
  192.       end else                              {it's a 4 character value  }
  193.         Value := INT[19] + INT[20] + INT[21] + INT[22];
  194.     end else begin
  195.       Name  := '  ';                        {no supplemental register  }
  196.       Value := '    ';
  197.     end{if};
  198.  
  199.       {Finally construct the 'Result' from what we've found}
  200.  
  201.     Result^.INT := INT[11] + INT[12];
  202.     Result^.AX  := AH + AL;
  203.     Result^.Other.Name  := Name;
  204.     Result^.Other.Value := Value;
  205.  
  206.     Parse := Result;
  207.   end{Parse};
  208.  
  209.   {--------------------------------------------------------------------}
  210.  
  211.   function Topic (TheItem : IntDataPtr;
  212.                   InThe   : SingleListPtr):Word;
  213.     {Result : the topic number of 'TheItem' if 'TheItem' can be found
  214.               in 'InThe'. Else returns 0}
  215.   var
  216.     TheNode  : IntDataPtr;
  217.     NotFound : Boolean;
  218.     {------------------------------------------------------------------}
  219.     function IsPartOf (TheOne, TheOther : IntDataPtr):Boolean;
  220.       {Returns TRUE if the register information of TheOne is equal to 
  221.       that of TheOther and if the Text information of TheOne is part of
  222.       the Text information of TheOther}
  223.     var
  224.       Result : Boolean;
  225.     begin
  226.       Result := ((TheOne^.AX = TheOther^.AX) and
  227.                 (TheOne^.Other.Name = TheOther^.Other.Name) and
  228.                 (TheOne^.Other.Value = TheOther^.Other.Value));
  229.       if Length (TheOne^.Text) <> 0 then
  230.         Result := (Result and
  231.                   (Search (TheOther^.Text[1], Length (TheOther^.Text),
  232.                           TheOne^.Text[1], Length (TheOne^.Text)) <> $FFFF));
  233.       IsPartOf := Result;
  234.     end;{IsPartOf}
  235.     {------------------------------------------------------------------}
  236.   begin
  237.     NotFound := True;
  238.     TheNode  := IntDataPtr (InThe^.Head);
  239.     while ((TheNode <> nil) and NotFound) do begin
  240.       NotFound := (not IsPartOf (TheItem, TheNode));
  241.       if NotFound then
  242.         TheNode := IntDataPtr (InThe^.Next (TheNode));
  243.     end{while};
  244.     if NotFound then
  245.       Topic := 0
  246.     else
  247.       Topic := TheNode^.Topic;
  248.   end{Topic};
  249.   {--------------------------------------------------------------------}
  250.   procedure GetLine (var TheLine : String);
  251.     {Reads one line from the inputfile into 'TheLine'}
  252.   begin
  253.     ReadLn (InFile, TheLine);
  254.       {The two following commands are included merely to allow you to
  255.        signal the user what we're doing}
  256.     Inc(LineCount);
  257.     PutLineNumber (LineCount);
  258.   end{GetLine};
  259.   {------------------------------------------------------------------}
  260.   function IsINT (TheLine : String): Boolean;
  261.     {Returns TRUE if 'TheLine' as a string indicating the start of 
  262.      information about a new interrupt item (i.e. '----------XX........')
  263.      where XX stands for the hexadecimal INT number}
  264.   begin
  265.     IsINT := ((Length(TheLine) <> 0) and
  266.               (ExtractWord (1, DummyStr, ['0','1','2','3','4','5','6','7',
  267.                                           '8','9','A','B','C','D','E','F'])
  268.                             = '----------'));
  269.   end{IsINT};
  270.   {------------------------------------------------------------------}
  271.   procedure Initialize;
  272.                   {Initialize everything}
  273.   begin
  274.     GetFileNames (InputF, OutputF);
  275.     Assign (InFile, InputF);
  276.     Assign (OutFile, OutputF);
  277.     Reset(InFile);
  278.     Rewrite(OutFile);
  279.     LastTopic := 0;
  280.     LineCount := 0;
  281.     CurInt    := 255;
  282.       {OK, I lied. I'm not really treating INT FF, so what ?}
  283.     for Counter := 0 to 255 do
  284.       New (IntArray[Counter], Init);
  285.     New (IntList, Init);
  286.       {Signal to 'UserInterface' that we're about to start}
  287.     StartPass1;
  288.       {Write the first (formatting) information to the output file}
  289.     writeln(OutFile, '!WIDTH 76');
  290.     writeln(OutFile, '!NOWRAP');
  291.   end{Initialize};
  292.   {------------------------------------------------------------------}
  293.   function MakeHeader (ForNode : IntDataPtr):String;
  294.     {Returns a string which can be used as a header for the help window
  295.      for the item to wich ForNode points : 
  296.         INT = xx / yy = zz
  297.      where xx stands for the INT number, yy optionally stands for an 
  298.      additional register name and zz for the value of that register}
  299.   var
  300.     Result : String;
  301.   begin
  302.     Result := 'INT = ' + ForNode^.INT;
  303.     if ForNode^.AX <> '    ' then
  304.       Result := Result + ' / AX = ' + ForNode^.AX;
  305.     if ForNode^.Other.Name <> '  ' then
  306.       Result := Result + ' / ' + ForNode^.Other.Name + ' = '
  307.                        + ForNode^.Other.Value;
  308.     MakeHeader := Result;
  309.   end{MakeHeader};
  310.   {------------------------------------------------------------------}
  311.   procedure BuildIntList;
  312.     {During a first pass through the input file, IntList and IntArray
  313.      are filled with the necessary data about the interrupts to be able
  314.      to X-reference the help file (i.e. implement the 'See Also : ...')}
  315.  
  316.     {After this routine, the input file has been 'rewound' and is ready
  317.      to be read again}
  318.   begin
  319.     while not EOF (InFile) do begin
  320.       GetLine (DummyStr);
  321.       if IsINT(DummyStr) then begin     {if it's an 'INT' line}
  322.         Inc (LastTopic);                { then get a new topic number       }
  323.         DummyNode := Parse (DummyStr);  {      get the data from that line  }
  324.         DummyNode^.Topic := LastTopic;  {      note down the topic number   }
  325.         GetLine (DummyStr);             {      read the line with additional
  326.                                                data and take note of this 
  327.                                                data                         }
  328.         for Counter := 10 to Length (DummyStr) do
  329.           DummyNode^.Text[Counter - 9] := DummyStr[Counter];
  330.         DummyNode^.Text[0] := Chr (Counter - 9);
  331.                                         {      Finally append the node to 
  332.                                                the appropriate list(s)      }
  333.         if Str2Int ('$'+DummyNode^.INT, DummyInt) then begin
  334.           IntArray[DummyInt]^.Append (SingleNodePtr (DummyNode));
  335.           IntList^.Append (SingleNodePtr (IntArray[DummyInt]^.Tail));
  336.         end else                        {if Ralph changes his 'syntax' !!   }
  337.           writeln ('Error on line ',LineCount:1);
  338.       end{if};
  339.     end{while};
  340.                                         {'Rewind' the input file            }
  341.     Reset (InFile);
  342.     LineCount := 0;
  343.   end{BuildIntList};
  344.   {------------------------------------------------------------------}
  345.   procedure TreatSeeAlso (TheItem : String);
  346.     {TheItem is supposed to be the string that follows a 'See Also :'
  347.  
  348.      This procedure will take 'TheItem' (in fact a X-reference list) and
  349.      write into the outputfile the code necessary to implement this
  350.      'SEE ALSO' X-referencing in the help system                     }
  351.   var
  352.     SeeList : SingleListPtr;
  353.     TheNode : IntDataPtr;
  354.     INTNr   : Integer;
  355.     DBool   : Boolean;
  356.     Text    : String;
  357.   begin
  358.     writeln (OutFile, 'SeeAlso : ');
  359.     SeeList := SeeAlso (TheItem);   {Construct a X-ref list}
  360.     TheNode := IntDataPtr (SeeList^.Head);
  361.     while TheNode <> nil do begin
  362.       {Write the necessary code into the outputfile per X-ref}
  363.       if TheNode^.INT = '  ' then begin
  364.         INTNr := Integer (CurInt);  {No INT number given, meaning the}
  365.         Text  := '';                {number hasn't changed           }
  366.       end else begin
  367.         DBool := Str2Int ('$'+TheNode^.INT, INTNr);
  368.         Text  := 'INT ' + TheNode^.INT;
  369.       end{if};
  370.       if TheNode^.AX <> '    ' then
  371.         Text := Text + ' AX=' + TheNode^.AX;
  372.       if TheNode^.Other.Name <> '  ' then
  373.         Text := Text + ' ' + TheNode^.Other.Name + '=' + TheNode^.Other.Value;
  374.       Text := Trim (Text + ' ' + TheNode^.Text);
  375.       writeln (OutFile, '  ',Chr(4), Topic (TheNode, INTArray[INTNr]):1,
  376.                              Chr(5), Detab (Text,8), Chr(5));
  377.       TheNode := IntDataPtr (SeeList^.Next (SingleNodePtr (TheNode)));
  378.     end{while};
  379.   end{TreatSeeAlso};
  380.   {------------------------------------------------------------------}
  381.   procedure TakeNote (StartingWith : String);
  382.     {Writes the necessary code to 'highlight' the part of 'StartingWith'
  383.      that comes before a colon in that string                         }
  384.   var
  385.     Temp  : String;
  386.     Count : Byte;
  387.   begin
  388.     Temp := ExtractWord (1, StartingWith, [':']);
  389.     write   (OutFile, Chr(1));
  390.     Insert  (Chr(1), StartingWith, Length (Temp) + 1);
  391.     writeln (OutFile, Detab (StartingWith, 8));
  392.   end{TakeNote};
  393.   {------------------------------------------------------------------}
  394.  
  395. begin
  396.   Initialize;
  397.   BuildIntList;
  398.   StartPass2;
  399.   DummyNode := IntDataPtr (IntList^.Head);
  400.     {From here on, DummyNode is the following node to be dealt with}
  401.   DummyStr := '';
  402.     {Skip introductory text in the input file}
  403.   while ((not IsINT (DummyStr)) and (not EOF (InFile))) do
  404.     GetLine (DummyStr);
  405.  
  406.   InINT := True;  {We are working with INT data in the input file}
  407.   while not EOF (InFile) do begin
  408.     if IsINT (DummyStr) then begin
  409.       {If this line starts a new INT item}
  410.       DummyBool := Str2Int ('$' + DummyNode^.INT, DummyINT);
  411.       if (DummyINT <> CurINT) then begin
  412.         {If it's a new INT number, we have to create a new main TOPIC in the
  413.          output file                                                        }
  414.         CurINT := DummyINT;
  415.         Inc (LastTopic);
  416.         writeln (OutFile, '!TOPIC ',LastTopic:1,' INT ',DummyNode^.INT);
  417.         writeln (OutFile, '!INDEX ',CurINT:1);
  418.         DummyNode2 := IntDataPtr (IntArray[CurInt]^.Head);
  419.         for DummyInt := 1 to IntArray[CurInt]^.Size do begin
  420.           write (OutFile, Chr(4), DummyNode2^.Topic:1, Chr(5));
  421.           if DummyNode2^.AX <> '    ' then
  422.             write (OutFile, 'AX=', DummyNode2^.AX, ' ');
  423.           if DummyNode2^.Other.Name <> '  ' then
  424.             write (OutFile, DummyNode2^.Other.Name,'=',DummyNode2^.Other.Value,' ');
  425.           if DummyNode2^.Text <> '' then
  426.             write (OutFile, Detab (DummyNode2^.Text,8), ' ');
  427.           writeln (OutFile, Chr(5));
  428.           DummyNode2 := IntDataPtr (IntArray[CurInt]^.Next
  429.                                          (SingleNodePtr (DummyNode2)));
  430.         end{for};
  431.       end{if};
  432.         {We always have to make a TOPIC for this INT itself}
  433.       writeln (OutFile, '!TOPIC ',DummyNode^.Topic:1,' ', MakeHeader (DummyNode));
  434.       writeln (OutFile, '!NOINDEX');
  435.         {Write an appropriate header}
  436.       writeln (OutFile, Detab (Dummynode^.Text, 8));
  437.         {Read the supplementary data (which is useless during this pass}
  438.       GetLine (DummyStr);
  439.       DummyNode := IntDataPtr (IntList^.Next (SingleNodePtr (DummyNode)));
  440.     end else
  441.       {if it's a X-Ref string}
  442.       if Pos ('SeeAlso:', DummyStr) <> 0 then
  443.         TreatSeeAlso (TrimSpaces (ExtractWord (2, DummyStr, [':'])))
  444.       else
  445.         {if it's a 'note'}
  446.         if Pos ('Note', DummyStr) = 1 then
  447.           TakeNote (DummyStr)
  448.         else {no INT, no SeeAlso, no Notes, just plain text}
  449.           writeln (OutFile, Detab (DummyStr, 8));
  450.     GetLine (DummyStr);
  451.     InINT := (DummyStr <> '---------------------------------------------');
  452.       {I have noticed that plain text, containing no information whatsoever
  453.        about INTs is separated from the 'useful' information by a line
  454.        filled with '-'.
  455.  
  456.        If such a line is encountered, skip everything until the EOF is
  457.        or a new INTline is encountered}
  458.     while (not InINT) and (not EOF (InFile)) do begin
  459.       GetLine (DummyStr);
  460.       InINT := IsINT (DummyStr);
  461.     end{while};
  462.     {end if}
  463.   end{while};
  464.   Dec(LastTopic);
  465.   UserInterface.Finished(LastTopic);
  466. end{IntHelp}.
  467.