home *** CD-ROM | disk | FTP | other *** search
/ CD/PC Actual 13 / CDA13.ISO / cdactual / demobin / share / program / Pascal / ANSIDRVR.ZIP / ANSICOM.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-05-03  |  18.1 KB  |  926 lines

  1. {
  2. Turbo Pascal ANSI Drivers
  3. Version 1.12
  4. Copyright (c) 1990 by Not So Serious Software
  5.  
  6. Original concept by Ian Silver
  7. Design and implementation by Kevin Dean
  8.  
  9. Kevin Dean
  10. Fairview Mall P.O. Box 55074
  11. 1800 Sheppard Avenue East
  12. Willowdale, Ontario
  13. CANADA    M2J 5B9
  14. CompuServe ID: 76336,3114
  15. }
  16.  
  17.  
  18. {$I-,F-,S-,R-}
  19. unit ANSICOM;
  20.  
  21.  
  22. interface
  23.  
  24.  
  25. uses
  26.   DOS,
  27.   ANSI;
  28.  
  29.  
  30. type
  31.   ErrorProc =            { Communications error handling procedure }
  32.     procedure(var Error : word);
  33.  
  34.  
  35. const
  36.   Init =            { Initialize modem when setting parameters }
  37.     true;
  38.   NoInit =            { Assume modem already initialized }
  39.     false;
  40.  
  41.   SyncTransmit =        { Synchronize transmission with output function }
  42.     true;
  43.   AsyncTransmit =        { Return from output function immediately }
  44.     false;
  45.  
  46.   NoCommError =            { No communications error }
  47.     $0000;
  48.   ReceiveOverrun =        { Received data overrun }
  49.     $0001;
  50.   TransmitOverrun =        { Output buffer overrun }
  51.     $0002;
  52.   ParityError =            { Data parity error }
  53.     $0004;
  54.   FramingError =        { Data framing error }
  55.     $0008;
  56.   BreakDetect =            { Break signal detected }
  57.     $0010;
  58.   CommTimeOut =            { Communications time-out (off-line) }
  59.     $0020;
  60.   NoCarrier =            { No carrier }
  61.     $0040;
  62.   CtrlBreak =            { Ctrl-Break key pressed }
  63.     $0080;
  64.   NotOnline =            { Communications routines not online }
  65.     $0100;
  66.  
  67.  
  68. function InitCOM(COMPort : byte; Baud : integer; Bits : byte; Parity : char;
  69.  Stop : byte; Init : boolean; Sync : boolean; Error : pointer) : integer;
  70. function SetBaud(Baud : integer; Bits : byte; Parity : char; Stop : byte) : integer;
  71. procedure Disconnect;
  72. procedure ReleaseCOM;
  73. procedure AssignCOM(var F : Text);
  74. function KeyPressed : boolean;
  75. function ReadKey : char;
  76.  
  77. { These functions are not to be called directly; they are used internally }
  78. function ModemIn(var F : Text) : integer;
  79. function ModemOut(var F : Text) : integer;
  80.  
  81.  
  82. implementation
  83.  
  84.  
  85. type
  86.   ModemRecord =
  87.     record
  88.     Addr : word;        { COM port address }
  89.     EnableMask : byte;        { Interrupt enable mask }
  90.     ResetMask : byte;        { Interrupt reset mask }
  91.     IntrNum : byte        { Interrupt number }
  92.     end;
  93.  
  94.   ModemArray =
  95.     array [1 .. 4] of ModemRecord;
  96.  
  97. const
  98.   THR =                { Transmitter holding register }
  99.     0;
  100.   RDR =                { Receiver data register }
  101.     0;
  102.   BRDL =            { Baud rate divisor (low byte) }
  103.     0;
  104.   BRDH =            { Baud rate divisor (high byte) }
  105.     1;
  106.   IER =                { Interrupt enable register }
  107.     1;
  108.   IIR =                { Interrupt identification register }
  109.     2;
  110.   LCR =                { Line control register }
  111.     3;
  112.   MCR =                { Modem control register }
  113.     4;
  114.   LSR =                { Line status register }
  115.     5;
  116.   MSR =                { Modem status register }
  117.     6;
  118.  
  119.   DCD =                { Data carrier detect bit in MSR }
  120.     $80;
  121.  
  122.   DTR =                { Data transmit ready in MCR }
  123.     $01;
  124.   RTS =                { Request-to-send in MCR }
  125.     $02;
  126.   IntrOn =            { Interrupt-enable (GPO2) in MCR }
  127.     $08;
  128.  
  129.   NoIntr =            { No interrupt pending }
  130.     $01;
  131.   ChangedMSR =            { Change in modem status register }
  132.     $00;
  133.   EmptyTHR =            { Transmitter holding register empty }
  134.     $02;
  135.   DataReceived =        { Data received }
  136.     $04;
  137.   ReceiveError =        { Reception error or break condition received }
  138.     $06;
  139.  
  140.   TransmitDone : boolean =    { True if output buffer is empty }
  141.     true;
  142.  
  143.   MBufSize =            { Modem buffer size }
  144.     $400;
  145.  
  146.   MIBufStart : integer =    { Start index of input communications buffer }
  147.     0;
  148.   MIBufEnd : integer =        { End index of input communications buffer }
  149.     0;
  150.   MOBufStart : integer =    { Start index of output communications buffer }
  151.     0;
  152.   MOBufEnd : integer =        { End index of output communications buffer }
  153.     0;
  154.  
  155.   _COMPort : byte =        { COM port in use }
  156.     0;
  157.  
  158.   OldCommInt : pointer =    { Old communications interrupt }
  159.     nil;
  160.  
  161.   ModemData : ModemArray =
  162.     (
  163.       (
  164.       Addr : $3F8; EnableMask : $EF; ResetMask : $64; IntrNum : $0C
  165.       ),
  166.       (
  167.       Addr : $2F8; EnableMask : $F7; ResetMask : $63; IntrNum : $0B
  168.       ),
  169.       (
  170.       Addr : $3E8; EnableMask : $EF; ResetMask : $64; IntrNum : $0C
  171.       ),
  172.       (
  173.       Addr : $2E8; EnableMask : $F7; ResetMask : $63; IntrNum : $0B
  174.       )
  175.     );
  176.  
  177.   ErrorHandler : pointer =    { User-defined error handling procedure }
  178.     nil;
  179.  
  180.   CommError : word =        { Last communications error }
  181.     NoCommError;
  182.  
  183. type
  184.   MBufArray =            { Modem buffer array }
  185.     array [0 .. MBufSize] of byte;
  186.  
  187. var
  188.   BasePort : word;        { Base communications port }
  189.   IntrMask : byte;        { Modem interrupt mask }
  190.   MCRStat : byte;        { Modem control register status }
  191.   InitModem : boolean;        { True if modem was initialized in InitCOM }
  192.   TransmitSync : boolean;    { True if transmission and output are synchronized }
  193.   MIBuf, MOBuf : MBufArray;    { Input and output buffers }
  194.   OldExit : pointer;        { Old exit procedure }
  195.  
  196.  
  197. {***}
  198. { Increment buffer index, wrap around if necessary }
  199. function IncIndex(Index : integer) : integer;
  200.  
  201. begin
  202. if Index = MBufSize then
  203.   Index := 0
  204. else
  205.   Inc(Index);
  206.  
  207. IncIndex := Index
  208. end;
  209.  
  210.  
  211. {***}
  212. { Decrement buffer index, wrap around if necessary }
  213. function DecIndex(Index : integer) : integer;
  214.  
  215. begin
  216. if Index = 0 then
  217.   Index := MBufSize
  218. else
  219.   Dec(Index);
  220.  
  221. DecIndex := Index
  222. end;
  223.  
  224.  
  225. {***}
  226. { Transmit next byte in output buffer if available }
  227. procedure TransmitByte;
  228.  
  229. begin
  230. if MOBufStart = MOBufEnd then
  231.   TransmitDone := true
  232. else
  233.   begin
  234.   TransmitDone := false;
  235.   Port[BasePort + THR] := MOBuf[MOBufStart];
  236.   MOBufStart := IncIndex(MOBufStart)
  237.   end
  238. end;
  239.  
  240.  
  241. {***}
  242. { Receive a byte into the input buffer }
  243. procedure ReceiveByte;
  244.  
  245. begin
  246. MIBuf[MIBufEnd] := Port[BasePort + RDR];
  247. MIBufEnd := IncIndex(MIBufEnd);
  248. if MIBufStart = MIBufEnd then
  249.   begin
  250.   MIBufEnd := DecIndex(MIBufEnd);
  251.   CommError := CommError or ReceiveOverrun
  252.   end
  253. end;
  254.  
  255.  
  256. {***}
  257. { Check modem status }
  258. procedure CheckStatus;
  259.  
  260. var
  261.   Status : byte;    { Line status }
  262.  
  263. begin
  264. { Read line status register }
  265. Status := Port[BasePort + LSR];
  266.  
  267. if Status and $02 <> 0 then
  268.   CommError := CommError or ReceiveOverrun;
  269. if Status and $04 <> 0 then
  270.   CommError := CommError or ParityError;
  271. if Status and $08 <> 0 then
  272.   CommError := CommError or FramingError;
  273. if Status and $10 <> 0 then
  274.   CommError := CommError or BreakDetect;
  275. if Status and $80 <> 0 then
  276.   CommError := CommError or CommTimeOut;
  277.  
  278. { Check for carrier }
  279. Status := Port[BasePort + MSR];
  280. if Status and DCD = 0 then
  281.   CommError := CommError or NoCarrier
  282. else
  283.   CommError := CommError and not NoCarrier
  284. end;
  285.  
  286.  
  287. {***}
  288. { Serial communications interrupt }
  289. procedure CommInt(Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : word);
  290. interrupt;
  291.  
  292. var
  293.   IntrType : byte;    { Interrupt type }
  294.  
  295. begin
  296. IntrType := Port[BasePort + IIR];
  297.  
  298. while IntrType <> NoIntr do
  299.   begin
  300.   case IntrType of
  301.     EmptyTHR:
  302.       TransmitByte;
  303.  
  304.     DataReceived:
  305.       ReceiveByte;
  306.  
  307.     ChangedMSR, ReceiveError:
  308.       CheckStatus
  309.     end;
  310.  
  311.   IntrType := Port[BasePort + IIR]
  312.   end;
  313.  
  314. { Acknowledge interrupt }
  315. Port[$20] := $20
  316. end;
  317.  
  318.  
  319. {***}
  320. { Clear interrupts by reading all communications registers }
  321. procedure ClearInterrupts;
  322.  
  323. var
  324.   IntrType : byte;    { Interrupt type }
  325.   X : byte;        { Temporary storage to read registers }
  326.  
  327. begin
  328. IntrType := Port[BasePort + IIR];
  329.  
  330. while IntrType <> NoIntr do
  331.   begin
  332.   case IntrType of
  333.     EmptyTHR:
  334.       ;
  335.  
  336.     DataReceived:
  337.       X := Port[BasePort + RDR];
  338.  
  339.     ChangedMSR, ReceiveError:
  340.       begin
  341.       X := Port[BasePort + LSR];
  342.       X := Port[BasePort + MSR]
  343.       end
  344.     end;
  345.  
  346.   IntrType := Port[BasePort + IIR]
  347.   end
  348. end;
  349.  
  350.  
  351. {***}
  352. { Initialize communications port and install interrupt }
  353. function InitCOM(COMPort : byte; Baud : integer; Bits : byte; Parity : char;
  354.  Stop : byte; Init : boolean; Sync : boolean; Error : pointer) : integer;
  355.  
  356. var
  357.   Result : integer;        { Initialization result }
  358.   Regs : Registers;        { Registers used in dummy interrupt call }
  359.   X : byte;            { Dummy value for COM port registers }
  360.  
  361. begin
  362. { No error }
  363. Result := 0;
  364.  
  365. if (COMPort >= 1) and (COMPort <= 4) then
  366.   begin
  367.   _COMPort := COMPort;
  368.  
  369.   BasePort := ModemData[COMPort].Addr;
  370.  
  371.   { Save modem interrupt enable mask }
  372.   IntrMask := Port[BasePort + IER];
  373.  
  374.   InitModem := Init;
  375.  
  376.   if InitModem then
  377.     begin
  378.     { Disable communications interrupts }
  379.     Port[BasePort + IER] := 0;
  380.  
  381.     Result := SetBaud(Baud, Bits, Parity, Stop)
  382.     end;
  383.  
  384.   if Result = 0 then
  385.     begin
  386.     { Install communications interrupt }
  387.     GetIntVec(ModemData[COMPort].IntrNum, OldCommInt);
  388.     SetIntVec(ModemData[COMPort].IntrNum, @CommInt);
  389.  
  390.     { Save transmission type }
  391.     TransmitSync := Sync;
  392.  
  393.     { Save user-defined error handler }
  394.     ErrorHandler := Error;
  395.  
  396.     { Set interrupt enable mask }
  397.     Port[$21] := Port[$21] and ModemData[COMPort].EnableMask;
  398.  
  399.     { Reset interrupt line }
  400.     Port[$20] := ModemData[COMPort].ResetMask;
  401.  
  402.     { Check for carrier }
  403.     if Port[BasePort + MSR] and DCD = 0 then
  404.       CommError := NoCarrier;
  405.  
  406.     { Interrupt on data received, THR empty, data reception error, and change in MSR }
  407.     Port[BasePort + IER] := $0F;
  408.  
  409.     { DTR active, RTS active, interrupts on }
  410.     MCRStat := Port[BasePort + MCR];
  411.     Port[BasePort + MCR] := DTR or RTS or IntrOn;
  412.  
  413.     { Clear all pending interrupts }
  414.     ClearInterrupts
  415.     end
  416.   end
  417. else
  418.   Result := 1;
  419.  
  420. InitCOM := Result
  421. end;
  422.  
  423.  
  424. {***}
  425. { Change baud rate and data format dynamically }
  426. function SetBaud(Baud : integer; Bits : byte; Parity : char; Stop : byte) : integer;
  427.  
  428. var
  429.   Result : integer;        { Initialization result }
  430.   LowDiv, HighDiv : byte;    { Low and high bytes of baud rate divisor }
  431.   DataFormat : byte;        { Modem data format (bits, parity, etc) }
  432.  
  433. begin
  434. if _COMPort <> 0 then
  435.   begin
  436.   Result := 0;
  437.  
  438.   { Set baud rate divisors }
  439.   if Baud = 110 then
  440.     begin
  441.     LowDiv := $17;
  442.     HighDiv := $04
  443.     end
  444.   else if Baud = 300 then
  445.     begin
  446.     LowDiv := $80;
  447.     HighDiv := $01
  448.     end
  449.   else if Baud = 600 then
  450.     begin
  451.     LowDiv := $C0;
  452.     HighDiv := $00
  453.     end
  454.   else if Baud = 1200 then
  455.     begin
  456.     LowDiv := $60;
  457.     HighDiv := $00
  458.     end
  459.   else if Baud = 1800 then
  460.     begin
  461.     LowDiv := $40;
  462.     HighDiv := $00
  463.     end
  464.   else if Baud = 2400 then
  465.     begin
  466.     LowDiv := $30;
  467.     HighDiv := $00
  468.     end
  469.   else if Baud = 3600 then
  470.     begin
  471.     LowDiv := $20;
  472.     HighDiv := $00
  473.     end
  474.   else if Baud = 4800 then
  475.     begin
  476.     LowDiv := $18;
  477.     HighDiv := $00
  478.     end
  479.   else if Baud = 9600 then
  480.     begin
  481.     LowDiv := $0C;
  482.     HighDiv := $00
  483.     end
  484.   else
  485.     Result := 1;
  486.  
  487.   { Determine number of data bits }
  488.   case Bits of
  489.     5:
  490.       DataFormat := $00;
  491.  
  492.     6:
  493.       DataFormat := $01;
  494.  
  495.     7:
  496.       DataFormat := $02;
  497.  
  498.     8:
  499.       DataFormat := $03;
  500.  
  501.     else
  502.       Result := 1
  503.     end;
  504.  
  505.   { Determine number of stop bits }
  506.   case Stop of
  507.     1:
  508.       { Bit is 0 }
  509.       ;
  510.  
  511.     2:
  512.       DataFormat := DataFormat or $04;
  513.  
  514.     else
  515.       Result := 1
  516.     end;
  517.  
  518.   { Determine parity }
  519.   case UpCase(Parity) of
  520.     'N':
  521.       { No parity, bit is 0 }
  522.       ;
  523.  
  524.     'O':
  525.       { Odd parity }
  526.       DataFormat := DataFormat or $08;
  527.  
  528.     'E':
  529.       { Even parity }
  530.       DataFormat := DataFormat or $18;
  531.  
  532.     'M':
  533.       { Mark parity }
  534.       DataFormat := DataFormat or $28;
  535.  
  536.     'S':
  537.       { Space parity }
  538.       DataFormat := DataFormat or $38;
  539.  
  540.     else
  541.       Result := 1
  542.     end;
  543.  
  544.   if Result = 0 then
  545.     begin
  546.     { Turn on bit 7 of line control register to set baud rate }
  547.     Port[BasePort + LCR] := Port[BasePort + LCR] or $80;
  548.  
  549.     { Set low and high baud rate divisors }
  550.     Port[BasePort+ BRDL] := LowDiv;
  551.     Port[BasePort+ BRDH] := HighDiv;
  552.  
  553.     { Set data format }
  554.     Port[BasePort + LCR] := DataFormat
  555.     end
  556.   end
  557. else
  558.   { Modem not previously initialized }
  559.   Result := 1;
  560.  
  561. SetBaud := Result
  562. end;
  563.  
  564.  
  565. {***}
  566. { Disconnect modem }
  567. procedure Disconnect;
  568.  
  569. begin
  570. { Turn off data transmit ready bit }
  571. Port[BasePort + MCR] := Port[BasePort + MCR] and not DTR;
  572.  
  573. { Wait enough time for other modem to recognize loss of carrier }
  574. Delay(1000);
  575.  
  576. { Turn on data transmit ready bit }
  577. Port[BasePort + MCR] := Port[BasePort + MCR] or DTR
  578. end;
  579.  
  580.  
  581. {***}
  582. { Release communications port }
  583. procedure ReleaseCOM;
  584.  
  585. begin
  586. if OldCommInt <> nil then
  587.   begin
  588.   if InitModem then
  589.     Disconnect;
  590.  
  591.   { Restore communications interrupt }
  592.   SetIntVec(ModemData[_COMPort].IntrNum, OldCommInt);
  593.   OldCommInt := nil;
  594.  
  595.   { Reset modem interrupt mask }
  596.   Port[BasePort + IER] := IntrMask;
  597.  
  598.   { Reset interrupt enable mask }
  599.   Port[$21] := Port[$21] or not ModemData[_COMPort].EnableMask;
  600.  
  601.   { Reset MCR }
  602.   Port[BasePort + MCR] := MCRStat;
  603.  
  604.   _COMPort := 0
  605.   end
  606. end;
  607.  
  608.  
  609. {$F+}
  610.  
  611. {***}
  612. { Release modem on exit }
  613. procedure ExitRelease;
  614.  
  615. begin
  616. ExitProc := OldExit;
  617. ReleaseCOM
  618. end;
  619.  
  620. {$F-}
  621.  
  622.  
  623. {***}
  624. { Check for communications error and call error routine if defined }
  625. procedure CheckError;
  626.  
  627. const
  628.   ErrorPending : boolean =    { True if error handling is already underway }
  629.     false;
  630.  
  631. begin
  632. if (CommError <> NoCommError) and not ErrorPending then
  633.   if ErrorHandler <> nil then
  634.     begin
  635.     ErrorPending := true;
  636.     ErrorProc(ErrorHandler)(CommError);
  637.     ErrorPending := false
  638.     end
  639.   else
  640.     CommError := NoCommError
  641. end;
  642.  
  643.  
  644. {$F+}
  645.  
  646. {***}
  647. { Handle line-oriented communications input }
  648. function ModemIn(var F : Text) : integer;
  649.  
  650. var
  651.   NumRead : integer;    { Number of characters read }
  652.   Done : boolean;    { True if end of line }
  653.   Key : char;        { Character received }
  654.  
  655. begin
  656. { Make sure program has been properly initialized }
  657. if OldCommInt = nil then
  658.   CommError := CommError or NotOnline;
  659.  
  660. NumRead := 0;
  661.  
  662. Done := false;
  663. while not Done do
  664.   begin
  665.   { Generate DOS OK interrupt while waiting for character }
  666.   while (MIBufStart = MIBufEnd) and (CommError = NoCommError) do
  667.     inline
  668.     (
  669.     $CD/$28    { INT    28h }
  670.     );
  671.  
  672.   CheckError;
  673.  
  674.   Key := Chr(MIBuf[MIBufStart]);
  675.   MIBufStart := IncIndex(MIBufStart);
  676.  
  677.   case Key of
  678.     NUL:
  679.       { Ignore extended keys }
  680.       begin
  681.       { Generate DOS OK interrupt while waiting for character }
  682.       while (MIBufStart = MIBufEnd) and (CommError = NoCommError) do
  683.     inline
  684.     (
  685.     $CD/$28        { INT    28h }
  686.     );
  687.  
  688.       CheckError;
  689.  
  690.       MIBufStart := IncIndex(MIBufStart)
  691.       end;
  692.  
  693.     BRK:
  694.       if CheckBreak then
  695.     CommError := CommError or CtrlBreak;
  696.  
  697.     BS:
  698.       { Erase last character if possible }
  699.       if (NumRead <> 0) and (WhereX <> 1) then
  700.     begin
  701.     Write(BS, ' ', BS);
  702.     Dec(NumRead)
  703.     end;
  704.  
  705.     CR, LF:
  706.       { End of line }
  707.       begin
  708.       Done := true;
  709.       TextRec(F).BufPtr^[NumRead] := CR;
  710.       Inc(NumRead);
  711.       TextRec(F).BufPtr^[NumRead] := LF;
  712.       Inc(NumRead);
  713.       WriteLn
  714.       end;
  715.  
  716.     EOF_:
  717.       { End of file }
  718.       if CheckEOF then
  719.     begin
  720.     Done := true;
  721.     TextRec(F).BufPtr^[NumRead] := EOF_;
  722.     Inc(NumRead)
  723.     end;
  724.  
  725.     ESC:
  726.       { Clear current input }
  727.       begin
  728.       Write('\', LF);
  729.       if MaxX = 0 then
  730.     GotoXY(WhereX - NumRead - 1 + MaxX, WhereY)
  731.       else
  732.     GotoXY((WhereX - NumRead + MaxX - 2) mod MaxX + 1, WhereY);
  733.       NumRead := 0
  734.       end;
  735.  
  736.     else
  737.       { Display the character }
  738.       with TextRec(F) do
  739.     if NumRead < BufSize - 2 then
  740.       begin
  741.       BufPtr^[NumRead] := Key;
  742.       Write(Key);
  743.       Inc(NumRead)
  744.       end
  745.     end
  746.   end;
  747.  
  748. { Save buffer pointers }
  749. with TextRec(F) do
  750.   begin
  751.   BufPos := 0;
  752.   BufEnd := NumRead
  753.   end;
  754.  
  755. ModemIn := 0
  756. end;
  757.  
  758.  
  759. {***}
  760. { Display text on modem }
  761. function ModemOut(var F : Text) : integer;
  762.  
  763. var
  764.   I : integer;        { Index into buffer }
  765.  
  766. begin
  767. with TextRec(F) do
  768.   begin
  769.   for I := 0 to BufPos - 1 do
  770.     begin
  771.     MOBuf[MOBufEnd] := Ord(BufPtr^[I]);
  772.     if MOBuf[MOBufEnd] = Ord(FF) then
  773.       { Translate form feed }
  774.       ClrScr
  775.     else
  776.       begin
  777.       MOBufEnd := IncIndex(MOBufEnd);
  778.       if MOBufStart = MOBufEnd then
  779.     begin
  780.     MOBufEnd := DecIndex(MOBufEnd);
  781.     CommError := CommError or TransmitOverrun
  782.     end
  783.       end
  784.     end;
  785.  
  786.   BufPos := 0
  787.   end;
  788.  
  789. CheckError;
  790.  
  791. { Start transmission if necessary }
  792. if TransmitDone and (OldCommInt <> nil) then
  793.   TransmitByte;
  794.  
  795. if TransmitSync and (OldCommInt <> nil) then
  796.   { Wait for end of transmission }
  797.   while not TransmitDone and (CommError = NoCommError) do
  798.     inline
  799.     (
  800.     $CD/$28    { INT    28h }
  801.     );
  802.  
  803. CheckError;
  804.  
  805. ModemOut := 0
  806. end;
  807.  
  808.  
  809. {***}
  810. { Flush modem buffer }
  811. function ModemFlush(var F : Text) : integer;
  812.  
  813. begin
  814. with TextRec(F) do
  815.   if Mode = fmInput then
  816.     { Ignore flush request }
  817.     ModemFlush := 0
  818.   else
  819.     { Chain to F's default output routine }
  820.     ModemFlush := IOFunc(InOutFunc)(F)
  821. end;
  822.  
  823.  
  824. {***}
  825. { Open modem for input or output }
  826. function ModemOpen(var F : Text) : integer;
  827.  
  828. begin
  829. with TextRec(F) do
  830.   if Mode = fmInput then
  831.     IOFunctions(UserData).NextInOut := @ModemIn
  832.   else
  833.     IOFunctions(UserData).NextInOut := @ModemOut;
  834.  
  835. ModemOpen := 0
  836. end;
  837.  
  838.  
  839. {***}
  840. { Close modem (do nothing) }
  841. function ModemClose(var F : Text) : integer;
  842.  
  843. begin
  844. ModemClose := 0
  845. end;
  846.  
  847. {$F-}
  848.  
  849.  
  850. {***}
  851. { Assign a file to the modem }
  852. procedure AssignCOM(var F : Text);
  853.  
  854. var
  855.   IOChain : IOFunctions;    { Modem I/O function chain }
  856.  
  857. begin
  858. with IOChain do
  859.   begin
  860.   NextOpen := @ModemOpen;
  861.   NextInOut := nil;
  862.   NextFlush := @ModemFlush;
  863.   NextClose := @ModemClose
  864.   end;
  865.  
  866. AssignANSI(F, IOChain)
  867. end;
  868.  
  869.  
  870. {***}
  871. { Return true if character in input buffer }
  872. function KeyPressed : boolean;
  873.  
  874. begin
  875. CheckError;
  876. KeyPressed := MIBufStart <> MIBufEnd
  877. end;
  878.  
  879.  
  880. {***}
  881. { Read character from input buffer }
  882. function ReadKey : char;
  883.  
  884. var
  885.   Key : char;    { Character received }
  886.  
  887. begin
  888. { Generate DOS OK interrupt while waiting for character }
  889. while (MIBufStart = MIBufEnd) and (CommError = NoCommError) do
  890.   inline
  891.   (
  892.   $CD/$28    { INT    28h }
  893.   );
  894.  
  895. CheckError;
  896.  
  897. Key := Chr(MIBuf[MIBufStart]);
  898. MIBufStart := IncIndex(MIBufStart);
  899.  
  900. if (Key = BRK) and CheckBreak then
  901.   begin
  902.   CommError := CommError or CtrlBreak;
  903.   CheckError
  904.   end;
  905.  
  906. ReadKey := Key
  907. end;
  908.  
  909.  
  910. {***}
  911. begin
  912. OldExit := ExitProc;
  913. ExitProc := @ExitRelease;
  914.  
  915. Close(Input);
  916. Close(Output);
  917.  
  918. AssignCOM(ANSIFile);
  919. Rewrite(ANSIFile);
  920.  
  921. AssignCOM(Input);
  922. Reset(Input);
  923.  
  924. AssignCOM(Output);
  925. Rewrite(Output)
  926. end.