home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / perqb / pq2mbu.pas < prev    next >
Pascal/Delphi Source File  |  2020-01-01  |  10KB  |  361 lines

  1. program MenuBuild;
  2.  
  3. imports MenuUtils from MenuUtils;
  4. imports Memory from Memory;
  5. imports System from System;
  6. imports FileSystem from FileSystem;
  7. imports CmdParse from CmdParse;
  8. imports Perq_String from Perq_String;
  9.  
  10. { Abstract:  This program build a menu structure in a user defined 
  11.   data segment.  The data segment is written to a user specified
  12.   .MSEG file.
  13.   Such .MSEG files may subsequently be utilized by the MenuUtils.GetMenu
  14.   procedure to load the menues for a given application in a high-speed 
  15.   fashion.  ( Using MultiRead. )
  16.   
  17.   In parallel with the generation of the data segment, a .HLP-file is 
  18.   generated, which will contain the helptext from the menu text file.
  19.   The .MSEG-file will contain blocknumbers referencing this .HLP-file,
  20.   and the .HLP-file will NOT be loaded when the menues are loaded by the
  21.   application, just read for the wanted information when HELP is requested
  22.   from any menu.
  23.  
  24.   Usage:  BuildMenu <input .MENU file> 
  25.                         [~ <output .MSEG file>[,<output .HLP file ]
  26.  
  27. }
  28.  
  29. exception FullMenuSeg;  {   Will be raised if menu structure needs more than 
  30.                             32 K words }     
  31. exception InvHelpFile;  { Will be raised if any of the filenames given }
  32. exception InvSegFile;   { are invalid  (or nonexistent input file) }
  33. exception InvMenuFile;
  34.  
  35. exception BadArgs;
  36.  
  37. VAR
  38.     Root                : pMenuEntry;
  39.     Mnu, MSeg, Help     : PathName;
  40.     Comm                : CString;
  41.     IsSwitch            : Boolean;
  42.     Inputs, Outputs     : pArgRec;
  43.     Switches            : pSwitchRec;
  44.     Err                 : String;
  45.     Sep                 : Char;
  46.  
  47. procedure   MakeMenues( MenuFName, SegFName, HelpFName : PathName );
  48.  
  49. VAR MenuFile    : Text;
  50.     SegF,HelpF  : FileID; 
  51.     Blk, Bits   : Integer;
  52.     Line        : String;
  53.     LineNo      : Integer;
  54.     Indent      : Integer;
  55.     ShowMenues  : boolean;
  56.  
  57.     HelpFree    : HelpAddress;
  58.  
  59.     MenuSeg     : SegmentNumber;
  60.     FreePtr     : MMPointer;
  61.  
  62.     DiskBuff    : pDirBlk;
  63.  
  64.  
  65.     procedure WriteSegment(     SegFName:   PathName; 
  66.                                 EndPtr:     MMPointer);
  67.     var NumBlocks, i    : integer;
  68.         SegF            : FileID;
  69.     begin
  70.         NumBlocks := (EndPtr.Offset+255) div 256;
  71.         SegF := FSEnter( SegFName );
  72.         if SegF=0 then raise InvSegFile;
  73.         for i := 0 to NumBlocks -1 do
  74.             FSBlkWrite( SegF, i, MakePtr( EndPtr.Segmen, i*256, pDirBlk ));
  75.         FSClose( SegF, NumBlocks, (EndPtr.Offset mod 256)*16 );
  76.     end; 
  77.  
  78.  
  79.     procedure CreateHelpFile( HelpFName: PathName );
  80.     begin
  81.         HelpF := FSEnter( HelpFName );
  82.         if HelpF=0 then raise InvHelpFile;
  83.         with HelpFree do begin
  84.             BlockNo := 0;
  85.             Offset := 0;
  86.         end;
  87.         new( DiskBuff );
  88.     end;
  89.     
  90.     procedure PutInBuffer( c : char );
  91.     begin
  92.         with HelpFree do begin
  93.             DiskBuff^.ByteBuffer[ Offset ] := ord(c);
  94.             Offset := Offset + 1;
  95.             if Offset>511 then begin
  96.                 FSBlkWrite( HelpF, BlockNo, DiskBuff );
  97.                 Offset := 0;
  98.                 BlockNo := BlockNo + 1;
  99.             end;
  100.         end;
  101.     end;
  102.  
  103.     procedure PutHelp( Txt : String );
  104.     var I:integer;
  105.     begin
  106.         for I := 1 to length( Txt ) do 
  107.             PutInBuffer( Txt[I]);
  108.         PutInBuffer( chr(13) );    
  109.     end;
  110.  
  111.  
  112.     procedure CloseHelpFile;
  113.     begin
  114.         with HelpFree do begin
  115.             if HelpFree.Offset>0 then begin { last buffer partially full }
  116.                 FSBlkWrite( HelpF, BlockNo, DiskBuff );
  117.                 FSClose( HelpF, BlockNo+1, Offset*8 );
  118.             end else                        { last buffer is empty }
  119.                 FSClose( HelpF, BlockNo, 0 );
  120.         end;
  121.     end;
  122.  
  123.    
  124.     procedure Allocate( s : integer );
  125.     begin
  126.         if (MMMaxExtSize div 2) > ((FreePtr.offset+S+255) div 256) then
  127.             FreePtr.Offset := FreePtr.Offset + S
  128.         else
  129.             raise FullMenuSeg;
  130.     end;
  131.  
  132.  
  133.     function NewMenuEntry( NType : NodeType; NumComm : integer ):pMenuEntry;
  134.     var ret     : pMenuEntry;
  135.         fixed   : integer;
  136.     begin
  137.         Fixed := WordSize( HelpAddress )+ 
  138.                         WordSize( String )+ WordSize( NodeType);
  139.         Ret := MakePtr( FreePtr.Segmen, FreePtr.Offset, pMenuEntry );
  140.         case NType of
  141.             ParmNode:   Allocate( Fixed );
  142.             EndNode :   Allocate( Fixed );
  143.             MenuNode:   Allocate( Fixed + WordSize( pNameDesc )
  144.                                   +  NumComm*WordSize( pMenuEntry ) );
  145.         end;
  146.         ret^.Node := NType;
  147.         NewMenuEntry := ret;
  148.     end;
  149.  
  150.  
  151.     function NewNameDesc( NumComm : integer ):pNameDesc;
  152.     var ret:pNameDesc;
  153.     begin
  154.         Ret := MakePtr( FreePtr.Segmen, FreePtr.Offset, pNameDesc );
  155.         Allocate( WordSize( Integer ) + (NumComm+1)*WordSize( S25 ) );
  156.         Ret^.NumCommands := NumComm;
  157.         NewNameDesc := ret;
  158.     end;
  159.                     
  160.  
  161.     function GetMenu : pMenuEntry;
  162.     VAR ME  : pMenuEntry;
  163.         NC  : integer;
  164.         CI  : integer;
  165.     begin
  166.         indent := indent+4;
  167.         readln( MenuFile, NC );
  168.         ReadLn( MenuFile, Line ); 
  169.  
  170.     { determine what kind of a node has been encountered }
  171.         if NC=0 then
  172.             ME := NewMenuEntry( EndNode, 0 ) 
  173.         else 
  174.         if NC<0 then
  175.             ME := NewMenuEntry( ParmNode, 0 ) 
  176.         else
  177.             ME := NewMenuEntry( MenuNode, NC+1 ); 
  178.  
  179.     
  180.     { build node }
  181.         with ME^ do begin
  182.             if Node=MenuNode then 
  183.             begin
  184.                 MPtr := NewNameDesc( NC+1 );
  185.                 if Line<>'>' then begin
  186.                     MPtr^.Header := Line;
  187.                     ReadLn( MenuFile, Line );
  188.                 end else
  189.                     MPtr^.Header := '';
  190.                 MPtr^.Commands[1] := 'HELP';   { Always a HELP entry }
  191.             end;
  192.             if Line<>'>' then begin
  193.                 Prompt := Line;
  194.                 ReadLn( MenuFile, Line );
  195.             end else
  196.                 Prompt := '';
  197.                 
  198.             Help := HelpFree;
  199.             while line<>'>' do begin
  200.                PutHelp( Line );
  201.                ReadLn( MenuFile, Line );
  202.             end;
  203.             PutHelp( Line );
  204.  
  205.             if Node=MenuNode then
  206.                 for CI := 2 to NC+1 do begin
  207.                     ReadLn( MenuFile, Line );
  208.                     if ShowMenues then
  209.                         writeln( '':indent, Line );
  210.                     {$range-}
  211.                     MPtr^.Commands[ CI ] := Line;
  212.                     NextLevel[ CI ] := GetMenu;
  213.                     {$range+}
  214.                 end;
  215.         end;
  216.             
  217.         GetMenu := ME;
  218.         Indent := Indent-4;
  219.     end;        
  220.         
  221.  
  222. begin
  223.             { Open menu source file }
  224.     if FSLookUp( MenuFName, Blk, Bits )=0 then
  225.         raise InvMenuFile
  226.     else begin
  227.         reset( MenuFile, MenuFName);
  228.  
  229.             { Allocate a BIG segment to build menues in }
  230.             { Use half of max. size to avoid trouble with }
  231.             { two's complement integer arithmetic }
  232.         CreateSegment( MenuSeg, MMMaxExtSize div 2, 1, MMMaxExtSize div 2 );
  233.         with FreePtr do begin
  234.             Offset := WordSize( Integer );
  235.             Segmen := MenuSeg;
  236.         end;
  237.  
  238.         CreateHelpFile( HelpFName );
  239.         LineNo := 0;
  240.         Indent := 0;
  241.         ReadLn( MenuFile, Line );
  242.         ShowMenues := Line<>'';
  243.  
  244.             { Now go for it!! }
  245.         Root := GetMenu;
  246.         CloseHelpFile;
  247.         WriteSegment( SegFName, FreePtr );
  248.     end;
  249. end;
  250.  
  251.  
  252. function StripOff( InStr, Tail : Pstring ):Pstring;
  253. { Strip <Tail> from <InStr> if the last characters of <InStr> matches <Tail> }
  254. var InL,TailL : integer;
  255.     T1, T2    : String;
  256. begin
  257.     InL := Length( InStr );
  258.     while InStr[InL]=' ' do begin
  259.         InL := InL - 1;
  260.         Adjust( InStr, InL );
  261.     end;
  262.     TailL := Length( Tail );
  263.     if TailL>InL then begin
  264.         StripOff := InStr
  265.     end else begin
  266.         T1 := SubStr( InStr,InL+1-TailL,TailL );
  267.         ConvUpper( T1 );
  268.         T2 := Tail;
  269.         ConvUpper( T2 );
  270.         if  T1=T2 then begin
  271.             StripOff := SubStr( InStr, 1, InL-TailL )
  272.         end else begin
  273.             StripOff := InStr;
  274.         end;
  275.     end;    
  276. end;
  277.  
  278.  
  279. procedure ParseArgs;
  280.  
  281.     handler InvMenuFile;
  282.     begin
  283.         writeln('Menu file: ',Mnu,' is invalid name or does not exist!');
  284.         exit( ParseArgs );
  285.     end;
  286.  
  287.     handler InvSegFile;
  288.     begin
  289.         writeln('Segment file name: ',Mseg,' is invalid name!');
  290.         exit( ParseArgs );
  291.     end;
  292.  
  293.     handler InvHelpFile;
  294.     begin
  295.         writeln('Help file name: ',Help,' is invalid name!');
  296.         exit( ParseArgs );
  297.     end;
  298.  
  299.     handler BadArgs;
  300.     begin
  301.         exit( ParseArgs );
  302.     end;
  303.  
  304. begin
  305.     Sep := NextId( Comm, isSwitch );
  306.     if ParseCmdArgs( Inputs, Outputs, Switches, Err )  then begin
  307.         Mnu := '';
  308.         Mseg := '';
  309.         Help := ''; 
  310.         
  311.         if Inputs<>NIL then Mnu := StripOff( Inputs^.Name, '.MENU' );
  312.         if Outputs<>NIL then begin
  313.             Mseg := StripOff( Outputs^.Name, '.MSEG' );
  314.             if Outputs^.Next<>NIL then begin
  315.                 Help := StripOff( Outputs^.Next^.Name, '.HLP' );
  316.             end;
  317.         end;
  318.         if Mnu='' then
  319.             Mnu := StripOff( LastFileName, '.MENU' );
  320.         if Mnu='' then
  321.             if Mseg='' then begin
  322.                 if Help='' then begin
  323.                     writeln('No filename given!');
  324.                     Raise BadArgs;
  325.                 end else begin
  326.                     Mseg := Help;
  327.                     Mnu := Help;
  328.                 end;
  329.             end else begin
  330.                 Mnu := Mseg;
  331.             end;
  332.         if Mseg='' then
  333.             Mseg := Mnu;
  334.         if Help='' then
  335.             Help := Mseg;
  336.                     
  337.         Mnu := Concat( Mnu, '.MENU' );
  338.         Mseg := Concat( Mseg, '.MSEG' );
  339.         Help := Concat( Help, '.HLP' );
  340.         Writeln( 'Reading: ',Mnu, ',');
  341.         Writeln( '  ==> ', MSeg, ', ', Help );
  342.         MakeMenues( Mnu, Mseg, Help );
  343.     end
  344.     else begin
  345.         writeln(Err);
  346.         writeln;
  347.         writeln
  348.          ('Usage:  MenuBuild <.MENU file> [~<.MSEG file> [,<.HLP file>] ]');
  349.     end;
  350. end;
  351.  
  352. begin
  353.     Inputs := NIL;
  354.     Outputs := NIL;
  355.     Switches := NIL;
  356.     ParseArgs;
  357.     DstryArgRec( Inputs );
  358.     DstryArgRec( Outputs );
  359.     DstrySwitchRec( Switches );
  360. end. 
  361.