home *** CD-ROM | disk | FTP | other *** search
/ POINT Software Programming / PPROG1.ISO / pascal / visionix / vansiiou.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-12-29  |  76.5 KB  |  3,687 lines

  1. {
  2.  ════════════════════════════════════════════════════════════════════════════
  3.  
  4.  Visionix ANSI In/Out Driver Unit (VANSIIOU)
  5.    Version 0.2
  6.  Copyright 1991,92,93 Visionix
  7.  ALL RIGHTS RESERVED
  8.  
  9.  ────────────────────────────────────────────────────────────────────────────
  10.  
  11.  ** revision history in reverse chronological order **
  12.  
  13.  Initials  Date      Comment
  14.  ────────  ────────  ────────────────────────────────────────────────────────
  15.  
  16.  jrt       12/22/93  Added even more function documentation.
  17.  
  18.  jrt       11/22/93  Added function documentation.
  19.  
  20.  jrt       11/17/93  Moved code out of VANSIu to here.
  21.  
  22.  jrt       11/15/93  Finished out driver and out filter.
  23.  
  24.  mep       05/08/93  Drivers (local and buffer) might work now - doubt it :)
  25.  
  26.  ────────────────────────────────────────────────────────────────────────────
  27. }
  28.  
  29. (*-
  30.  
  31. [SECTION: Section 2: The Text I/O Libraries]
  32. [CHAPTER: Chapter 1: The ANSI Driver & Filter I/O Unit]
  33.  
  34. [TEXT]
  35.  
  36. <Overview>
  37.  
  38. The VANSIiou unit contains only two procedures:  ANSIFilter and
  39. ANSIOutDriverProc.  As the names imply, ANSIFilter is a VOUT filter
  40. for ANSI commands, and ANSIOutDriverProc is an VOUT output driver
  41. for ANSI.
  42.  
  43. For more information on text filters, drivers, sub-channels, etc., be sure
  44. to read the VOUTu and VINu chapters.
  45.  
  46.  
  47. <<The ANSIFilter>>
  48.  
  49.   The ANSI Filter is a VOUT filter procedure.  ANSIFilter can be
  50.   attached to a VOUT sub-channel via a call to VOutFilterAttach.
  51.   After the ANSIFilter has been attached, it will "filter" all of the
  52.   ANSI commands in the text-stream sent to that channel, and convert
  53.   the ANSI commands one or more "out driver packets", which is the
  54.   internal command format used by VOUT.
  55.  
  56.   <<<What the heck does this mean?>>>
  57.  
  58.   Basically it means that after you attach the ANSIfilter to a
  59.   sub-channel, you can write ANSI commands into that sub-channel, and
  60.   the ANSI commands will be properly interpreted and executed on the
  61.   sub-channels display.  For example, if you were to attach the ANSI
  62.   filter to the sub-channel used by VCRTu, you could then use
  63.   ANSI commands in your WRITE and WRITELN statements, and the appropriate
  64.   colors, text, actions, etc would appear on your monitor.
  65.  
  66.   <<<Examples and usage>>>
  67.  
  68.   To attach the ANSI filter to the VCRTU's output sub-channel (which is
  69.   created automatically in the VCRTu units init-code):
  70.  
  71.   VOutFilterAttach( CrtOCH,
  72.                     0,
  73.                     'ANSIFILTER',
  74.                     'Bx00VMEM',
  75.                     AnsiFilter,
  76.                     0,0,0            );
  77.  
  78.  
  79.     CrtOCH is the channel handle for VCRTus output-channel.
  80.     As a paramater to VOutFilterAttach, it tells VOUT which channel
  81.     to attach the filter to.
  82.  
  83.     The second parameter, 0, is the flags parameter.  ANSIFilter
  84.     currently has no flags.
  85.  
  86.     The third parameter, 'ANSIFILTER', is the name by which this
  87.     instance of the filter is managed.
  88.  
  89.     The fourth parameter, 'Bx00VMEM', is the name of the sub-channel
  90.     off of the "CrtOCH" channel to which the filter should be
  91.     attached.  'Bx00VMEM' is the name that VCRTu uses for the default
  92.     sub-channel it creates which goes to the primary displays
  93.     video memory.
  94.  
  95.     The fifth parameter, AnsiFilter, is the filter procedure to
  96.     attach.  Since we are attaching the ANSI filter, we specify
  97.     the procedure AnsiFilter.
  98.  
  99.     The last three parameters to VOutFilterAttach are parameters/values
  100.     which are passed to the AnsiFilter.  Currently AnsiFilter has
  101.     no parameters, so we leave them all set to 0.
  102.  
  103.   To attach an ANSI filter to a new sub-channel, which happens to use
  104.   the ANSI Driver:
  105.  
  106.     { first we create a new-sub channel off of the CRT output channel }
  107.     { this new-sub channel will use the ANSI output driver procedure. }
  108.     { note that the ANSIOutDriverProc is very different from the      }
  109.     { ANSI filter.  We'll explain shortly...                          }
  110.  
  111.     { part 1 }
  112.  
  113.     VOutSubChannelNew( CrtOCH,
  114.                        0,
  115.                        'ANSIOUT',
  116.                        ANSIOutDriverProc,
  117.                        caoDOS,0,0                     );
  118.  
  119.  
  120.     { Then we attach the ANSI filter to the new sub-channel }
  121.  
  122.     { part 2 }
  123.  
  124.  
  125.     VOutFilterAttach( CrtOCH,
  126.                       0,
  127.                       'ANSIFILTER',
  128.                       'ANSIOUT',  {<--note we specify the new sub-chan name}
  129.                       AnsiFilter,
  130.                       0,0,0            );
  131.  
  132.     In "Part 1" of this example we create a new-sub channel.  We specify
  133.     that this sub-channel will use the ANSIOutDriverProc.  The
  134.     ANSIOutDriverProc is very different from the ANSIFilter.  The
  135.     ANSIFilter converts ANSI commands into the "Out driver packets"
  136.     used internally within VOUT, and the ANSIOutDriverProc performs
  137.     "Out driver Packets" by generating ANSI commands and sending them
  138.     to a text-stream output device.
  139.  
  140.     In "Part 2" of this example, we attach the ANSI filter to this
  141.     newly created sub-channel.
  142.  
  143.     What we end up with as a result of these actions is a sub-channel
  144.     that converts ANSI commands to output driver packets, and then
  145.     converts the output-driver packets back into ANSI commands.  This
  146.     may seem a little uncessarry, but in fact it is not.  We need
  147.     the intermediate conversion step so that (1) any other filters
  148.     which are added to the sub-channel can "understand" the ANSI commands
  149.     (since they are now converted to Out driver packets, (2) so that
  150.     the ANSI driver (or any other driver we may use) can respond
  151.     appropriately.  For the ANSI driver, an appropriate response is not
  152.     to just send out ANSI commands.  It must also "track" everything it
  153.     does (IE: keep track of the current text color, current cursor
  154.     x/y,etc).  By converting the ANSI commands into Out driver
  155.     packets, the ANSI driver now has a format by which it can understand
  156.     and track the ANSI commands "passing through" it.
  157.  
  158.     How about some simple-english:
  159.  
  160.     Even though this example creates a sub-channel which _generates_
  161.     ANSI commands, we still need the ANSI filter to interpret any
  162.     ANSI commands sent into the sub-channel by applications which
  163.     use VOUT our VCRTu.  Why?  Because although it may not seem like
  164.     it, the easiest way to implement and manage a sub-channel which can
  165.     both interpret and generate ANSI commands is to break the two tasks
  166.     up into seperate modules:  In this case, the ANSIFilter (which
  167.     interprets ANSI commands), and the ANSIOutDriverProc (which generates
  168.     ANSI commands).
  169.  
  170.     For more information on filter, driver, sub-channels, etc., be sure
  171.     to read the VOUTu and VINu chapters.
  172.  
  173. <<ANSIOutDriverProc>>
  174.  
  175.   The ANSI output-driver procedure is a VOUT output driver.  This
  176.   output-driver procedure lets you create a sub-channel which will
  177.   send ANSI commands to a specified device in response to VOUT text
  178.   I/O calls (IE: VOutClrScr, VOutWrite, etc).  By default, the
  179.   ANSI output-driver sends its output to the local, primary ANSI
  180.   device (IE:  DOS' ANSI.SYS or OS/2 VIO).  However, by specifying
  181.   other paramaters when a sub-channel using this driver is created,
  182.   ANSI will send its output to any other device, including a VSER
  183.   based serial port.
  184.  
  185.   <<<And what does all that mean?>>>
  186.  
  187.   The ANSIOutDriverProc responds to VOUTClrScr, VOutClrEol, VOutWrite,
  188.   etc. calls by generating ANSI commands.  These ANSI commands can be
  189.   sent to ANSI.SYS, OS/2 VIO, a serial port, or just about anywhere you
  190.   want by specifying the appropriate parameters on a call to
  191.   VOutSubChannelNew.  This driver is the key part that allows you,
  192.   for example, to use the normal TP CRT API functions (ClrScr, Write,
  193.   etc) over the serial port--because VCRTu's CRT API functions work
  194.   via VOUT, and VOUT can generate ANSI via this driver!
  195.  
  196.   <<<Examples and usage>>>
  197.  
  198.   To create a new-sub channel which uses the ANSIOutDriverProc
  199.   and sends its ANSI output to DOS CON: / ANSI.SYS
  200.  
  201.     { Here  we create a new-sub channel off of the CRT output channel }
  202.     { this new-sub channel will use the ANSI output driver procedure. }
  203.  
  204.     { part 1 }
  205.  
  206.     VOutSubChannelNew( CrtOCH,
  207.                        0,
  208.                        'ANSIOUT',
  209.                        ANSIOutDriverProc,
  210.                        caoDOS,0,0                     );
  211.  
  212.     CrtOCH is the channel handle for VCRTus output-channel.
  213.     As a paramater to VOutSubChannelNew, it tells VOUT which channel
  214.     to create a new sub-channel off of.
  215.  
  216.     The second parameter, 0, is the flags parameter.  VOutSubChanneNew
  217.     currently has no flags.
  218.  
  219.     The third parameter, 'ANSIOUT', is the name by which this
  220.     new sub-channel will be managed.
  221.  
  222.  
  223.     The fourth parameter, AnsiOutDriverProc, is the driver-procedure
  224.     which the new sub-channel will use or be "anchored" by.  In this
  225.     example, we specify ANSIOutDriverProc, which creates a sub-channel
  226.     which will generate ANSI commands in response to calls to
  227.     VOutClrScr, VOutWrite, VOUTGotoXY, etc.
  228.  
  229.     The last three parameters are parameters which are passed to the
  230.     ANSIOutDriverProc.
  231.  
  232.       For the ANSIOutDriverProc, the first of these parameters is a
  233.       value which specifies where the ANSI drivers output stream
  234.       should be sent.  In this example, we specify caoDOS, which tells
  235.       the ANSI driver to send its output to the default ANSI device,
  236.       which in DOS is CON: (or ANSI.SYS) and in OS/2 is the
  237.       VIOWriteTTY function.
  238.  
  239.       When the first of these parameters is caoDOS, the other
  240.       two parameters are not used.
  241.  
  242.  
  243.   To create a new-sub channel which uses the ANSIOutDriverProc
  244.   and sends its ANSI output to a custom stream device.
  245.  
  246.     Procedure MySend( Idata : POINTER; Var St : STRING ); Far;
  247.  
  248.     BEGIN
  249.  
  250.       { write ST to wherever here }
  251.  
  252.  
  253.     END;
  254.  
  255.  
  256.     VOutSubChannelNew( CrtOCH,
  257.                        0,
  258.                        'CustANSIOUT',
  259.                        ANSIOutDriverProc,
  260.                        caoCustom,
  261.                        Longint(@MySend),
  262.                        0                       );
  263.  
  264.  
  265.     CrtOCH is the channel handle for VCRTus output-channel.
  266.     As a paramater to VOutSubChannelNew, it tells VOUT which channel
  267.     to create a new sub-channel off of.
  268.  
  269.     The second parameter, 0, is the flags parameter.  VOutSubChanneNew
  270.     currently has no flags.
  271.  
  272.     The third parameter, 'CustANSIOUT', is the name by which this
  273.     new sub-channel will be managed.
  274.  
  275.     The fourth parameter, AnsiOutDriverProc, is the driver-procedure
  276.     which the new sub-channel will use or be "anchored" by.  In this
  277.     example, we specify ANSIOutDriverProc, which creates a sub-channel
  278.     which will generate ANSI commands in response to calls to
  279.     VOutClrScr, VOutWrite, VOUTGotoXY, etc.
  280.  
  281.     The last three parameters are parameters which are passed to the
  282.     ANSIOutDriverProc.
  283.  
  284.       For the ANSIOutDriverProc, the first of these parameters is a
  285.       value which specifies where the ANSI drivers output stream
  286.       should be sent.  In this example, we specify caoCustom, which tells
  287.       the ANSI driver to send its output to a custom send-procedure.
  288.  
  289.       When the first of these parameters is caoCustom, the second
  290.       parameter should be a pointer to the procedure to call when
  291.       ANSIOutDriverProc needs to send out text.  Since this
  292.       parameter is defined as a longint, this procedure-pointer needs
  293.       to be cast to a LONGINT.
  294.  
  295.       When using caoCustom, the third parameter is a 32-bit instance
  296.       data value that will be passed to the custom send-procedure.
  297.       Every time it is called (This is the IData paramater on the
  298.       MySend procedure).  You can use this 32-bit value for whatever
  299.       you'd like.  (IE: as a pointer to other information your
  300.       custom send-procedure might need, etc)
  301.  
  302. For more information on text filters, drivers, sub-channels, etc., be sure
  303. to read the VOUTu and VINu chapters.
  304.  
  305. <Interface>
  306.  
  307. -*)
  308.  
  309. Unit VAnsiIOu;
  310.  
  311. Interface
  312.  
  313. Uses
  314.  
  315.   VCRTu,
  316.   VAnsiU,
  317.   DOS,
  318.   VInlineu,
  319.   VInu,
  320.   VOutu,
  321.   VTypesu,
  322.   VStringu,
  323. {$IFDEF OS2}
  324.   VVioI,
  325. {$ENDIF}
  326.   VGenu;
  327.  
  328.  
  329. Const
  330.  
  331.   caoDos    = 0;
  332.   caoCustom = $80;
  333.  
  334.  
  335. {-----------------------------}
  336. { ANSI Emulation state record }
  337. {-----------------------------}
  338.  
  339. Type
  340.  
  341.   TANSIEmu = RECORD
  342.  
  343.     Cmd        : STRING;
  344.     StringMode : BOOLEAN;
  345.     AttrBold   : BYTE;
  346.     SaveX      : BYTE;
  347.     SaveY      : BYTE;
  348.  
  349.     X          : BYTE;
  350.     Y          : BYTE;
  351.     N          : BYTE;
  352.     TmpS       : STRING;
  353.  
  354.   END;
  355.  
  356.   PAnsiEmu = ^TAnsiEmu;
  357.  
  358.  
  359. Type
  360.  
  361.  
  362.   TANSIScreen = RECORD
  363.  
  364.     CurX        : INTEGER;
  365.     CurY        : INTEGER;
  366.     CurAttr     : BYTE;
  367.  
  368.     WinX1       : WORD;
  369.     WinX2       : WORD;
  370.     WinY1       : WORD;
  371.     WinY2       : WORD;
  372.  
  373.     CurType     : WORD;
  374.  
  375.     WinIsScreen : BOOLEAN;
  376.  
  377.     AttrIsKnown : BOOLEAN;
  378.  
  379.     KnownCurAttr: BYTE;
  380.     KnownCurX   : INTEGER;
  381.     KnownCurY   : INTEGER;
  382.  
  383.   END;  { TScreen }
  384.  
  385.   PANSIScreen = ^TANSIScreen;
  386.  
  387.   PAnsiOutDriverIdata = ^TAnsiOutDriverIdata;
  388.  
  389.   TAnsiSendProc = PROCEDURE( IData : PAnsiOutDriverIData; Var ST : STRING );
  390.  
  391.   TANSIOutDriverIData = Record
  392.  
  393.     Off        : WORD;
  394.     Name       : TProcName;
  395.  
  396.     Param1     : LONGINT;
  397.     Param2     : LONGINT;
  398.     Param3     : LONGINT;
  399.  
  400.     SendProc   : TAnsiSendProc;
  401.     SendBuff   : STRING;
  402.  
  403.     EmuBuf     : STRING;
  404.  
  405.     DisplayMode: BYTE;
  406.  
  407.     Cols       : WORD;
  408.     Rows       : WORD;
  409.  
  410.     YMult      : WORD;
  411.  
  412.     NumScreens : BYTE;
  413.  
  414.     AScreen    : BYTE;
  415.  
  416.     Screen     : Array[1..8] of TANSIScreen;
  417.  
  418.   END;  { TANSIOutDriverIData }
  419.  
  420.  
  421.  
  422.  
  423. Procedure ANSIFilter(             ODP            : POutDriverPacket );
  424.  
  425. Procedure ANSIOutDriverProc(      ODP            : POutDriverPacket );
  426.  
  427.  
  428. Procedure AttachAnsiFilter(       Chan       : TChanHandle;
  429.                                   SubChan    : STRING              );
  430.  
  431.  
  432.  
  433.  
  434. Implementation
  435.  
  436.  
  437.  
  438.  
  439.  
  440. {────────────────────────────────────────────────────────────────────────────}
  441.  
  442.  
  443.  
  444. (*-
  445.  
  446. [FUNCTION]
  447.  
  448. Procedure ANSIFilter(       ODP            : POutDriverPacket );
  449.  
  450. [PARAMETERS]
  451.  
  452. ODP         Pointer to a VOUT Out-driver request packet
  453.  
  454. [RETURNS]
  455.  
  456. (None)
  457.  
  458. [DESCRIPTION]
  459.  
  460. This procedure is an ANSI filter for the Visionix Input/Output
  461. architecture.
  462.  
  463. This procedure will "filter" incoming ANSI requests and generate
  464. the appropriate Out-Driver-Packets (ODP), and pass the new ODP
  465. packets down the driver stack of the sub-channel this filter
  466. is attached to.
  467.  
  468. This procedure should NOT be called directly.  Instead, use the
  469. VOutFilterAttach function to attach this filter to a previously
  470. created output sub-channel.
  471.  
  472. [SEE-ALSO]
  473.  
  474. (None)
  475.  
  476. [EXAMPLE]
  477.  
  478.   VOutFilterAttach( TheChan,
  479.                     0,
  480.                     'ANSIfilter',
  481.                     'TheSubChan',
  482.                     ANSIFilter,
  483.                     NIL            );
  484.  
  485. -*)
  486.  
  487.  
  488. Procedure ANSIFilter(       ODP            : POutDriverPacket );
  489.  
  490. Type
  491.  
  492.  
  493.   TCharBuff = Array[1..32768] of CHAR;
  494.   PCharBuff = ^TCharBuff;
  495.  
  496.   TANSIFilterIData = Record
  497.  
  498.     Off        : WORD;
  499.     Name       : TProcName;
  500.  
  501.     AnsiEMU    : TAnsiEmu;
  502.  
  503.   END;  { TANSIFilterIData }
  504.  
  505.   PAnsiFilterIData = ^TAnsiFilterIData;
  506.  
  507.   {----}
  508.  
  509. Var
  510.   IData      : PAnsiFilterIData;
  511.  
  512.   Z          : INTEGER;
  513.  
  514.   SBuff      : STRING;
  515.  
  516.   {---------------------------------------------------}
  517.  
  518.   Procedure SBuffFlush;
  519.  
  520.  
  521.   Var
  522.     MyODP : TOutDriverPacket;
  523.  
  524.   BEGIN
  525.  
  526.     If SBuff<>'' Then
  527.     BEGIN
  528.  
  529.       MyODP.Func   := ODF_WriteBlock;
  530.       MyODP.Buff   := @SBuff[1];
  531.       MyODP.Size   := Byte(SBuff[0]);
  532.       MyODP.Start  := 1;
  533.       MyODP.NextDriver := ODP^.NextDriver;
  534.       MyODP.Status := 0;
  535.  
  536.       CallNextDriver( @MyODP );
  537.  
  538.       SBuff := '';
  539.  
  540.     END;
  541.  
  542.   END;
  543.  
  544.   {---------------------------------------------------}
  545.  
  546.   Procedure ANSItoODP(         TheANSIEmu     : PAnsiEMU;
  547.                                Ch             : CHAR;
  548.                                OrigODP        : POutDriverPacket      );
  549.  
  550.   Var
  551.  
  552.     L1 : INTEGER;
  553.     L2 : BYTE;
  554.     L3 : BYTE;
  555.  
  556.     ODP : TOutDriverPacket;
  557.  
  558.     aTextAttr : BYTE;
  559.  
  560.     Function ANSITakeParam( Var Cmd : STRING ) : STRING;
  561.  
  562.     Var
  563.  
  564.       Idx  : BYTE;
  565.       Cnt  : BYTE;
  566.  
  567.     BEGIN
  568.  
  569.       Idx := Pos(';', Cmd);
  570.  
  571.       If Idx = 0 Then
  572.       BEGIN
  573.  
  574.         Cnt := Byte(Cmd[0]) - 2;
  575.  
  576.         ANSITakeParam := Copy(Cmd, 3, Cnt);
  577.         Delete(Cmd, 3, Cnt);
  578.  
  579.       END
  580.       Else
  581.       BEGIN
  582.  
  583.         Dec(Idx);
  584.         Cnt := Idx - 2;
  585.  
  586.         ANSITakeParam := Copy(Cmd, 3, Cnt);
  587.         Delete(Cmd, 3, Succ(Cnt));
  588.  
  589.       END;
  590.  
  591.     END;
  592.  
  593.     {───────────────────────────────────────────────────────}
  594.  
  595.     Function ANSITakeInt( Var Cmd : STRING ) : INTEGER;
  596.  
  597.     BEGIN
  598.  
  599.       ANSITakeInt := StrToInt( ANSITakeParam(Cmd) );
  600.  
  601.     END;
  602.  
  603.     {───────────────────────────────────────────────────────}
  604.  
  605.     Function ANSINextParam( Var Cmd : STRING ) : INTEGER;
  606.  
  607.     { -1 = no parameter        }
  608.     {  1 = string parameter    }
  609.     {  2 = command             }
  610.     {  3 = number parameter    }
  611.     {  4 = blank parameter ';' }
  612.  
  613.     BEGIN
  614.  
  615.       If Byte(Cmd[0]) < 3 Then
  616.         ANSINextParam := -1
  617.       Else
  618.       If Cmd[Byte(Cmd[0])] = '"' Then
  619.         ANSINextParam := 1
  620.       Else
  621.       If NOT IsNum(Cmd[Byte(Cmd[0])]) Then
  622.         ANSINextParam := 2
  623.       Else
  624.       If Cmd[3] = ';' Then
  625.       BEGIN
  626.         Delete(Cmd, 3, 1);   { yuck - but works! }
  627.         ANSINextParam := 4;
  628.       END
  629.       Else
  630.         ANSINextParam := 3;
  631.  
  632.     END;
  633.  
  634.     {─────────────────────────────────────────────────────}
  635.  
  636.     Procedure ResetCmd;
  637.  
  638.     BEGIN
  639.  
  640.       TheANSIEmu^.Cmd := '';
  641.  
  642.     END;
  643.  
  644.     {─────────────────────────────────────────────────────}
  645.  
  646.     Procedure MyWrite( CH: CHAR );
  647.  
  648.     BEGIN
  649.  
  650.       { SBuff := SBuff + CH; }
  651.  
  652.       StrAddCh( SBuff, CH );
  653.  
  654.  
  655.       (*
  656.       ODP.Func   := ODF_WriteChar;
  657.       ODP.CH     := CH;
  658.       ODP.Status := 0;
  659.  
  660.       CallNextDriver( @ODP );
  661.       *)
  662.  
  663.     END;
  664.  
  665.     Procedure MyWriteStr( S : STRING );
  666.  
  667.     Var
  668.      Z : INTEGER;
  669.  
  670.     BEGIN
  671.  
  672.       { SBuff := SBuff + S; }
  673.  
  674.       StrAddStr( Sbuff, S );
  675.  
  676.       (*
  677.       For Z:=1 to Length( S ) Do
  678.         MyWrite( S[Z] );
  679.       *)
  680.  
  681.  
  682.     END;
  683.  
  684.     {─────────────────────────────────────────────────────}
  685.  
  686.  
  687.   BEGIN
  688.  
  689.     { ODP := OrigODP^; }
  690.  
  691.     ODP.NextDriver := OrigODP^.NextDriver;
  692.  
  693.     With TheANSIEmu^ Do
  694.     BEGIN
  695.  
  696.       If Cmd[0] > NUL Then
  697.       BEGIN
  698.  
  699.         If Byte(Cmd[0]) = 1 Then
  700.         BEGIN
  701.  
  702.           If Ch = '[' Then
  703.             StrAddCh( Cmd, CH )
  704.           Else
  705.           BEGIN
  706.  
  707.             MyWrite(Ch);
  708.             ResetCmd;
  709.  
  710.           END;
  711.  
  712.         END
  713.         Else
  714.         BEGIN
  715.  
  716.           If StringMode AND (Ch <> '"') Then
  717.             StrAddCh( Cmd, CH )
  718.           Else
  719.           Case Ch of
  720.  
  721.             '0'..'9', { inputing number(s) values }
  722.             ';' :
  723.               StrAddCH( Cmd, CH );
  724.  
  725.             'A' :     { Up Row }
  726.  
  727.               BEGIN
  728.  
  729.                 If ANSINextParam(Cmd) = 3 Then
  730.                   L1 := ANSITakeInt(Cmd)
  731.                 Else
  732.                   L1 := 1;
  733.  
  734.                 SBuffFlush;
  735.  
  736.                 ODP.Func     := ODF_CursorUp;
  737.                 ODP.Status   := 0;
  738.                 ODP.NumVal   := L1;
  739.                 CallNextDriver( @ODP );
  740.  
  741.                 ResetCmd;
  742.  
  743.               END;
  744.  
  745.             'B' :     { Down Row }
  746.  
  747.               BEGIN
  748.  
  749.                 If ANSINextParam(Cmd) = 3 Then
  750.                   L1 := ANSITakeInt(Cmd)
  751.                 Else
  752.                   L1 := 1;
  753.  
  754.                 SBuffFlush;
  755.  
  756.                 ODP.Func     := ODF_CursorDown;
  757.                 ODP.Status   := 0;
  758.                 ODP.NumVal   := L1;
  759.                 CallNextDriver( @ODP );
  760.  
  761.                 ResetCmd;
  762.  
  763.               END;
  764.  
  765.             'C' :     { Right Col }
  766.  
  767.               BEGIN
  768.  
  769.                 If ANSINextParam(Cmd) = 3 Then
  770.                   L1 := ANSITakeInt(Cmd)
  771.                 Else
  772.                   L1 := 1;
  773.  
  774.                 SBuffFlush;
  775.  
  776.                 ODP.Func     := ODF_CursorRight;
  777.                 ODP.Status   := 0;
  778.                 ODP.NumVal   := L1;
  779.                 CallNextDriver( @ODP );
  780.  
  781.                 ResetCmd;
  782.  
  783.               END;
  784.  
  785.             'D' :     { Left Col }
  786.  
  787.               BEGIN
  788.  
  789.                 If ANSINextParam(Cmd) = 3 Then
  790.                   L1 := ANSITakeInt(Cmd)
  791.                 Else
  792.                   L1 := 1;
  793.  
  794.                 SBuffFlush;
  795.  
  796.                 ODP.Func     := ODF_CursorLeft;
  797.                 ODP.Status   := 0;
  798.                 ODP.NumVal   := L1;
  799.                 CallNextDriver( @ODP );
  800.  
  801.                 ResetCmd;
  802.  
  803.               END;
  804.  
  805.             'H',      { Home/GotoRC }
  806.             'f' :
  807.  
  808.               BEGIN
  809.  
  810.                 With TheANSIEmu^ Do
  811.                 BEGIN
  812.  
  813.                   X := 1;
  814.                   Y := 1;
  815.  
  816.                   If ANSINextParam(Cmd) = 3 Then
  817.                     Inc( Y, Pred(ANSITakeInt(Cmd)) );
  818.                   If ANSINextParam(Cmd) = 3 Then
  819.                     Inc( X, Pred(ANSITakeInt(Cmd)) );
  820.  
  821.                   SBuffFlush;
  822.  
  823.                   ODP.Func     := ODF_GetWin;
  824.                   ODP.Status   := 0;
  825.                   CallNextDriver( @ODP );
  826.  
  827.                   ODP.Func := ODF_GotoXY;
  828.                   ODP.X1   := LesserInt( (ODP.X2-ODP.X1)+1, X );
  829.                   ODP.Y1   := LesserInt( (ODP.Y2-ODP.Y1)+1, Y );
  830.                   ODP.Status := 0;
  831.  
  832.                   CallNextDriver( @ODP );
  833.  
  834.                 END;
  835.  
  836.                 ResetCmd;
  837.  
  838.               END;
  839.  
  840.             's' :     { Save Cursor Position }
  841.  
  842.               BEGIN
  843.  
  844.                 SBuffFlush;
  845.  
  846.                 ODP.Func     := ODF_GetXY;
  847.                 ODP.Status   := 0;
  848.                 CallNextDriver( @ODP );
  849.  
  850.                 TheAnsiEmu^.SaveX := ODP.X1;
  851.                 TheAnsiEmu^.SaveY := ODP.Y1;
  852.  
  853.                 ResetCmd;
  854.  
  855.               END;
  856.  
  857.             'u' :     { Restore Cursor Position }
  858.  
  859.               BEGIN
  860.  
  861.                 If (TheANSIEmu^.SaveX > 0) and
  862.                    (TheANSIEmu^.SaveY > 0) Then
  863.                 BEGIN
  864.  
  865.                   SBuffFlush;
  866.  
  867.                   ODP.Func := ODF_GotoXY;
  868.                   ODP.X1   := TheAnsiEmu^.SaveX;
  869.                   ODP.Y1   := TheAnsiEmu^.SaveY;
  870.                   ODP.Status := 0;
  871.                   CallNextDriver( @ODP );
  872.  
  873.                 END;
  874.  
  875.                 ResetCmd;
  876.  
  877.               END;
  878.  
  879.             'm' :     { Graphics }
  880.  
  881.               BEGIN
  882.  
  883.                 SBuffFlush;
  884.  
  885.                 While ( ANSINextParam(Cmd) = 3 ) Do
  886.                 BEGIN
  887.  
  888.                   With TheANSIEmu^ Do
  889.                   BEGIN
  890.  
  891.                     ODP.Func := ODF_GetAttr;
  892.                     ODP.Status := 0;
  893.                     CallNextDriver( @ODP );
  894.  
  895.                     aTextAttr := ODP.Attr;
  896.  
  897.                     AttrBold := aTextAttr AND $8;
  898.  
  899.                     L3 := ANSITakeInt(Cmd);
  900.  
  901.                     Case L3 of
  902.  
  903.                       0  :   { Attrs OFF }
  904.                         BEGIN
  905.  
  906.                           AttrBold := 0;
  907.                           aTextAttr := 7;
  908.  
  909.                         END;
  910.  
  911.                       1  :   { Bold ON }
  912.                         BEGIN
  913.  
  914.                           AttrBold := 8;
  915.                           aTextAttr := aTextAttr OR $8;
  916.  
  917.                         END;
  918.  
  919.                       5  : aTextAttr := aTextAttr OR  $80; { Blink ON }
  920.                       7  : aTextAttr := aTextAttr XOR $FF; { Rev. Video ON }
  921.                                                               {nonono!}
  922.  
  923.                       22 :
  924.                       BEGIN
  925.                         aTextAttr := aTextAttr and $F7; {turn boldoff}
  926.                         AttrBold  := 0;
  927.                       END;
  928.  
  929.                       25 : aTextAttr := aTextAttr AND NOT $80; { Blink OFF }
  930.                       27 : aTextAttr := aTextAttr XOR $FF; { Rev. Video OFF }
  931.  
  932.                       30 : atextAttr := (aTextAttr and $F8)+(Black     );
  933.                       31 : atextAttr := (aTextAttr and $F8)+(Red       );
  934.                       32 : atextAttr := (aTextAttr and $F8)+(Green     );
  935.                       33 : atextAttr := (aTextAttr and $F8)+(Brown     );
  936.                       34 : atextAttr := (aTextAttr and $F8)+(Blue      );
  937.                       35 : atextAttr := (aTextAttr and $F8)+(Magenta   );
  938.                       36 : atextAttr := (aTextAttr and $F8)+(Cyan      );
  939.                       37 : atextAttr := (aTextAttr and $F8)+(LightGray );
  940.  
  941.                       40 : atextAttr := (aTextAttr and $8F)+(BackBlack    );
  942.                       41 : atextAttr := (aTextAttr and $8F)+(BackRed      );
  943.                       42 : atextAttr := (aTextAttr and $8F)+(BackGreen    );
  944.                       43 : atextAttr := (aTextAttr and $8F)+(BackBrown    );
  945.                       44 : atextAttr := (aTextAttr and $8F)+(BackBlue     );
  946.                       45 : atextAttr := (aTextAttr and $8F)+(BackMagenta  );
  947.                       46 : atextAttr := (aTextAttr and $8F)+(BackCyan     );
  948.                       47 : atextAttr := (aTextAttr and $8F)+(BackLightGray);
  949.  
  950.                     End;
  951.  
  952.                     ODP.Func := ODF_SetAttr;
  953.                     ODP.Attr := aTextAttr;
  954.                     ODP.Status := 0;
  955.                     CallNextDriver( @ODP );
  956.  
  957.                   END;
  958.  
  959.                 END;
  960.  
  961.                 ResetCmd;
  962.  
  963.               END;
  964.  
  965.             'J' :     { ClrScr }
  966.  
  967.               BEGIN
  968.  
  969.                 With TheANSIEmu^ Do
  970.                 BEGIN
  971.  
  972.                   If ANSINextParam(Cmd) = 3 Then
  973.                     L3 := ANSITakeInt(Cmd)
  974.                   Else
  975.                   BEGIN  { ClrScr >= }
  976.  
  977.                     SBuffFlush;
  978.  
  979.                     ODP.Func := ODF_ClrScr;
  980.                     ODP.Status := 0;
  981.                     CallNextDriver( @ODP );
  982.  
  983.   (*
  984.                     X  := WhereX;
  985.                     Y  := WhereY;
  986.                     L1 := X;
  987.                     L2 := Y;
  988.  
  989.                     While ( L2 <= Hi(WindMax)) Do
  990.                     BEGIN
  991.  
  992.                       While (L1 <= Lo(WindMax)) Do
  993.                       BEGIN
  994.  
  995.                         Inc(L1);
  996.                         Write(SP);
  997.  
  998.                       END;
  999.  
  1000.                       Inc(L2);
  1001.                       L1 := Lo(WindMin);
  1002.                       GotoXY(L1, L2);
  1003.  
  1004.                     END;
  1005.  
  1006.                     GotoXY(X, Y);
  1007.   *)
  1008.  
  1009.                   END;
  1010.  
  1011.                   If L3 = 2 Then  { ClrScr }
  1012.                   BEGIN
  1013.  
  1014.                     SBuffFlush;
  1015.  
  1016.                     ODP.Func := ODF_ClrScr;
  1017.                     ODP.Status := 0;
  1018.                     CallNextDriver( @ODP );
  1019.  
  1020.                     ODP.Func := ODF_SetAttr;
  1021.                     ODP.Attr := 7;
  1022.                     ODP.Status := 0;
  1023.                     CallNextDriver( @ODP );
  1024.  
  1025.   (*
  1026.                     ClrScr;
  1027.                     TextAttr := 7;
  1028.   *)
  1029.  
  1030.                   END
  1031.                   Else
  1032.                   If L3 = 1 Then  { ClrScr <= }
  1033.                   BEGIN
  1034.  
  1035.                     With TheANSIEmu^ Do
  1036.                     BEGIN
  1037.   (*
  1038.                       X  := WhereX;
  1039.                       Y  := WhereY;
  1040.                       L1 := X;
  1041.                       L2 := Y;
  1042.  
  1043.                       GotoXY( Lo(WindMin), Hi(WindMin) );
  1044.                       While (WhereY < L2) Do
  1045.                       BEGIN
  1046.  
  1047.                         While ( WhereX < Lo(WindMax) ) Do
  1048.                         BEGIN
  1049.  
  1050.                           GotoXY(Succ(WhereX), WhereY);
  1051.                           Write(SP);
  1052.  
  1053.                         END;
  1054.  
  1055.                         GotoXY( Lo(WindMin), Succ(WhereY));
  1056.  
  1057.                       END;
  1058.  
  1059.                       While (WhereX <= L1) Do
  1060.                       BEGIN
  1061.  
  1062.                         GotoXY(Succ(WhereX), WhereY);
  1063.                         Write(SP);
  1064.  
  1065.                       END;
  1066.  
  1067.                       GotoXY(X, Y);
  1068.   *)
  1069.  
  1070.                     END;
  1071.  
  1072.                   END;
  1073.  
  1074.                 END;
  1075.  
  1076.                 ResetCmd;
  1077.  
  1078.               END;
  1079.  
  1080.             'K' :     { ClrEol }
  1081.  
  1082.               BEGIN
  1083.  
  1084.                 SBuffFlush;
  1085.  
  1086.                 ODP.Func := ODF_ClrEOL;
  1087.                 ODP.Status := 0;
  1088.                 CallNextDriver( @ODP );
  1089.  
  1090.                 {  ClrEol;  }
  1091.  
  1092.                 ResetCmd;
  1093.  
  1094.               END;
  1095.  
  1096.             'L' :     { InsLine }
  1097.  
  1098.               BEGIN
  1099.  
  1100.                 SBuffFlush;
  1101.  
  1102.                 If ANSINextParam(Cmd) = 3 Then
  1103.                   L1 := ANSITakeInt(Cmd)
  1104.                 Else
  1105.                   L1 := 1;
  1106.                 For L2 := 1 to L1 Do
  1107.                 BEGIN
  1108.  
  1109.                   ODP.Func := ODF_InsLine;
  1110.                   ODP.Status := 0;
  1111.                   CallNextDriver( @ODP );
  1112.  
  1113.                   { InsLine; }
  1114.  
  1115.                 END;
  1116.  
  1117.                 ResetCmd;
  1118.  
  1119.               END;
  1120.  
  1121.             'M' :     { DelLine }
  1122.  
  1123.               BEGIN
  1124.  
  1125.                 SBuffFlush;
  1126.  
  1127.                 If ANSINextParam(Cmd) = 3 Then
  1128.                   L1 := ANSITakeInt(Cmd)
  1129.                 Else
  1130.                   L1 := 1;
  1131.                 For L2 := 1 to L1 Do
  1132.                 BEGIN
  1133.  
  1134.                   ODP.Func := ODF_DelLine;
  1135.                   ODP.Status := 0;
  1136.                   CallNextDriver( @ODP );
  1137.  
  1138.                   {DelLine;}
  1139.  
  1140.                 END;
  1141.  
  1142.                 ResetCmd;
  1143.  
  1144.               END;
  1145.  
  1146.             'n' :     { Device Status Report }
  1147.  
  1148.               BEGIN
  1149.  
  1150.                 If ANSINextParam(Cmd) = 3 Then
  1151.                   L1 := ANSITakeInt(Cmd)
  1152.                 Else
  1153.                   L1 := 1;
  1154.  
  1155.                 ODP.Func := ODF_GetXY;
  1156.  
  1157.                 If L1 = 6 Then
  1158.                   MyWriteStr('[' + IntToStr(ODP.Y1) + ';' +
  1159.                                    IntToStr(ODP.X1) + 'R'    );
  1160.  
  1161.                 ResetCmd;
  1162.  
  1163.               END;
  1164.  
  1165.             '@' :     { Inserts Characters on Line }
  1166.  
  1167.               BEGIN
  1168.  
  1169.                 If ANSINextParam(Cmd) = 3 Then
  1170.                   L1 := ANSITakeInt(Cmd)
  1171.                 Else
  1172.                   L1 := 1;
  1173.                 For L2 := 1 to L1 Do
  1174.                 BEGIN
  1175.  
  1176.                 END;
  1177.  
  1178.                 ResetCmd;
  1179.  
  1180.               END;
  1181.  
  1182.             'P' :     { Deletes Characters on Line }
  1183.  
  1184.               BEGIN
  1185.  
  1186.                 If ANSINextParam(Cmd) = 3 Then
  1187.                   L1 := ANSITakeInt(Cmd)
  1188.                 Else
  1189.                   L1 := 1;
  1190.                 For L2 := 1 to L1 Do
  1191.                 BEGIN
  1192.  
  1193.                 END;
  1194.  
  1195.                 ResetCmd;
  1196.  
  1197.               END;
  1198.  
  1199.             'h' :     { Set Graphic Modes }
  1200.  
  1201.               BEGIN
  1202.  
  1203.                 If (ANSINextParam(Cmd) = 3) Then
  1204.                 BEGIN
  1205.  
  1206.                   L3 := Byte(ANSITakeInt(Cmd));
  1207.  
  1208.   (*
  1209.                   ASM
  1210.  
  1211.                     MOV AH, 0
  1212.                     MOV AL, L3
  1213.                     INT 10h
  1214.  
  1215.                   END;
  1216.   *)
  1217.  
  1218.                 END;
  1219.  
  1220.                 ResetCmd;
  1221.  
  1222.               END;
  1223.  
  1224.             'l' :     { Reset Graphic Modes }
  1225.  
  1226.               BEGIN
  1227.  
  1228.                 If (ANSINextParam(Cmd) = 3) Then
  1229.                 BEGIN
  1230.  
  1231.                   L3 := Byte(ANSITakeInt(Cmd));
  1232.   (*
  1233.                   ASM
  1234.  
  1235.                     MOV AH, 0
  1236.                     MOV AL, L3
  1237.                     INT 10h
  1238.                   END;
  1239.   *)
  1240.  
  1241.                 END;
  1242.  
  1243.                 ResetCmd;
  1244.  
  1245.               END;
  1246.  
  1247.             'p' :     { Keyboard Redefination }
  1248.               BEGIN
  1249.  
  1250.                 ResetCmd;
  1251.  
  1252.               END;
  1253.  
  1254.             '"' :     { inputing a string value }
  1255.               BEGIN
  1256.  
  1257.                 StringMode := NOT StringMode;
  1258.                 StrAddCh( Cmd, CH );
  1259.  
  1260.               END;
  1261.  
  1262.             '?',
  1263.             '=' :
  1264.               StrAddCh( Cmd, CH );
  1265.            Else
  1266.            BEGIN
  1267.  
  1268.              MyWrite(Ch);
  1269.              ResetCmd;
  1270.  
  1271.            END
  1272.  
  1273.           End;{of case}
  1274.  
  1275.         END;
  1276.  
  1277.       END
  1278.       Else
  1279.       BEGIN
  1280.  
  1281.         If Byte(CH)<32 Then
  1282.         BEGIN
  1283.  
  1284.           Case CH Of
  1285.             #8:
  1286.             BEGIN
  1287.               SBuffFlush;
  1288.               ODP.Func   := ODF_CursorLeft;
  1289.               ODP.NumVal := 1;
  1290.               ODP.Status := 0;
  1291.               CallNextDriver( @ODP );
  1292.             END;
  1293.             #12:
  1294.             BEGIN
  1295.               SBuffFlush;
  1296.               ODP.Func   := ODF_ClrScr;
  1297.               ODP.NumVal := 1;
  1298.               ODP.Status := 0;
  1299.               CallNextDriver( @ODP );
  1300.  
  1301.             END;
  1302.             #27:StrAddCH( Cmd, CH );
  1303.           ELSE
  1304.             MyWrite( CH );
  1305.           END;
  1306.  
  1307.         END
  1308.         ELSE
  1309.           MyWrite(CH);
  1310.  
  1311.       END;
  1312.  
  1313.     END;
  1314.  
  1315.   END; { ansi to odp }
  1316.  
  1317.   {---------------------------------------------------}
  1318.  
  1319.  
  1320.  
  1321. BEGIN  { AnsiFilterProc }
  1322.  
  1323.   IData := ODP^.ID;
  1324.  
  1325.   If ODP^.Status = 0 Then
  1326.   BEGIN
  1327.  
  1328.     Case ODP^.Func Of
  1329.  
  1330.       ODF_DriverNew:
  1331.       BEGIN
  1332.  
  1333.         {-----------------------------}
  1334.         { are they telling me to new? }
  1335.         {-----------------------------}
  1336.  
  1337.         IF @ODP^.OutDriverProc = @AnsiFilter Then
  1338.         BEGIN
  1339.  
  1340.           {-------------------------}
  1341.           { Get a new Instance Data }
  1342.           { master node.            }
  1343.           {-------------------------}
  1344.  
  1345.           New( Idata );
  1346.  
  1347.           IData^.Off := 0;
  1348.  
  1349.           IData^.Name := ODP^.Name^;
  1350.  
  1351.           FillChar( Idata^.ANSIEmu, SizeOf(TANSIEmu), 0 );
  1352.  
  1353.           ODP^.Status    := ODS_Install+ODS_Changed;
  1354.           ODP^.ID        := IData;
  1355.  
  1356.         END; { If ODP^.OutDriverProc --> Us }
  1357.  
  1358.       END; { ODF_DriverNew }
  1359.  
  1360.       {----}
  1361.  
  1362.       ODF_DriverOff:
  1363.       BEGIN
  1364.  
  1365.         If ODP^.Name^ = IData^.Name Then
  1366.         BEGIN
  1367.  
  1368.           Inc( Idata^.Off );
  1369.  
  1370.         END;  { If ODP^.Name^ }
  1371.  
  1372.       END;  { ODF_DriverOff }
  1373.  
  1374.       {----}
  1375.  
  1376.       ODF_DriverOn:
  1377.       BEGIN
  1378.  
  1379.         If ODP^.Name^ = IData^.Name Then
  1380.         BEGIN
  1381.  
  1382.           If Idata^.Off <> 0 Then
  1383.             Dec( Idata^.Off );
  1384.  
  1385.         END;  { ODP^.Name^ }
  1386.  
  1387.       END;  { ODF_DriverOn }
  1388.  
  1389.       {----}
  1390.  
  1391.       ODF_DriverDispose:
  1392.       BEGIN
  1393.  
  1394.         If ODP^.Name^ = IData^.Name Then
  1395.         BEGIN
  1396.  
  1397.           {RemoveFromOutDriverStack }
  1398.  
  1399.           Dispose( IData );
  1400.  
  1401.         END;  { If ODP^.Name^ }
  1402.  
  1403.       END;  { ODF_DriverDispose }
  1404.  
  1405.       {----}
  1406.  
  1407.       ODF_WriteChar:
  1408.       BEGIN
  1409.  
  1410.         SBuff := '';
  1411.  
  1412.         ANSItoODP( @IData^.AnsiEmu,
  1413.                    ODP^.CH,
  1414.                    ODP                  );
  1415.  
  1416.         SBuffFlush;
  1417.  
  1418.         {make sure ODP.func hasnt changed to make us }
  1419.          { do another part of the case statement    }
  1420.  
  1421.       END;  { ODF_WriteChar }
  1422.  
  1423.       {----}
  1424.  
  1425.       ODF_WriteBlock:
  1426.       BEGIN
  1427.  
  1428.         SBuff := '';
  1429.  
  1430.         For Z:=ODP^.Start to ODP^.Size Do
  1431.         BEGIN
  1432.  
  1433.           ANSItoODP( @IData^.AnsiEmu,
  1434.                      PCharBuff( ODP^.Buff )^[Z],
  1435.                      ODP                  );
  1436.  
  1437.         END; { For Z }
  1438.  
  1439.         ODP^.Start := ODP^.Size;
  1440.  
  1441.         SBuffFlush;
  1442.  
  1443.       END;  { ODF_WriteBlock }
  1444.  
  1445.       {----}
  1446.  
  1447.     Else { Else Case }
  1448.  
  1449.       CallNextDriver( ODP );
  1450.  
  1451.     END;  { Case ODP^.Func }
  1452.  
  1453.   END; { If ODP^.Status = 0 }
  1454.  
  1455. END;  { ANSIFilter }
  1456.  
  1457.  
  1458. {────────────────────────────────────────────────────────────────────────────}
  1459.  
  1460.  
  1461. Procedure DosSendSt(              IData          : PANSIOutDriverIData;
  1462.                               Var ST2            : STRING               ); Far;
  1463.  
  1464. {$IFNDEF OS2}
  1465.  
  1466. Var
  1467.   R : REGISTERS;
  1468.   L : BYTE;
  1469.   S,O: WORD;
  1470. BEGIN
  1471.  
  1472.   {$IFDEF DOSWRITE}
  1473.  
  1474.   L := Byte( ST2[0] );
  1475.   S := Seg( ST2[1] );
  1476.   O := ofs( ST2[1] );
  1477.   ASM
  1478.  
  1479.     PUSH DS
  1480.  
  1481.     MOV  AH, $40
  1482.     MOV  BX, 1
  1483.     MOV  CL, L
  1484.     XOR  CH, CH
  1485.  
  1486.     PUSH S
  1487.     POP  DS
  1488.     MOV  DX, O
  1489.  
  1490.     INT  $21
  1491.  
  1492.     POP  DS
  1493.  
  1494.   END;
  1495.  
  1496.   {$ELSE}
  1497.  
  1498.   ASM
  1499.  
  1500.     { Save DS }
  1501.  
  1502.     PUSH DS
  1503.  
  1504.     { Make DS:SI --> ST2 }
  1505.  
  1506.     LDS  SI, [ST2]
  1507.  
  1508.     { Load CL with the count of bytes to write }
  1509.  
  1510.     MOV  CL, DS:[SI]
  1511.  
  1512.     { move DS:SI --> down to the text }
  1513.  
  1514.     INC  SI
  1515.  
  1516.     { WRITE OUT THE STRING VIA INT $29 (Dos fast console output) }
  1517.  
  1518.   @@1:
  1519.  
  1520.     LODSB
  1521.     INT $29
  1522.     LOOP @@1
  1523.  
  1524.     { Restore DS }
  1525.  
  1526.     POP DS
  1527.  
  1528.   END;
  1529.  
  1530.   {$ENDIF}
  1531.  
  1532. END;
  1533.  
  1534. {$ELSE}
  1535.  
  1536. BEGIN
  1537.  
  1538.   VioWrtTTY( @St2[1], Length(St2), 0 );
  1539.  
  1540. END;
  1541.  
  1542. {$ENDIF}
  1543.  
  1544. {────────────────────────────────────────────────────────────────────────────}
  1545.  
  1546. (*-
  1547.  
  1548. [FUNCTION]
  1549.  
  1550. Procedure ANSIOutDriverProc(      ODP            : POutDriverPacket );
  1551.  
  1552. [PARAMETERS]
  1553.  
  1554. ODP         Pointer to Output Driver Packet
  1555.  
  1556. [RETURNS]
  1557.  
  1558. (None)
  1559.  
  1560. [DESCRIPTION]
  1561.  
  1562. Visionix input/output architecture ANSI driver.  This driver converts
  1563. vout out-driver-packets into the appropriate ANSI commands.
  1564.  
  1565. This is an out driver procedure which is used to anchor a sub-channel
  1566. when it is created.  It should not be called directly, but should be
  1567. used with the VOutSubChannelNew function in VOut.
  1568.  
  1569. [SEE-ALSO]
  1570.  
  1571. [EXAMPLE]
  1572.  
  1573.   VOutSubChannelNew( TheChan,
  1574.                      0,
  1575.                      'TheSubChan',
  1576.                      ANSIOutDriverProc,
  1577.                      NIL                  );
  1578.  
  1579.  
  1580. -*)
  1581.  
  1582.  
  1583. Procedure ANSIOutDriverProc(      ODP            : POutDriverPacket );
  1584.  
  1585. Type
  1586.  
  1587.  
  1588.   TCell = Record
  1589.  
  1590.     Char    : CHAR;
  1591.     Attr    : BYTE;
  1592.  
  1593.   END;  { TCell }
  1594.  
  1595.   TScreenStore = Array[0..32000] of TCell;
  1596.  
  1597.   PScreenStore = ^TScreenStore;
  1598.  
  1599.   {----}
  1600.  
  1601.   {----}
  1602.  
  1603. Var
  1604.  
  1605.   IData      : PANSIOutDriverIData;
  1606.  
  1607.   YMult      : WORD;
  1608.  
  1609.   AS         : PANSIScreen;
  1610.  
  1611.   Z          : INTEGER;
  1612.   Z2         : INTEGER;
  1613.   Z3         : INTEGER;
  1614.  
  1615.   S          : STRING;
  1616.   P          : POINTER;
  1617.  
  1618.   SaveCurX   : WORD;
  1619.   SaveCurY   : WORD;
  1620.   SaveAttr   : BYTE;
  1621.  
  1622.   savewinx1,savewiny1,savewinx2,savewiny2:integer;
  1623.  
  1624.   {────────────────────────────────────────────────────────────────────────}
  1625.  
  1626.   Procedure InitIData;
  1627.  
  1628.   Var
  1629.  
  1630.     L : WORD;
  1631.  
  1632.   BEGIN
  1633.  
  1634.     IData^.Off         := 0;
  1635.     IData^.Name        := ODP^.Name^;
  1636.     IData^.EmuBuf      := '';
  1637.  
  1638.     IData^.Cols        := 80;
  1639.     IData^.Rows        := 25;
  1640.     IData^.YMult       := 80;
  1641.     IData^.NumScreens  := 1;
  1642.     IData^.AScreen     := 1;
  1643.  
  1644.     IData^.SendBuff    := '';
  1645.  
  1646.     For L := 1 to Idata^.NumScreens Do
  1647.     BEGIN
  1648.       IData^.Screen[L].KnownCurX   := 255;
  1649.       IData^.Screen[L].KnownCurY   := 255;
  1650.       IData^.Screen[L].KnownCurAttr:= 255;
  1651.  
  1652.       IData^.Screen[L].CurX        := 0;
  1653.       IData^.Screen[L].CurY        := 0;
  1654.       IData^.Screen[L].CurAttr     := 7;
  1655.       IData^.Screen[L].WinX1       := 0;
  1656.       IData^.Screen[L].WinY1       := 0;
  1657.       IData^.Screen[L].WinX2       := Idata^.Cols-1;
  1658.       IData^.Screen[L].WinY2       := Idata^.Rows-1;
  1659.  
  1660.       IData^.Screen[L].WinIsScreen := TRUE;
  1661.  
  1662.     END;
  1663.  
  1664.     {------------------------------}
  1665.     { copy the params to our IDATA }
  1666.     {------------------------------}
  1667.  
  1668.     IData^.Param1 := ODP^.DriverParam1;
  1669.     IData^.Param2 := ODP^.DriverParam2;
  1670.     IData^.Param3 := ODP^.DriverParam3;
  1671.  
  1672.     {-----------------------}
  1673.     { Setup the output proc }
  1674.     {-----------------------}
  1675.  
  1676.     Case ODP^.DriverParam1 of
  1677.  
  1678.       caoDOS    : IData^.SendProc := DosSendSt;
  1679.       caoCustom : IData^.SendProc :=
  1680.                      TAnsiSendProc( ODP^.DriverParam2 );
  1681.  
  1682.     ELSE
  1683.  
  1684.       IData^.SendProc := DosSendSt;
  1685.  
  1686.     END;
  1687.  
  1688.   END; { InitIData }
  1689.  
  1690.   {────────────────────────────────────────────────────────────────────────}
  1691.  
  1692.   Procedure AddBufCh( Buf : CHAR );
  1693.   Var
  1694.    s : string[1];
  1695.  
  1696.   BEGIN
  1697.  
  1698.     If Length(IData^.SendBuff)=255 Then
  1699.     BEGIN
  1700.       IData^.SendProc( IData, IData^.SendBuff );
  1701.       IData^.SendBuff := Buf;
  1702.     END
  1703.     ELSE
  1704.       StrAddCh( IData^.SendBuff, Buf );
  1705.  
  1706.     (*
  1707.     s:=buf;
  1708.     IData^.SendProc( IData, S );
  1709.     *)
  1710.   END;
  1711.  
  1712.   {────────────────────────────────────────────────────────────────────────}
  1713.  
  1714.   Procedure AddBuf(     Buf : STRING );
  1715.  
  1716.   BEGIN
  1717.  
  1718.     If Length(IData^.SendBuff)+Length(Buf)>255 Then
  1719.     BEGIN
  1720.       IData^.SendProc( IData, Idata^.SendBuff );
  1721.       IData^.SendBuff := Buf;
  1722.     END
  1723.     ELSE
  1724.       StrAddStr( IData^.SendBuff, Buf );
  1725.  
  1726.     (*
  1727.     IData^.SendProc( IData, Buf );
  1728.     *)
  1729.  
  1730.   END;
  1731.  
  1732.   {────────────────────────────────────────────────────────────────────────}
  1733.  
  1734.   Procedure FlushBuff;
  1735.  
  1736.   BEGIN
  1737.  
  1738.     If Length(IData^.SendBuff)>0 Then
  1739.     BEGIN
  1740.       IData^.SendProc( IData, IData^.SendBuff );
  1741.       IData^.SendBuff := '';
  1742.     END;
  1743.  
  1744.   END;
  1745.  
  1746.   {────────────────────────────────────────────────────────────────────────}
  1747.  
  1748.   {$IFDEF CHECKCURXY}
  1749.  
  1750.   Procedure CheckCurXY;
  1751.  
  1752.   {$IFNDEF OS2}
  1753.  
  1754.   Var
  1755.     R : REGISTERS;
  1756.  
  1757.   BEGIN
  1758.  
  1759.     R.AH :=$03;
  1760.     R.BH :=0;
  1761.     R.ES :=$0;
  1762.     R.DS :=$0;
  1763.  
  1764.     Intr( $10, R );
  1765.  
  1766.     If (R.DL<>AS^.CurX) or (R.DH<>AS^.CurY) Then
  1767.     BEGIN
  1768.  
  1769.       R.DL := R.DL;
  1770.  
  1771.     END;
  1772.  
  1773.  
  1774.   END;
  1775.  
  1776.   {$ELSE}
  1777.  
  1778.   BEGIN
  1779.  
  1780.   END;
  1781.  
  1782.   {$ENDIF}
  1783.  
  1784.   {$ENDIF} { ifdef checkcurxy }
  1785.  
  1786.   {────────────────────────────────────────────────────────────────────────}
  1787.  
  1788.   Procedure ChkTextAttr;
  1789.  
  1790.   BEGIN
  1791.  
  1792.     (*
  1793.  
  1794.     If (IData^.Win[IData^.InWin].CurTextAttr <> TextAttr) Then
  1795.     BEGIN
  1796.  
  1797.       AddBuf( ANSITextAttr(TextAttr) );
  1798.       IData^.Win[IData^.InWin].CurTextAttr := TextAttr;
  1799.  
  1800.     END;
  1801.  
  1802.     *)
  1803.  
  1804.   END;
  1805.  
  1806.   {────────────────────────────────────────────────────────────────────────}
  1807.  
  1808.   Procedure MySyncAttr;
  1809.  
  1810.   Var
  1811.  
  1812.     S : STRING[30];
  1813.  
  1814.     newattr, oldattr : byte;
  1815.  
  1816.     label done;
  1817.  
  1818.   BEGIN
  1819.  
  1820.     With AS^ Do
  1821.     BEGIN
  1822.  
  1823.       NewAttr := CurAttr;
  1824.       OldAttr := KnownCurAttr;
  1825.  
  1826.       { are the attrs the same? }
  1827.  
  1828.       IF NewAttr<>OldAttr Then
  1829.       BEGIN
  1830.  
  1831.         S:=#27+'[';
  1832.  
  1833.         { is the new attr the default attr? }
  1834.  
  1835.         If newattr=$07 then
  1836.         BEGIN
  1837.           StrAddConstStr( S, '0;' );
  1838.           goto DONE;
  1839.         END;
  1840.  
  1841.         { is blink being turned off? }
  1842.  
  1843.         If ((NewAttr and $80)=0) and ((OldAttr and $80)>0) Then
  1844.         BEGIN
  1845.           StrAddConstStr( S, '0;' );
  1846.           OldAttr := $07;
  1847.         END
  1848.         ELSE
  1849.           { is blink being turned on? }
  1850.  
  1851.           If ((NewAttr and $80)>0) and ((OldAttr and $80)=0) Then
  1852.           BEGIN
  1853.             StrAddConstStr( S, '5;' );
  1854.           END;
  1855.  
  1856.         { is intensity being turned off ? }
  1857.  
  1858.         If ((NewAttr and $08)=0) and ((OldAttr and $08)>0) Then
  1859.         BEGIN
  1860.           StrAddConstStr( S, '0;' );
  1861.           OldAttr := $07;
  1862.         END
  1863.         ELSE
  1864.           { isintensity being turned on ? }
  1865.  
  1866.           If ((NewAttr and $08)>0) and ((OldAttr and $08)=0) Then
  1867.           BEGIN
  1868.           StrAddConstStr( S, '1;' );
  1869.           END;
  1870.  
  1871.         { is the background changing? }
  1872.  
  1873.         If (NewAttr and $70)<>(OldAttr AND $70) Then
  1874.         BEGIN
  1875.           Case ((NewAttr AND $70) SHR 4) of
  1876.             Black     : StrAddConstStr( S, '40;' );
  1877.             Blue      : StrAddConstStr( S, '44;' );
  1878.             Green     : StrAddConstStr( S, '42;' );
  1879.             Cyan      : StrAddConstStr( S, '46;' );
  1880.             Red       : StrAddConstStr( S, '41;' );
  1881.             Magenta   : StrAddConstStr( S, '45;' );
  1882.             Brown     : StrAddConstStr( S, '43;' );
  1883.             LightGray : StrAddConstStr( S, '47;' );
  1884.           END;
  1885.         END;
  1886.  
  1887.         { isthe foreground changing? }
  1888.  
  1889.         If (NewAttr and $07)<>(OldAttr AND $07) Then
  1890.         BEGIN
  1891.           Case (NewAttr AND $07) of
  1892.             Black     : StrAddConstStr( S, '30;' );
  1893.             Blue      : StrAddConstStr( S, '34;' );
  1894.             Green     : StrAddConstStr( S, '32;' );
  1895.             Cyan      : StrAddConstStr( S, '36;' );
  1896.             Red       : StrAddConstStr( S, '31;' );
  1897.             Magenta   : StrAddConstStr( S, '35;' );
  1898.             Brown     : StrAddConstStr( S, '33;' );
  1899.             LightGray : StrAddConstStr( S, '37;' );
  1900.           END;
  1901.         END;
  1902.  
  1903.         DONE:
  1904.  
  1905.         S[Length(S)]:='m';
  1906.  
  1907.         AddBuf( S );
  1908.  
  1909.         KnownCurAttr := NewAttr;
  1910.  
  1911.       END; { if newattr<>curattr }
  1912.  
  1913.       (*
  1914.       If (CurAttr AND $0F)<>(KnownCurAttr AND $0F) Then
  1915.       BEGIN
  1916.  
  1917.         { textcolors dont match }
  1918.  
  1919.         If (CurAttr AND $F0)<>(KnownCurAttr AND $F0) Then
  1920.           AddBuf( AnsiTextattr( CurAttr ) )
  1921.         Else
  1922.           Addbuf( AnsiTextColor( CurAttr AND $0F ) );
  1923.  
  1924.       END
  1925.       ELSE
  1926.       If (CurAttr AND $F0)<>(KnownCurAttr and $F0) Then
  1927.       BEGIN
  1928.  
  1929.         { textbackground/blink doesnt match }
  1930.  
  1931.         {
  1932.         If (CurAttr AND $80)<>(KnownCurAttr and $80) Then
  1933.           AddBuf( AnsiTextAttr( CurAttr ) )
  1934.         ELSE
  1935.           Addbuf( AnsiTextBackGround( (CurAttr AND $70) SHR 4 ) );
  1936.         }
  1937.  
  1938.         AddBuf( AnsiTextAttr( CurAttr ) );
  1939.  
  1940.       END;
  1941.  
  1942.       KnownCurAttr := CurAttr;
  1943.       *)
  1944.  
  1945.       (*
  1946.       If CurAttr<>KnownCurAttr Then
  1947.       BEGIN
  1948.         AddBuf( AnsiTextAttr( CurAttr ) );
  1949.         KnownCurAttr := CurAttr;
  1950.       END;
  1951.       *)
  1952.  
  1953.     END;
  1954.  
  1955.   END;
  1956.  
  1957.   Procedure MyTextAttr( Attr : BYTE );
  1958.  
  1959.   BEGIN
  1960.  
  1961.     With AS^ Do
  1962.       If Attr<>KnownCurAttr Then
  1963.       BEGIN
  1964.         AddBuf( AnsiTextAttr( Attr ) );
  1965.         KnownCurAttr := Attr;
  1966.       END;
  1967.  
  1968.   END;
  1969.  
  1970.   {────────────────────────────────────────────────────────────────────────}
  1971.  
  1972.   Procedure MySyncCurXY;
  1973.  
  1974.   Var
  1975.  
  1976.     S : STRING[30];
  1977.     S2: STRING[30];
  1978.     XDiff : INTEGER;
  1979.     YDiff : INTEGER;
  1980.  
  1981.   BEGIN
  1982.  
  1983.     With AS^ Do
  1984.       If (CurX<>KnownCurX) or (CurY<>KnownCurY) Then
  1985.       BEGIN
  1986.         S2:= '';
  1987.         S := ANSIGotoXY( CurX+1, CurY+1 );
  1988.  
  1989.         XDiff := KnownCurX-CurX;
  1990.         YDiff := KnownCurY-CurY;
  1991.  
  1992.         If XDiff<>0 Then
  1993.           If XDiff<0 Then
  1994.           BEGIN
  1995.             If Abs(XDiff)=1 Then
  1996.               StrAddConstStr( S2, AnsiRight )
  1997.             ELSE
  1998.               StrAddConstStr( S2, AnsiRightCount( Abs( XDiff ) ) );
  1999.           END { move right }
  2000.           Else
  2001.           BEGIN
  2002.             If XDiff=1 Then
  2003.               StrAddConstStr( S2, AnsiLeft )
  2004.             ELSE
  2005.               StrAddConstStr( S2, AnsiLeftCount( XDiff ) );
  2006.           END; { move right / else }
  2007.  
  2008.         If YDiff<>0 Then
  2009.           If YDiff<0 Then
  2010.           BEGIN
  2011.             If Abs(YDiff)=1 Then
  2012.               StrAddConstStr( S2, AnsiDown )
  2013.             ELSE
  2014.               StrAddConstStr( S2, AnsiDownCount( Abs(YDiff) ) );
  2015.           END { move down }
  2016.           Else
  2017.           BEGIN
  2018.             If YDiff=1 Then
  2019.               StrAddConstStr( S2, AnsiUp )
  2020.             ELSE
  2021.               StrAddConstStr( S2, AnsiUpCount( YDiff ) );
  2022.           END; { moveup }
  2023.  
  2024.         (*
  2025.         If XDiff<>0 Then
  2026.           If XDiff<0 Then
  2027.             S2 := S2 + AnsiRightCount( Abs(XDiff) )
  2028.           END
  2029.           Else
  2030.             S2 := S2 + AnsiLeftCount( XDiff );
  2031.  
  2032.         If YDiff<>0 Then
  2033.           If YDiff<0 Then
  2034.             S2 := S2 + AnsiDownCount( Abs(YDiff) )
  2035.           Else
  2036.             S2 := S2 + AnsiUpCount( YDiff );
  2037.         *)
  2038.  
  2039.  
  2040.  
  2041.         If Length(S)<=Length(S2) Then
  2042.           Addbuf( S )
  2043.         ELSE
  2044.           AddBuf( S2 );
  2045.  
  2046.         { AddBuf( AnsiGotoXY( CurX+1, CurY+1 ) ); }
  2047.  
  2048.         KnownCurX := CurX;
  2049.         KnownCurY := CurY;
  2050.       END;
  2051.  
  2052.   END;
  2053.  
  2054.   Procedure MySyncGotoXY( x, y : INTEGER );
  2055.  
  2056.   BEGIN
  2057.  
  2058.     With AS^ Do
  2059.     BEGIN
  2060.       Curx := x;
  2061.       CurY := y;
  2062.       If (CurX<>KnownCurX) or (CurY<>KnownCurY) Then
  2063.       BEGIN
  2064.         AddBuf( AnsiGotoXY( CurX+1, CurY+1 ) );
  2065.         KnownCurX := CurX;
  2066.         KnownCurY := CurY;
  2067.       END;
  2068.     END;
  2069.   END;
  2070.  
  2071.   Procedure MyKnownGotoXY( newx, newy : INTEGER );
  2072.  
  2073.   BEGIN
  2074.  
  2075.     With AS^ Do
  2076.       If (CurX<>NewX) or (CurY<>NewY) Then
  2077.       BEGIN
  2078.         AddBuf( AnsiGotoXY( NewX, NewY ) );
  2079.         KnownCurX := NewX;
  2080.         KnownCurY := NewY;
  2081.       END;
  2082.  
  2083.   END;
  2084.  
  2085.   Procedure MyKnownCurXY( x,y : INTEGER );
  2086.  
  2087.   BEGIN
  2088.  
  2089.     With AS^ Do
  2090.     BEGIN
  2091.       KnownCurX := X;
  2092.       KnownCurY := Y;
  2093.     END;
  2094.  
  2095.   END;
  2096.  
  2097.   {────────────────────────────────────────────────────────────────────────}
  2098. (*
  2099.   Procedure CursorDown(           Sync           : BOOLEAN   );
  2100.  
  2101.   BEGIN
  2102.  
  2103.     With AS^ Do
  2104.     BEGIN
  2105.  
  2106.       Inc( CurY );
  2107.  
  2108.       If CurY > WinY2 Then
  2109.       BEGIN
  2110.  
  2111.         { scroll the region }
  2112.  
  2113.         Dec( CurY );
  2114.  
  2115.       END  { if cur>winy2 }
  2116.       ELSE
  2117.       BEGIN
  2118.  
  2119.         AddBuff( AnsiDown );
  2120.  
  2121.       END;
  2122.  
  2123.       {
  2124.       If (Sync) Then
  2125.         RealCursorGoto( IData^.AScreen-1, CurX, CurY );
  2126.       }
  2127.  
  2128.     END; { With AS^ }
  2129.  
  2130.   END; { CursorDown }
  2131. *)
  2132.  
  2133.   {────────────────────────────────────────────────────────────────────────}
  2134.  
  2135.  
  2136.   Procedure MyClrEOL;
  2137.  
  2138.   BEGIN
  2139.  
  2140.     With AS^ DO
  2141.     BEGIN
  2142.  
  2143.       MySyncCurXy;
  2144.       MySyncAttr;
  2145.  
  2146.       { does the right-edge of the window = right-edge of screen? }
  2147.  
  2148.       If WinX2=Idata^.Cols-1 Then
  2149.       BEGIN
  2150.  
  2151.         { use Clear to end of line's }
  2152.  
  2153.         Addbuf( ANSIClrEOL );
  2154.  
  2155.       END
  2156.       ELSE
  2157.  
  2158.       (*
  2159.       { does the left-edge of the win = left-edge of screen? }
  2160.  
  2161.       If WinX1=0 Then
  2162.       BEGIN
  2163.  
  2164.         { use Clear to START of line's }
  2165.  
  2166.         AddBuf( AnsiGotoXY( WinX2+1, CurY+1 ) );
  2167.         Addbuf( ANSIClrSOL                    );
  2168.         AddBuf( AnsiGotoXY( CurX+1, CurY+1  ) );
  2169.  
  2170.       END
  2171.       ELSE
  2172.       *)
  2173.  
  2174.       BEGIN
  2175.  
  2176.         { otherwise use spaces }
  2177.  
  2178.         S := RepeatString( ' ', (WinX2-WinX1)+1 );
  2179.  
  2180.         Addbuf( S                            );
  2181.  
  2182.         MyKnownCurXY( Curx+Length(S), CurY );
  2183.  
  2184.         MySyncCurXY;
  2185.  
  2186.         { MyGotoXY( CurX+1, CurY+1 ); }
  2187.         { AddBuf( AnsiGotoXY( CurX+1, CurY+1 ) ); }
  2188.  
  2189.       END; { if winx2=cols/else if winx1=1/else }
  2190.  
  2191.       {$IFDEF CHECKCURSOR}
  2192.         CheckCurXY;
  2193.       {$ENDIF}
  2194.  
  2195.     END; { with as^ }
  2196.  
  2197.   END; { procedure MyClrEol }
  2198.  
  2199.  
  2200.   {────────────────────────────────────────────────────────────────────────}
  2201.  
  2202.   Function  CursorNextChar(       Sync           : BOOLEAN   ):WORD;
  2203.  
  2204.   Var
  2205.    Ret : WORD;
  2206.  
  2207.   BEGIN
  2208.  
  2209.     Ret := 0;
  2210.  
  2211.     With   AS^ Do
  2212.     BEGIN
  2213.  
  2214.       { if the window is the same size as the screen }
  2215.  
  2216.       If WinIsScreen Then
  2217.       BEGIN
  2218.  
  2219.         Inc( CurX );
  2220.         Inc( KnownCurX );
  2221.  
  2222.         If CurX>WinX2 Then
  2223.         BEGIN
  2224.  
  2225.           CurX      := 0;
  2226.           KnownCurX := 0;
  2227.  
  2228.           If CurY<WinY2 Then
  2229.           BEGIN
  2230.             Inc( CurY );
  2231.             Inc( KnownCurY );
  2232.           END;
  2233.  
  2234.         END;
  2235.  
  2236.         {$IFDEF CHECKCURSOR}
  2237.           CheckCurXY;
  2238.         {$ENDIF}
  2239.  
  2240.       END  { if window is same size as screen }
  2241.       ELSE
  2242.       BEGIN
  2243.  
  2244.         Inc( CurX );
  2245.         Inc( KnownCurX );
  2246.  
  2247.         { here we see if the known has changed because  }
  2248.         { we moved past the edge of the physical screen }
  2249.  
  2250.         If (AS^.Winx2=IData^.Cols-1) Then
  2251.         BEGIN
  2252.           KnownCurx := 0;
  2253.           If AS^.CurY<Idata^.Rows-1 Then
  2254.             Inc( KnownCurY );
  2255.         END;
  2256.  
  2257.         { if past right-edge of window }
  2258.  
  2259.         If CurX>WinX2 Then
  2260.         BEGIN
  2261.  
  2262.           CurX := winX1;
  2263.  
  2264.           { if not at bottom-edgeof window }
  2265.  
  2266.           If CurY<WinY2 Then
  2267.           BEGIN
  2268.  
  2269.             Inc( CurY );
  2270.  
  2271.             MySyncCurXY;
  2272.  
  2273.             { AddBuf( AnsiGotoXY( CurX+1, CurY+1 ) ); }
  2274.  
  2275.           END
  2276.           ELSE
  2277.           BEGIN
  2278.  
  2279.  
  2280.             { AddBuf( AnsiGotoXY( CurX+1, CurY+1 ) ); }
  2281.  
  2282.             MySyncCurXy;
  2283.  
  2284.             { clear this line since it "scrolled" }
  2285.  
  2286.             MyClrEol;
  2287.  
  2288.             { we are at the bottom edge }
  2289.             { inform filters before us on the stack that we need a scroll }
  2290.  
  2291.             ODP^.Status    := ODS_CantDo;
  2292.             ODP^.StatusMsg := ODS_MsgNeedScrollUp;
  2293.  
  2294.             Ret := 1;
  2295.  
  2296.           END;
  2297.  
  2298.           { put the cursor to where we will want it }
  2299.         END;
  2300.  
  2301.         {$IFDEF CHECKCURSOR}
  2302.           CheckCurXY;
  2303.         {$ENDIF}
  2304.  
  2305.       END; { if window is same size as screen / else }
  2306.  
  2307.       (*
  2308.       If (Sync) and (IData^.VirtualCRT=FALSE) Then
  2309.         RealCursorGoto( IData^.AScreen-1, CurX, CurY );
  2310.       *)
  2311.  
  2312.     END; { With AS^ }
  2313.  
  2314.     CursorNextChar := Ret;
  2315.  
  2316.   END; { CursorNextChar }
  2317.  
  2318.   {────────────────────────────────────────────────────────────────────────}
  2319.  
  2320.   Function MyWriteChar( CH : CHAR ):WORD;
  2321.  
  2322.   Var
  2323.  
  2324.     Ret : WORD;
  2325.  
  2326.   BEGIN
  2327.  
  2328.     Ret := 0;
  2329.  
  2330.     With AS^ Do
  2331.     BEGIN
  2332.  
  2333.       Case Ch Of
  2334.  
  2335.         #13:
  2336.         BEGIN
  2337.  
  2338.           If WinX1=1 Then
  2339.             AddBufCh( #13 )
  2340.           ELSE
  2341.           BEGIN
  2342.             CurX := WinX1;
  2343.             MySyncCurXY;
  2344.  
  2345.             { AddBuf( AnsiGotoXY( CurX+1, CurY+1 ) ); }
  2346.           END;
  2347.  
  2348.         END;  { #13 }
  2349.  
  2350.         #10:
  2351.         BEGIN
  2352.  
  2353.           If WinIsScreen Then
  2354.           BEGIN
  2355.  
  2356.             AddBufCh( #10 );
  2357.  
  2358.             If CurY<WinY2 Then
  2359.             BEGIN
  2360.               Inc( CurY );
  2361.               Inc( KnownCurY );
  2362.             END;
  2363.  
  2364.             {$IFDEF CHECKCURSOR}
  2365.               CheckCurXY;
  2366.             {$ENDIF}
  2367.  
  2368.           END  { if winy2=rows / else }
  2369.           ELSE
  2370.           BEGIN
  2371.  
  2372.             { if not at bottom-edge of window }
  2373.  
  2374.             If CurY<WinY2 Then
  2375.             BEGIN
  2376.  
  2377.               { move down a line }
  2378.  
  2379.               AddBufCh( #10 );
  2380.               Inc( CurY );
  2381.               Inc( KnownCurY );
  2382.  
  2383.               {$IFDEF CHECKCURSOR}
  2384.                 CheckCurXY;
  2385.               {$ENDIF}
  2386.  
  2387.             END
  2388.             ELSE
  2389.             BEGIN
  2390.  
  2391.               { at bottom edge of window, so }
  2392.               { scroll the window up         }
  2393.               { by telling filters before    }
  2394.               { us on the stack we need a    }
  2395.               { scroll.                      }
  2396.  
  2397.               ODP^.Status    := ODS_CantDo;
  2398.               ODP^.StatusMsg := ODS_MsgNeedScrollUp;
  2399.  
  2400.               Ret := 1;
  2401.  
  2402.               { scroll window }
  2403.             END;
  2404.  
  2405.           END;  { if winy2=rows / else }
  2406.  
  2407.           { CursorDown( TRUE ); }
  2408.  
  2409.         END;  { #10 }
  2410.  
  2411.         #26:AddbufCh( CH );
  2412.  
  2413.       Else
  2414.  
  2415.         AddBufCh( Ch );
  2416.  
  2417.         Ret := CursorNextChar( TRUE );
  2418.  
  2419.       END;  { Case Ch }
  2420.  
  2421.     END; { With AS^ }
  2422.  
  2423.     MyWriteChar := Ret;
  2424.  
  2425.   END; { MyWriteChar }
  2426.  
  2427.   {────────────────────────────────────────────────────────────────────────}
  2428.  
  2429.   Procedure SwapCoords( Var A,B : WORD );
  2430.  
  2431.   Var
  2432.     Temp : WORD;
  2433.  
  2434.   BEGIN
  2435.  
  2436.     Temp := A;
  2437.     A    := B;
  2438.     B    := Temp;
  2439.  
  2440.   END;  { SwapCoords }
  2441.  
  2442.   {────────────────────────────────────────────────────────────────────────}
  2443.  
  2444.   Procedure MyWriteRegion;
  2445.  
  2446.   Var
  2447.     YLoop    : INTEGER;
  2448.     XLoop    : INTEGER;
  2449.     StoreOfs : WORD;
  2450.     SaveAttr : BYTE;
  2451.     LastAttr : BYTE;
  2452.     NewCell  : TCell;
  2453.  
  2454.   BEGIN
  2455.  
  2456.     With AS^ Do
  2457.     BEGIN
  2458.  
  2459.       {-------------------------------}
  2460.       { save the xy position and attr }
  2461.       {-------------------------------}
  2462.  
  2463.       AddBuf( ANSISavePos );
  2464.  
  2465.       SaveAttr := AS^.CurAttr;
  2466.  
  2467.       {-------------------------------}
  2468.       { setup variables used in loops }
  2469.       {-------------------------------}
  2470.  
  2471.       StoreOfs :=0;  {offset into region store buffer }
  2472.  
  2473.       LastAttr := AS^.curAttr;
  2474.  
  2475.       {---------------}
  2476.       { for each line }
  2477.       {---------------}
  2478.  
  2479.       For YLoop := ODP^.Y1 To ODP^.Y2 Do
  2480.       BEGIN
  2481.  
  2482.         { ^!^ do goto optimizations!!! }
  2483.  
  2484.         { goto }
  2485.  
  2486.         AddBuf( ANSIGotoXY( ODP^.X1, YLoop ) );
  2487.  
  2488.         { for each cell in the line }
  2489.  
  2490.         For XLoop := ODP^.X1 To ODP^.X2 Do
  2491.         BEGIN
  2492.  
  2493.           { get the new cell }
  2494.  
  2495.           NewCell := PScreenStore( ODP^.Region )^[StoreOfs];
  2496.  
  2497.           MyTextAttr( NewCell.Attr );
  2498.  
  2499.           (*
  2500.           { if the newcell's attr <> the lastattr, update attr }
  2501.  
  2502.           If NewCell.Attr<>LastAttr Then
  2503.           BEGIN
  2504.             AddBuf( ANSITextAttr( NewCell.Attr ) );
  2505.             LastAttr := NewCell.Attr;
  2506.           END;
  2507.           *)
  2508.  
  2509.           { write out the character }
  2510.  
  2511.           AddBufCh( NewCell.Char );
  2512.  
  2513.           { move our offset }
  2514.  
  2515.           Inc( StoreOfs );
  2516.  
  2517.         END; { for xloop }
  2518.  
  2519.       END; { for yloop }
  2520.  
  2521.       {--------------------------------}
  2522.       { restore the attr and cursor xy }
  2523.       {--------------------------------}
  2524.  
  2525.       (*
  2526.       If LastAttr<>SaveAttr Then
  2527.         Addbuf( ANSITextAttr( SaveAttr ) );
  2528.       *)
  2529.  
  2530.       { MyTextAttr( SaveAttr ) }
  2531.  
  2532.       Addbuf( ANSIRestorePos );
  2533.  
  2534.     END; { with AS^ }
  2535.  
  2536.   END; { procedure MyWriteRegion }
  2537.  
  2538.   {────────────────────────────────────────────────────────────────────────}
  2539.  
  2540.  
  2541.  
  2542.  
  2543. BEGIN  { ANSIOutDriverProc }
  2544.  
  2545.   IData := ODP^.ID;
  2546.  
  2547.   If ODP^.Func<> ODF_DriverNew Then
  2548.   BEGIN
  2549.  
  2550.     AS    := @IData^.Screen[ IData^.AScreen ];
  2551.     YMult := IData^.YMult;
  2552.  
  2553.   END;  { ODP^.Func }
  2554.  
  2555.  
  2556.   If ODP^.Status = 0 Then
  2557.   BEGIN
  2558.  
  2559.     Case ODP^.Func Of
  2560.  
  2561.       ODF_DriverNew:
  2562.       BEGIN
  2563.  
  2564.         If @ODP^.OutDriverProc = @ANSIOutDriverProc Then
  2565.         BEGIN
  2566.  
  2567.           {-------------------------}
  2568.           { Get a new Instance Data }
  2569.           { master node.            }
  2570.           {-------------------------}
  2571.  
  2572.           New( Idata );
  2573.  
  2574.           InitIData;
  2575.  
  2576.           {--------}
  2577.           { Return }
  2578.           {--------}
  2579.  
  2580.           ODP^.Status    := ODS_Install+ODS_Changed;
  2581.  
  2582.           ODP^.ID        := IData;
  2583.  
  2584.         END; { If ODP^.OutDriverProc --> Us }
  2585.  
  2586.       END; { ODF_DriverNew }
  2587.  
  2588.       {----}
  2589.  
  2590.       ODF_DriverOff:
  2591.       BEGIN
  2592.  
  2593.         If ODP^.Name^ = IData^.Name Then
  2594.         BEGIN
  2595.  
  2596.           Inc( Idata^.Off );
  2597.  
  2598.         END;  { If ODP^.Name^ }
  2599.  
  2600.       END;  { ODF_DriverOff }
  2601.  
  2602.       {----}
  2603.  
  2604.       ODF_DriverOn:
  2605.       BEGIN
  2606.  
  2607.         If ODP^.Name^ = IData^.Name Then
  2608.         BEGIN
  2609.  
  2610.           If Idata^.Off <> 0 Then
  2611.             Dec( Idata^.Off );
  2612.  
  2613.         END;  { ODP^.Name^ }
  2614.  
  2615.       END;  { ODF_DriverOn }
  2616.  
  2617.       {----}
  2618.  
  2619.       ODF_DriverDispose:
  2620.       BEGIN
  2621.  
  2622.         If ODP^.Name^ = IData^.Name Then
  2623.         BEGIN
  2624.  
  2625.           {-----------------------------}
  2626.           { Remove from OutDriver stack }
  2627.           {-----------------------------}
  2628.  
  2629.           Dispose( IData );
  2630.  
  2631.         END;  { If ODP^.Name^ }
  2632.  
  2633.       END;  { ODF_DriverDispose }
  2634.  
  2635.       {----}
  2636.  
  2637.       ODF_WriteChar:
  2638.       BEGIN
  2639.  
  2640.         MySyncAttr;
  2641.         MySyncCurXY;
  2642.  
  2643.         MyWriteChar( ODP^.CH );
  2644.  
  2645. (*
  2646.         ChkTextAttr;
  2647.  
  2648.         AddBufCh( ODP^.Ch );
  2649. *)
  2650.  
  2651.       END;  { ODF_WriteChar }
  2652.  
  2653.       {----}
  2654.  
  2655.       ODF_WriteBlock:
  2656.       BEGIN
  2657.  
  2658.         ChkTextAttr;
  2659.  
  2660.         MySyncAttr;
  2661.  
  2662.         MySyncCurXY;
  2663.  
  2664.         (*
  2665.  
  2666.         Z2 := ODP^.NumVal;
  2667.         Z3 := ODP^.Size;
  2668.  
  2669.         {-----------------------}
  2670.         { anything left to do ? }
  2671.         {-----------------------}
  2672.  
  2673.         If (Z2<Z3) Then
  2674.         BEGIN
  2675.  
  2676.           P := Addr( TCharArray( ODP^.Buff^)[Z2] );
  2677.  
  2678.           ASM
  2679.  
  2680.             PUSH DS
  2681.  
  2682.             { setup the registers }
  2683.  
  2684.             MOV CX, Z3             { get total                    }
  2685.             SUB CX, Z2             { subtract amount already done }
  2686.  
  2687.             LDS SI, dword PTR [P]  { make DS:SI = p }
  2688.  
  2689.             CLD                    { go forward...                }
  2690.  
  2691.             { loop through the buffer }
  2692.  
  2693.            @@1:
  2694.  
  2695.             LODSB                  { get the character }
  2696.             PUSH AX                { push the char (param) }
  2697.             CALL MyWriteChar       { call the write }
  2698.             CMP  AX, 1             { Q: did write say scroll? }
  2699.             JE   @@2               {    Y: get outa here... }
  2700.  
  2701.             LOOP @@1               { loop de loop }
  2702.  
  2703.             { we did all the characters }
  2704.  
  2705.             MOV BX, Z3             { get total }
  2706.             MOV Z2, BX             { we did em all. }
  2707.             MOV Z,  0              { we dont need a scroll }
  2708.  
  2709.             JMP @@3                { get outa here }
  2710.  
  2711.            @@2:
  2712.  
  2713.             { write func said to scroll }
  2714.  
  2715.             MOV BX, Z3             { get total }
  2716.             SUB BX, CX             { subtract # of chars left }
  2717.             MOV Z2, BX             { store it as # of chars done }
  2718.             MOV Z,  1              { we need a scroll }
  2719.  
  2720.            @@3:
  2721.  
  2722.             POP DS
  2723.  
  2724.           END; { asm }
  2725.  
  2726.           IF Z=1 Then
  2727.           BEGIN
  2728.             ODP^.Status    := ODS_CantDo;
  2729.             ODP^.StatusMsg := ODS_MsgNeedScrollUp;
  2730.           END;
  2731.  
  2732.         END; { if z2<>z3 (stuff left) }
  2733.  
  2734.         *)
  2735.  
  2736.         Z  := ODP^.Start;
  2737.         Z2 := ODP^.Size;
  2738.         Z3 := 0;
  2739.  
  2740.         While (Z<=Z2) and (Z3=0) Do
  2741.         BEGIN
  2742.  
  2743.           Z3:=MyWriteChar( TCharArray(ODP^.Buff^)[Z] );
  2744.  
  2745.           Inc( Z );
  2746.  
  2747.         END;
  2748.  
  2749.         If Z>ODP^.Size Then
  2750.           ODP^.Start := ODP^.Size
  2751.         ELSE
  2752.           ODP^.Start := Z;
  2753.  
  2754.         { ODP^.NumVal := Z-1; }
  2755.  
  2756.         If Z3=1 Then
  2757.         BEGIN
  2758.           ODP^.Status    := ODS_CantDo;
  2759.           ODP^.StatusMsg := ODS_MsgNeedScrollUp;
  2760.         END;
  2761.  
  2762.  
  2763.         (*
  2764.         For Z := ODP^.NumVal to ODP^.Size Do
  2765.           MyWriteChar( TCharArray(ODP^.Buff^)[Z] );
  2766.         *)
  2767.  
  2768.       END;  { ODF_WriteBlock }
  2769.  
  2770.       {----}
  2771.  
  2772.       ODF_WriteVert:
  2773.       BEGIN
  2774.  
  2775.         ChkTextAttr;
  2776.  
  2777.         MySyncAttr;
  2778.         MySyncCurXY;
  2779.  
  2780.         { how about when it writes vert out of the window }
  2781.  
  2782.         For Z := 1 to ODP^.Size Do
  2783.         BEGIN
  2784.  
  2785.           AddBufCh( TCharArray(ODP^.Buff^)[Z] );
  2786.           AddBuf( ANSIGotoXY(Pred(WhereX), Succ(WhereY)) );
  2787.  
  2788.         END;
  2789.  
  2790.       END;  { ODF_WriteVert }
  2791.  
  2792.       {----}
  2793.  
  2794.       ODF_WriteCharAt:
  2795.       BEGIN
  2796.  
  2797.         {!^! goto optimizations!}
  2798.  
  2799.         AddBuf( ANSISavePos );
  2800.  
  2801.         AddBuf( ANSIGotoXY(ODP^.X1, ODP^.Y1) );
  2802.  
  2803.         ChkTextAttr;
  2804.  
  2805.         MyTextAttr( ODP^.Attr );
  2806.  
  2807.  
  2808.         AddBufCh( ODP^.Ch );
  2809.  
  2810.         AddBuf( ANSIRestorePos );
  2811.  
  2812.       END;  { ODF_WriteCharAt }
  2813.  
  2814.       {----}
  2815.  
  2816.       ODF_WriteBlockAt:
  2817.       BEGIN
  2818.  
  2819.  
  2820.         SaveCurX  := AS^.CurX;
  2821.         SaveCurY  := AS^.CurY;
  2822.         SaveWinX1 := AS^.WinX1;
  2823.         SaveWinY1 := AS^.WinY1;
  2824.         SaveWinX2 := AS^.WinX2;
  2825.         SaveWinY2 := AS^.WinY2;
  2826.  
  2827.         { AddBuf( ANSISavePos ); }
  2828.  
  2829.         { MyKnownGotoXY( ODP^.X1, ODP^.Y1 ); }
  2830.  
  2831.         AS^.CurX := ODP^.X1-1;
  2832.         AS^.CurY := ODP^.Y1-1;
  2833.  
  2834.         AS^.WinX1:= 0;
  2835.         AS^.WinY1:= 0;
  2836.         AS^.WinX2:= IData^.Cols-1;
  2837.         AS^.WinY2:= IData^.Rows-1;
  2838.  
  2839.         MySyncCurXY;
  2840.  
  2841.         { MySyncGotoXY( ODP^.X1, ODP^.Y1 ); }
  2842.  
  2843.         { AddBuf( ANSIGotoXY(ODP^.X1, ODP^.Y1) ); }
  2844.  
  2845.         ChkTextAttr;
  2846.  
  2847.         MyTextAttr( ODP^.Attr );
  2848.  
  2849.  
  2850.         (*
  2851.         SaveAttr := AS^.CurAttr;
  2852.  
  2853.         If ODP^.Attr<>SaveAttr Then
  2854.           AddBuf( AnsiTextAttr( ODP^.Attr ) );
  2855.         *)
  2856.  
  2857.  
  2858.         {-}
  2859.  
  2860.         Z  := 1;
  2861.         Z2 := ODP^.Size;
  2862.         Z3 := 0;
  2863.  
  2864.         While (Z<=Z2) and (Z3=0) Do
  2865.         BEGIN
  2866.  
  2867.           Z3:=MyWriteChar( TCharArray(ODP^.Buff^)[Z] );
  2868.  
  2869.           Inc( Z );
  2870.  
  2871.         END;
  2872.  
  2873.         ODP^.NumVal := Z-1;
  2874.  
  2875.         If Z3=1 Then
  2876.         BEGIN
  2877.           ODP^.Status    := ODS_CantDo;
  2878.           ODP^.StatusMsg := ODS_MsgNeedScrollUp;
  2879.         END;
  2880.  
  2881.         ODP^.Status := 0;
  2882.  
  2883.         {-}
  2884.  
  2885. (*
  2886.         For Z := 1 to ODP^.Size Do
  2887.           AddBufCh( TCharArray(ODP^.Buff^)[Z] );
  2888. *)
  2889.  
  2890.  
  2891. (*
  2892.         If ODP^.Attr<>SaveAttr Then
  2893.           AddBuf( AnsiTextAttr( SaveAttr ) );
  2894. *)
  2895.  
  2896.         {!^! JRT NEW!}
  2897.         AS^.CurAttr := SaveAttr;
  2898.  
  2899.         { Addbuf( AnsiGotoXY( SaveCurX+1, SaveCurY+1 ) ); }
  2900.  
  2901.         AS^.WinX1:= SaveWinX1;
  2902.         AS^.WinY1:= SaveWinY1;
  2903.         AS^.WinX2:= SaveWinX2;
  2904.         AS^.WinY2:= SaveWinY2;
  2905.  
  2906.         AS^.CurX := SaveCurX;
  2907.         AS^.CurY := SaveCurY;
  2908.  
  2909.         MySyncCurXY;
  2910.  
  2911.         { AddBuf( ANSIRestorePos ); }
  2912.  
  2913.       END;  { ODF_WriteBlockAt }
  2914.  
  2915.       {----}
  2916.  
  2917.       ODF_WriteVertAt:
  2918.       BEGIN
  2919.  
  2920.         AddBuf( ANSISavePos );
  2921.  
  2922.         AddBuf( ANSIGotoXY(ODP^.X1, ODP^.Y1) );
  2923.  
  2924.         { MyKnownGotoXY( ODP^.X, ODP^.Y1 ); }
  2925.  
  2926.         {!^! JRT NEW }
  2927.         SaveAttr := AS^.CurAttr;
  2928.  
  2929.         ChkTextAttr;
  2930.  
  2931.         MyTextAttr( ODP^.Attr );
  2932.  
  2933.         For Z := 1 to ODP^.Size Do
  2934.         BEGIN
  2935.  
  2936.           AddBufCh( TCharArray(ODP^.Buff^)[Z] );
  2937.           {AddBuf( ANSIGotoXY(Pred(WhereX), Succ(WhereY)) );}
  2938.  
  2939.         END;
  2940.  
  2941.         {!^! JRT NEW}
  2942.         AS^.CurAttr := SaveAttr;
  2943.  
  2944.         AddBuf( ANSIRestorePos );
  2945.  
  2946.       END;  { ODF_WriteVertAt }
  2947.  
  2948.       {----}
  2949.  
  2950.       ODF_ClrEOL: MyClrEol;
  2951.  
  2952.       {----}
  2953.  
  2954.       ODF_ClrScr:
  2955.       BEGIN
  2956.  
  2957.         With AS^ DO
  2958.         BEGIN
  2959.  
  2960.           MySyncAttr;
  2961.           MySyncCurXY;
  2962.  
  2963.           If WinIsScreen Then
  2964.           BEGIN
  2965.  
  2966.             { use a clear screen }
  2967.  
  2968.             AddBuf( ANSIClrScr );
  2969.  
  2970.             CurX := 0;
  2971.             CurY := 0;
  2972.  
  2973.             KnownCurX := 0;
  2974.             KnownCurY := 0;
  2975.  
  2976.             {$IFDEF CHECKCURSOR}
  2977.               CheckCurXY;
  2978.             {$ENDIF}
  2979.  
  2980.           END  { if window=screen }
  2981.           ELSE
  2982.           BEGIN
  2983.  
  2984.             { does the right-edge of the window = right-edge of screen? }
  2985.  
  2986.             If WinX2=Idata^.Cols-1 Then
  2987.             BEGIN
  2988.  
  2989.               { use Clear to end of line's }
  2990.  
  2991.               For Z:=WinY1 To WinY2 Do
  2992.               BEGIN
  2993.                 MyKnownGotoXY( WinX1+1, Z+1 );
  2994.                 { Addbuf( ANSIGotoXY( WinX1+1, Z+1 ) ); }
  2995.                 Addbuf( ANSIClrEOL               )
  2996.               END;
  2997.  
  2998.             END
  2999.             ELSE
  3000.  
  3001.             (*
  3002.             { does the left-edge of the win = left-edge of screen? }
  3003.  
  3004.             If WinX1=0 Then
  3005.             BEGIN
  3006.  
  3007.               { use Clear to START of line's }
  3008.  
  3009.               For Z:=WinY1 To WinY2 Do
  3010.               BEGIN
  3011.                 Addbuf( ANSIGotoXY( WinX2+1, Z+1 ) );
  3012.                 Addbuf( ANSIClrSOL               )
  3013.               END;
  3014.  
  3015.             END
  3016.             ELSE
  3017.  
  3018.             *)
  3019.  
  3020.             BEGIN
  3021.  
  3022.               { otherwise use spaces }
  3023.  
  3024.               S := RepeatString( ' ', (WinX2-WinX1)+1 );
  3025.  
  3026.               For Z:=WinY1 To WinY2 Do
  3027.               BEGIN
  3028.                 MyKnownGotoXY( WinX1+1, Z+1 );
  3029.                 { Addbuf( ANSIGotoXY( WinX1+1, Z+1 ) ); }
  3030.                 Addbuf( S                        )
  3031.               END;
  3032.  
  3033.             END; { if winx2=cols/else if winx1=1/else }
  3034.  
  3035.             CurX := WinX1;
  3036.             CurY := WinY1;
  3037.  
  3038.             MySyncCurXy;
  3039.  
  3040.             { AddBuf( ANSIGotoXY( CurX+1, CurY+1 ) ); }
  3041.  
  3042.             {$IFDEF CHECKCURSOR}
  3043.               CheckCurXY;
  3044.             {$ENDIF}
  3045.  
  3046.           END; { if window=screen / else }
  3047.  
  3048.         END; { with as^ }
  3049.  
  3050.       END;
  3051.  
  3052.       {----}
  3053.  
  3054.       ODF_DelLine:
  3055.       BEGIN
  3056.  
  3057.         MySyncAttr;
  3058.         MySyncCurXY;
  3059.  
  3060.         AddBuf( ANSIDelLine );
  3061.  
  3062.       END;
  3063.  
  3064.       {----}
  3065.  
  3066.       ODF_InsLine:
  3067.       BEGIN
  3068.  
  3069.         MySyncAttr;
  3070.         MySyncCurXY;
  3071.  
  3072.         AddBuf( ANSIInsLine );
  3073.  
  3074.       END;
  3075.  
  3076.       {----}
  3077.  
  3078.       ODF_GotoXY:
  3079.       BEGIN
  3080.  
  3081.         With AS^ Do
  3082.         BEGIN
  3083.  
  3084.           CurX := WinX1+(ODP^.X1-1);
  3085.           CurY := WinY1+(ODP^.Y1-1);
  3086.  
  3087.           MySyncCurXY;
  3088.  
  3089.           { AddBuf( ANSIGotoXY( CurX+1, CurY+1 ) ); }
  3090.  
  3091.           {$IFDEF CHECKCURSOR}
  3092.             CheckCurXY;
  3093.           {$ENDIF}
  3094.  
  3095.         END;
  3096.  
  3097.       END;
  3098.  
  3099.       {----}
  3100.  
  3101.       ODF_Window:
  3102.       BEGIN
  3103.  
  3104.         With AS^ Do
  3105.         BEGIN
  3106.  
  3107.           WinX1 := ODP^.X1-1;
  3108.           WinY1 := ODP^.Y1-1;
  3109.           WinX2 := ODP^.X2-1;
  3110.           WinY2 := ODP^.Y2-1;
  3111.  
  3112.           If WinX2<WinX1 Then SwapCoords( WinX1, WinX2 );
  3113.           If WinY2<WinY1 Then SwapCoords( WinY1, WinY2 );
  3114.  
  3115.           WinIsScreen := (winx1=0            ) and (winy1=0            ) and
  3116.                          (Winx2=IData^.Cols-1) and (Winy2=Idata^.rows-1);
  3117.  
  3118.  
  3119.           CurX  := WinX1;
  3120.           CurY  := WinY1;
  3121.  
  3122.           MySyncCurXY;
  3123.  
  3124.           { AddBuf( ANSIGotoXY( CurX+1, CurY+1 ) ); }
  3125.  
  3126.  
  3127. {            RealCursorGoto( IData^.Ascreen-1, CurX, Cury );}
  3128.  
  3129.           { call visionix services to set window coords }
  3130.  
  3131.         END;  { With AS^ }
  3132.  
  3133. (*
  3134.         With IData^.Win[IData^.InWin] Do
  3135.         BEGIN
  3136.  
  3137.           SaveXY      := 0;
  3138.           CursorXY    := (ODP^.Y1 SHL 8) + ODP^.X1;
  3139.           WindMinXY   := (Pred(ODP^.Y1) SHL 8) + Pred(ODP^.X1);
  3140.           WindMaxXY   := (Pred(ODP^.Y2) SHL 8) + Pred(ODP^.X2);
  3141.           CurTextAttr := TextAttr;
  3142.  
  3143.         END;
  3144. *)
  3145.  
  3146.       END;  { ODF_Window }
  3147.  
  3148.       {----}
  3149.  
  3150.       ODF_ColorText:
  3151.       BEGIN
  3152.  
  3153.         With AS^ Do
  3154.         BEGIN
  3155.  
  3156.           CurAttr := (CurAttr AND $F0) + (ODP^.TheColor AND $0F);
  3157.  
  3158.           { AddBuf( ANSITextColor(ODP^.TheColor) ); }
  3159.  
  3160.         END;  { With AS^ }
  3161.  
  3162.       END;
  3163.  
  3164.  
  3165.       {----}
  3166.  
  3167.       ODF_ColorBack:
  3168.       BEGIN
  3169.  
  3170.         With AS^ Do
  3171.         BEGIN
  3172.  
  3173.           CurAttr := (CurAttr AND $0F) + ((ODP^.TheColor AND $07) SHL 4);
  3174.  
  3175.           { AddBuf( ANSITextBackground(ODP^.TheColor) ); }
  3176.  
  3177.         END;  { With AS^ }
  3178.  
  3179.       END;  { ODF_ColorBack }
  3180.  
  3181.  
  3182.       {----}
  3183.  
  3184.       ODF_GetWin:
  3185.       BEGIN
  3186.  
  3187.         With AS^ Do
  3188.         BEGIN
  3189.  
  3190.           ODP^.X1 := WinX1+1;
  3191.           ODP^.Y1 := WinY1+1;
  3192.           ODP^.X2 := WinX2+1;
  3193.           ODP^.Y2 := WinY2+1;
  3194.  
  3195.           ODP^.Status := ODS_Changed;
  3196.  
  3197.         END;  { With AS^ }
  3198.  
  3199.       END;  { ODF_GetWin }
  3200.  
  3201.       {----}
  3202.  
  3203.       ODF_GetAttr:
  3204.       BEGIN
  3205.  
  3206.         ODP^.Attr   := AS^.CurAttr;
  3207.         ODP^.Status := ODS_Changed;
  3208.  
  3209.       END;  { ODF_GetAttr }
  3210.  
  3211.       {----}
  3212.  
  3213.       ODF_SetAttr:
  3214.       BEGIN
  3215.  
  3216.         AS^.CurAttr := ODP^.Attr;
  3217.  
  3218.         { AddBuf( ANSITextAttr(ODP^.Attr) ); }
  3219.  
  3220.       END;  { ODF_SetAttr }
  3221.  
  3222.  
  3223.       {----}
  3224.  
  3225.       ODF_GetXY:
  3226.       BEGIN
  3227.  
  3228.         ODP^.X1 := (AS^.CurX+1)-AS^.WinX1;
  3229.         ODP^.Y1 := (AS^.CurY+1)-AS^.WinY1;
  3230.  
  3231.         ODP^.Status := ODS_Changed;
  3232.  
  3233.       END;  { ODF_GetXY }
  3234.  
  3235.       {----}
  3236.  
  3237.       ODF_GetNumScreens:
  3238.       BEGIN
  3239.  
  3240.  
  3241.         ODP^.Screens := IData^.NumScreens;
  3242.  
  3243.         ODP^.Status  := ODS_Changed;
  3244.  
  3245.       END;  { ODF_GetNumScreens }
  3246.  
  3247.       {----}
  3248.  
  3249.       ODF_GoScreen:
  3250.       BEGIN
  3251.  
  3252.       END;  { ODF_GoScreen }
  3253.  
  3254.       {----}
  3255.  
  3256.       ODF_SetCursorType:
  3257.       BEGIN
  3258.  
  3259.       END;  { ODF_SetCursorType }
  3260.  
  3261.       {----}
  3262.  
  3263.       ODF_DrawVLine:
  3264.       BEGIN
  3265.  
  3266.       END;  { ODF_DrawVLine }
  3267.  
  3268.       {----}
  3269.  
  3270.       ODF_DrawHLine:
  3271.       BEGIN
  3272.  
  3273.       END;  { ODF_DrawHLine }
  3274.  
  3275.       {----}
  3276.  
  3277.       ODF_DrawBox:
  3278.       BEGIN
  3279.  
  3280.       END;  { ODF_DrawBox }
  3281.  
  3282.       {----}
  3283.  
  3284.       ODF_ReadChar:
  3285.       BEGIN
  3286.  
  3287.         ODP^.Status    := ODS_CantDo;
  3288.         ODP^.StatusMsg := ODS_MsgNoScreenBuff;
  3289.  
  3290.       END;  { ODF_ReadChar }
  3291.  
  3292.       {----}
  3293.  
  3294.       ODF_ReadAttr:
  3295.       BEGIN
  3296.  
  3297.         ODP^.Status    := ODS_CantDo;
  3298.         ODP^.StatusMsg := ODS_MsgNoScreenBuff;
  3299.  
  3300.       END;  { ODF_ReadAttr }
  3301.  
  3302.       {----}
  3303.  
  3304.       ODF_WriteAttr:
  3305.       BEGIN
  3306.  
  3307.         MySyncAttr;
  3308.  
  3309.         ODP^.Status    := ODS_CantDo;
  3310.         ODP^.StatusMsg := ODS_MsgNoScreenBuff;
  3311.  
  3312.       END;  { ODF_WriteAttr }
  3313.  
  3314.       {----}
  3315.  
  3316.       ODF_QueryRegion:
  3317.       BEGIN
  3318.  
  3319.         ODP^.Status    := ODS_CantDo;
  3320.         ODP^.StatusMsg := ODS_MsgNoScreenBuff;
  3321.  
  3322.       END;  { ODF_QueryRegion }
  3323.  
  3324.       {----}
  3325.  
  3326.       ODF_ReadRegion:
  3327.       BEGIN
  3328.  
  3329.         ODP^.Status    := ODS_CantDo;
  3330.         ODP^.StatusMsg := ODS_MsgNoScreenBuff;
  3331.  
  3332.       END;  { ODF_ReadRegion }
  3333.  
  3334.       {----}
  3335.  
  3336.       ODF_WriteRegion:
  3337.       BEGIN
  3338.  
  3339.         MyWriteRegion;
  3340.  
  3341.       END;  { ODF_WriteRegion }
  3342.  
  3343.       {----}
  3344.  
  3345.       ODF_DriverRenew:
  3346.       BEGIN
  3347.  
  3348.       END;  { ODF_DriverRenew }
  3349.  
  3350.       {----}
  3351.  
  3352.       ODF_CursorUp:
  3353.       BEGIN
  3354.  
  3355.         With AS^Do
  3356.         BEGIN
  3357.  
  3358.           If CurY-ODP^.NumVal<WinY1 Then
  3359.             CurY:=WinY1
  3360.           ELSE
  3361.             Dec(CurY,ODP^.NumVal);
  3362.  
  3363.           MySyncCurXY;
  3364.  
  3365.           (*
  3366.           For Z:=1 to ODP^.NumVal Do
  3367.             If CurY>WinY1 Then
  3368.             BEGIN
  3369.               Dec(CurY);
  3370.               AddBuf( ANSIUp );
  3371.               Dec(KnownCurY);
  3372.             END;
  3373.           *)
  3374.  
  3375.         END;  { With AS^ }
  3376.  
  3377.       END;  { ODF_CursorUp }
  3378.  
  3379.      {----}
  3380.  
  3381.       ODF_CursorDown:
  3382.       BEGIN
  3383.  
  3384.         With AS^Do
  3385.         BEGIN
  3386.  
  3387.           If CurY+ODP^.NumVal>WinY2 Then
  3388.             CurY:=WinY2
  3389.           ELSE
  3390.             Inc(CurY,ODP^.NumVal);
  3391.  
  3392.           MySyncCurXY;
  3393.  
  3394.           (*
  3395.  
  3396.           For Z:=1 to ODP^.NumVal Do
  3397.             If CurY<WinY2 Then
  3398.             BEGIN
  3399.               Inc(CurY);
  3400.               AddBuf( ANSIDown );
  3401.               Inc(KnownCurY);
  3402.             END;
  3403.  
  3404.           *)
  3405.  
  3406.         END;  { With AS^ }
  3407.  
  3408.       END;  { ODF_CursorDown }
  3409.  
  3410.      {----}
  3411.  
  3412.       ODF_CursorLeft:
  3413.       BEGIN
  3414.  
  3415.         With AS^ Do
  3416.         BEGIN
  3417.  
  3418.           If CurX-ODP^.NumVal<WinX1 Then
  3419.             CurX:=WinX1
  3420.           ELSE
  3421.             Dec(CurX,ODP^.NumVal);
  3422.  
  3423.           MySyncCurXY;
  3424.  
  3425.           (*
  3426.           For Z:=1 to ODP^.Numval Do
  3427.             If CurX>WinX1 Then
  3428.             BEGIN
  3429.               Dec(CurX);
  3430.               AddBuf( ANSILeft );
  3431.               Dec(KnownCurX);
  3432.             END;
  3433.           *)
  3434.  
  3435.         END;  { With AS^ }
  3436.  
  3437.       END;  { ODF_CursorLeft }
  3438.  
  3439.      {----}
  3440.  
  3441.       ODF_CursorRight:
  3442.       BEGIN
  3443.  
  3444.         With AS^Do
  3445.         BEGIN
  3446.  
  3447.           If CurX+ODP^.NumVal>WinX2 Then
  3448.             CurX:=WinX2
  3449.           ELSE
  3450.             Inc(CurX,ODP^.NumVal);
  3451.  
  3452.           MySyncCurXY;
  3453.  
  3454.           (*
  3455.           For Z:=1 to ODP^.Numval Do
  3456.             If CurX<WinX2 Then
  3457.             BEGIN
  3458.               Inc(CurX);
  3459.               AddBuf( ANSIRight );
  3460.               Inc(KnownCurX);
  3461.             END;
  3462.           *)
  3463.  
  3464.         END;  { With AS^ }
  3465.  
  3466.       END;  { ODF_CursorRight }
  3467.  
  3468.      {----}
  3469.  
  3470.       ODF_RegionScrUp:
  3471.       BEGIN
  3472.  
  3473.       (*
  3474.  
  3475.       If (winx1=x1) and (winx2=x2)
  3476.  
  3477.  
  3478.       *)
  3479.  
  3480.       END;  { ODF_RegionScrUp }
  3481.  
  3482.      {----}
  3483.  
  3484.       ODF_RegionScrDown:
  3485.       BEGIN
  3486.  
  3487.       END;  { ODF_RegionScrDown }
  3488.  
  3489.      {----}
  3490.  
  3491.       ODF_RegionCopy:
  3492.       BEGIN
  3493.  
  3494.       END;  { ODF_RegionCopy }
  3495.  
  3496.      {----}
  3497.  
  3498.       ODF_RegionFill:
  3499.       BEGIN
  3500.         With AS^ DO
  3501.         BEGIN
  3502.  
  3503.            AddBuf( ANSISavePos );
  3504.  
  3505.            MyTextAttr( ODP^.Attr );
  3506.  
  3507.            S := RepeatString( ODP^.CH, (ODP^.X2-ODP^.X1)+1 );
  3508.  
  3509.            For Z:=ODP^.Y1 To ODP^.Y2 Do
  3510.            BEGIN
  3511.              AddBuf( ANSIGotoXY( ODP^.X1, Z ) );
  3512.              Addbuf( S                        )
  3513.            END;
  3514.  
  3515.            AddBuf( AnsiRestorePos );
  3516.  
  3517.         END;
  3518.  
  3519.       END;  { ODF_RegionFill }
  3520.  
  3521.      {----}
  3522.  
  3523.       ODF_RegionFillA:
  3524.       BEGIN
  3525.         ODP^.Status    := ODS_CantDo;
  3526.         ODP^.StatusMsg := ODS_MsgNoScreenBuff;
  3527.       END;  { ODF_RegionFillA }
  3528.  
  3529.      {----}
  3530.  
  3531.       ODF_RegionFillC:
  3532.       BEGIN
  3533.         ODP^.Status    := ODS_CantDo;
  3534.         ODP^.StatusMsg := ODS_MsgNoScreenBuff;
  3535.       END;  { ODF_RegionFillC }
  3536.  
  3537.      {----}
  3538.  
  3539.       ODF_RepeatChar:
  3540.       BEGIN
  3541.  
  3542.         MySyncAttr;
  3543.         MySyncCurXY;
  3544.  
  3545.         If (ODP^.CH <> #13) AND (ODP^.CH <> #10) Then
  3546.           For Z := 1 to ODP^.NumVal Do
  3547.             AddBufCh( ODP^.Ch );
  3548.  
  3549.       END;  { ODF_RepeatChar }
  3550.  
  3551.      {----}
  3552.  
  3553.       ODF_RepeatCharAt:
  3554.       BEGIN
  3555.  
  3556.         { goto optimizations! }
  3557.  
  3558.         AddBuf( ANSISavePos );
  3559.  
  3560.         AddBuf( ANSIGotoXY(ODP^.X1, ODP^.Y1) );
  3561.  
  3562.         MyTextAttr( ODP^.Attr );
  3563.  
  3564.         If (ODP^.CH <> #13) AND (ODP^.CH <> #10) Then
  3565.           For Z := 1 to ODP^.NumVal Do
  3566.             AddBufCh( ODP^.Ch );
  3567.  
  3568.         AddBuf( ANSIRestorePos );
  3569.  
  3570.       END;  { ODF_RepeatCharAt }
  3571.  
  3572.      {----}
  3573.  
  3574.       ODF_GetScreenSize:
  3575.       BEGIN
  3576.  
  3577.         With AS^ Do
  3578.         BEGIN
  3579.  
  3580.           ODP^.X1 := IData^.Cols;
  3581.           ODP^.Y1 := Idata^.Rows;
  3582.  
  3583.         END;  { With AS^ }
  3584.  
  3585.       END;  { ODF_GetScreenSize }
  3586.  
  3587.      {----}
  3588.  
  3589.       ODF_RepeatBlock:
  3590.       BEGIN
  3591.  
  3592.         ChkTextAttr;
  3593.  
  3594.         MySyncAttr;
  3595.  
  3596.         MySyncCurXY;
  3597.  
  3598.         Z  := ODP^.Start;
  3599.         Z2 := ODP^.Size;
  3600.         Z3 := 0;
  3601.  
  3602.         While (ODP^.NumVal>0) and (Z3=0) Do
  3603.         BEGIN
  3604.  
  3605.           While (Z<=Z2) and (Z3=0) Do
  3606.           BEGIN
  3607.  
  3608.             Z3:=MyWriteChar( TCharArray(ODP^.Buff^)[Z] );
  3609.  
  3610.             Inc( Z );
  3611.  
  3612.           END;
  3613.  
  3614.           IF Z>Z2 Then
  3615.           BEGIN
  3616.             Dec( ODP^.NumVal);
  3617.             If ODP^.NumVal>0 Then
  3618.               Z:=1;
  3619.           END;
  3620.  
  3621.         END; { while ODP^.numval>0 }
  3622.  
  3623.         If Z>ODP^.Size Then
  3624.           ODP^.Start := ODP^.Size
  3625.         ELSE
  3626.           ODP^.Start := Z;
  3627.  
  3628.         If Z3=1 Then
  3629.         BEGIN
  3630.           ODP^.Status    := ODS_CantDo;
  3631.           ODP^.StatusMsg := ODS_MsgNeedScrollUp;
  3632.         END;
  3633.  
  3634.       END;  { ODF_WriteBlock }
  3635.  
  3636.  
  3637.      {----}
  3638.  
  3639.      ODF_FlushBuffers:
  3640.      BEGIN
  3641.  
  3642.        FlushBuff;
  3643.  
  3644.      END;
  3645.  
  3646.  
  3647.      {----}
  3648.  
  3649.     Else { Else Case }
  3650.  
  3651.     END;  { Case ODP^.Func }
  3652.  
  3653.     FlushBuff;
  3654.  
  3655.   END; { If ODP^.Status = 0 }
  3656.  
  3657. END;  { ANSIOutDriverProc }
  3658.  
  3659. {────────────────────────────────────────────────────────────────────────────}
  3660.  
  3661. Procedure AttachAnsiFilter(       Chan       : TChanHandle;
  3662.                                   SubChan    : STRING              );
  3663.  
  3664. BEGIN
  3665.  
  3666.   VOutFilterAttach( Chan,
  3667.                     0,
  3668.                     'ANSIFILTER',
  3669.                     SubChan,
  3670.                     AnsiFilter,
  3671.                     0,0,0           );
  3672.  
  3673.  
  3674.  
  3675. END;
  3676.  
  3677.  
  3678.  
  3679.  
  3680. {────────────────────────────────────────────────────────────────────────────}
  3681. {────────────────────────────────────────────────────────────────────────────}
  3682. {────────────────────────────────────────────────────────────────────────────}
  3683.  
  3684.  
  3685. BEGIN
  3686.  
  3687. END.