home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vp21beta.zip / ARTLSRC.RAR / WINCRT.PAS < prev    next >
Pascal/Delphi Source File  |  2000-08-15  |  47KB  |  1,831 lines

  1. //█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█
  2. //█                                                       █
  3. //█      Virtual Pascal Runtime Library.  Version 2.1.    █
  4. //█      OS/2 Presentation Manager CRT interface unit     █
  5. //█      Win32 Windowed CRT interface unit                █
  6. //█      DPMI32 simplified implementation                 █
  7. //█      ─────────────────────────────────────────────────█
  8. //█      Copyright (C) 1995-2000 vpascal.com              █
  9. //█                                                       █
  10. //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  11. {$S-,R-,Q-,I-,Cdecl-,OrgName-,AlignRec-,Use32+,T-}
  12.  
  13. {$IFDEF DPMI32} {$DEFINE DPMI32_LINUX}{$ENDIF}
  14. {$IFDEF Linux}  {$DEFINE DPMI32_LINUX}{$ENDIF}
  15.  
  16. unit WinCrt;
  17.  
  18. interface
  19.  
  20. uses
  21. {$IFDEF OS2}
  22.   Os2Def, Os2PmApi,
  23. {$ENDIF OS2}
  24. {$IFDEF WIN32}
  25.   Windows,
  26. {$ENDIF WIN32}
  27. {$IFDEF DPMI32_LINUX}
  28.   VpSysLow,
  29. {$ENDIF DPMI32_LINUX}
  30.   Strings, WinDos;
  31.  
  32. var
  33.   WindowTitle: array[0..79] of Char;        { CRT window title }
  34.   InactiveTitleBuf: array[0..79] of Char;   { CRT window inactive title }
  35.  
  36. {$IFDEF OS2}
  37. const
  38.   cw_UseDefault = Integer($8000);
  39.  
  40. const
  41.   WindowOrg: PointL =                       { CRT window origin }
  42.     (X: cw_UseDefault; Y: cw_UseDefault);
  43.   WindowSize: PointL =                      { CRT window size }
  44.     (X: cw_UseDefault; Y: cw_UseDefault);
  45.   ScreenSize: PointL = (X: 80; Y: 25);      { Screen buffer dimensions }
  46.   InactiveTitle: PChar = @InactiveTitleBuf; { Inactive window title }
  47.   Cursor: PointL = (X: 0; Y: 0);            { Cursor location }
  48.   Origin: PointL = (X: 0; Y: 0);            { Client area origin }
  49.   FontId: ULong = 1;                        { Font Id }
  50.   FontAttr: FAttrs = (                      { Font attributes }
  51.     usRecordLength:  SizeOf(FAttrs);        { Size of the record }
  52.     fsSelection:     0;                     { fattr_Sel_xxx }
  53.     lMatch:          1;
  54.     szFacename:      'System VIO';          { Fixed-pitch font }
  55.     idRegistry:      0;
  56.     usCodePage:      0;
  57.     lMaxBaselineExt: 16;                    { Font Size: 16x8 }
  58.     lAveCharWidth:   8;
  59.     fsType:          0;                     { fattr_Type_xxx }
  60.     fsFontUse:       0                      { fattr_FontUse_xxx }
  61.   );
  62.   CrtCreateFlags: ULong = fcf_TitleBar + fcf_SysMenu + fcf_SizeBorder +
  63.     fcf_MinMax + fcf_TaskList + fcf_NoByteAlign + fcf_VertScroll + fcf_HorzScroll;
  64. {$ENDIF OS2}
  65. {$IFDEF WIN32}
  66.  
  67. const
  68.   WindowOrg: TPoint =                       { CRT window origin }
  69.     (X: cw_UseDefault; Y: cw_UseDefault);
  70.   WindowSize: TPoint =                      { CRT window size }
  71.     (X: cw_UseDefault; Y: cw_UseDefault);
  72.   ScreenSize: TPoint = (X: 80; Y: 25);      { Screen buffer dimensions }
  73.   Cursor: TPoint = (X: 0; Y: 0);            { Cursor location }
  74.   Origin: TPoint = (X: 0; Y: 0);            { Client area origin }
  75.   InactiveTitle: PChar = '(Inactive %s)';   { Inactive window title }
  76.  
  77. {$ENDIF WIN32}
  78.  
  79. {$IFDEF DPMI32_LINUX}
  80. const                                       { $0700 = white on black }
  81.   Wincrt_Cell:SmallWord=($1e00);            { $1e00 = yellow on blue }
  82. {$ENDIF}
  83.  
  84.   AutoTracking: Boolean = True;             { Track cursor on Write? }
  85.   CheckEOF: Boolean = False;                { Allow Ctrl-Z for EOF? }
  86.   CheckBreak: Boolean = True;               { Allow Ctrl-C for break? }
  87.  
  88. procedure InitWinCrt;
  89. procedure DoneWinCrt;
  90.  
  91. procedure WriteBuf(Buffer: PChar; Count: Word);
  92. procedure WriteChar(Ch: Char);
  93.  
  94. function KeyPressed: Boolean;
  95. function ReadKey: Char;
  96. function ReadBuf(Buffer: PChar; Count: Word): Word;
  97.  
  98. procedure GotoXY(X, Y: Integer);
  99. function WhereX: Integer;
  100. function WhereY: Integer;
  101. procedure ClrScr;
  102. procedure ClrEol;
  103.  
  104. procedure CursorTo(X, Y: Integer);
  105. procedure ScrollTo(X, Y: Integer);
  106. procedure TrackCursor;
  107.  
  108. procedure AssignCrt(var F: Text);
  109.  
  110. {$IFDEF OS2}
  111. { CRT window procedures }
  112.  
  113. function CrtWinProc(Window: HWnd; Message: ULong; Mp1, Mp2: MParam): MResult; cdecl; export;
  114. function FrameWndProc(Window: HWnd; Message: ULong; Mp1, Mp2: MParam): MResult; cdecl; export;
  115.  
  116. {$ENDIF}
  117.  
  118. implementation
  119.  
  120. { Double word record }
  121.  
  122. type
  123.   LongRec = record
  124.     Lo, Hi: SmallInt;
  125.   end;
  126.  
  127. { Scroll key definition record }
  128.  
  129. type
  130.   TScrollKey = record
  131.     Key: Byte;
  132.     Ctrl: Boolean;
  133.     SBar: Byte;
  134.     Action: Byte;
  135.   end;
  136.  
  137. { Return the smaller of two integer values }
  138.  
  139. function Min(X, Y: Integer): Integer;
  140. begin
  141.   if X < Y then Min := X else Min := Y;
  142. end;
  143.  
  144. { Return the larger of two integer values }
  145.  
  146. function Max(X, Y: Integer): Integer;
  147. begin
  148.   if X > Y then Max := X else Max := Y;
  149. end;
  150.  
  151. {$IFDEF OS2}
  152.  
  153. const
  154.   CrtWindow: HWnd = 0;                  { CRT window handle }
  155.   CrtWindowFrame: HWnd = 0;             { CRT window frame handle }
  156.   FirstLine: Integer = 0;               { First line in circular buffer }
  157.   KeyCount: Integer = 0;                { Count of keys in KeyBuffer }
  158.   Created: Boolean = False;             { CRT window created? }
  159.   Focused: Boolean = False;             { CRT window focused? }
  160.   Reading: Boolean = False;             { Reading from CRT window? }
  161.   Painting: Boolean = False;            { Handling wm_Paint? }
  162.  
  163. var
  164.   SaveExit: Pointer;                    { Saved exit procedure pointer }
  165.   ScreenBuffer: PChar;                  { Screen buffer pointer }
  166.   ClientSize: PointL;                   { Client area dimensions }
  167.   MaxWindowSize: PointL;                { Maximum window size }
  168.   Range: PointL;                        { Scroll bar ranges }
  169.   CharSize: PointL;                     { Character cell size }
  170.   CharDescent: Integer;                 { Character descent }
  171.   DC: HDC;                              { Global device context }
  172.   KeyBuffer: array[0..63] of Char;      { Keyboard type-ahead buffer }
  173.   Anchor: HAB;                          { PM anchor block }
  174.   MsgQue: HMQ;                          { PM message queue }
  175.   PS: HPS;                              { Presentation space handle }
  176.   VScrollBar: HWnd;                     { Vertical scrollbar handle }
  177.   HScrollBar: HWnd;                     { Horizontal scrollbar handle }
  178.   PR: RectL;                            { Painting rectangle }
  179.   cyClient: Integer;                    { Client window height }
  180.   OldFrameWndProc: FnWp;                { Standard frame window procedure }
  181.   DesktopSize: PointL;                  { Size of the PM Desktop }
  182.  
  183. const
  184.   CrtClassName: PChar = 'VPWinCrt';
  185.  
  186. const
  187.   sb_Top        = 8;    { PM does not have these ones }
  188.   sb_Bottom     = 9;
  189.  
  190. { Scroll keys table }
  191.  
  192. const
  193.   ScrollKeyCount = 12;
  194.   ScrollKeys: array[1..ScrollKeyCount] of TScrollKey = (
  195.     (Key: vk_Left;     Ctrl: False; SBar: sbs_Horz; Action: sb_LineUp),
  196.     (Key: vk_Right;    Ctrl: False; SBar: sbs_Horz; Action: sb_LineDown),
  197.     (Key: vk_Left;     Ctrl: True;  SBar: sbs_Horz; Action: sb_PageUp),
  198.     (Key: vk_Right;    Ctrl: True;  SBar: sbs_Horz; Action: sb_PageDown),
  199.     (Key: vk_Home;     Ctrl: False; SBar: sbs_Horz; Action: sb_Top),
  200.     (Key: vk_End;      Ctrl: False; SBar: sbs_Horz; Action: sb_Bottom),
  201.     (Key: vk_Up;       Ctrl: False; SBar: sbs_Vert; Action: sb_LineUp),
  202.     (Key: vk_Down;     Ctrl: False; SBar: sbs_Vert; Action: sb_LineDown),
  203.     (Key: vk_PageUp;   Ctrl: False; SBar: sbs_Vert; Action: sb_PageUp),
  204.     (Key: vk_PageDown; Ctrl: False; SBar: sbs_Vert; Action: sb_PageDown),
  205.     (Key: vk_Home;     Ctrl: True;  SBar: sbs_Vert; Action: sb_Top),
  206.     (Key: vk_End;      Ctrl: True;  SBar: sbs_Vert; Action: sb_Bottom));
  207.  
  208. { Allocate presentation space }
  209.  
  210. procedure InitPresentationSpace;
  211. begin
  212.   if Painting then
  213.     PS := WinBeginPaint(CrtWindow, hNULL, @PR) else
  214.     PS := WinGetPS(CrtWindow);
  215.   GpiCreateLogFont(PS, nil, FontId, FontAttr);
  216.   GpiSetCharSet(PS, FontId);
  217.   GpiSetBackMix(PS, bm_OverPaint);
  218.   GpiSetColor(PS, clr_Default);
  219.   GpiSetBackColor(PS, clr_Background);
  220. end;
  221.  
  222. { Release presentation space }
  223.  
  224. procedure DonePresentationSpace;
  225. begin
  226.   GpiSetCharSet(PS, lcid_Default);
  227.   if Painting then
  228.     WinEndPaint(PS) else
  229.     WinReleasePS(PS);
  230. end;
  231.  
  232. { Calculates window parameters: character size and descent, }
  233. { maximum window size                                       }
  234.  
  235. procedure GetWindowParams;
  236. var
  237.   Metrics: FontMetrics;
  238. begin
  239.   InitPresentationSpace;
  240.   GpiQueryFontMetrics(PS, SizeOf(Metrics), Metrics);
  241.   CharSize.X := Metrics.lAveCharWidth;
  242.   CharSize.Y := Metrics.lMaxAscender + Metrics.lMaxDescender;
  243.   CharDescent := Metrics.lMaxDescender;
  244.   MaxWindowSize.X := ScreenSize.X * CharSize.X +
  245.     WinQuerySysValue(hwnd_Desktop, sv_CxVScroll) +
  246.     2 * WinQuerySysValue(hwnd_Desktop, sv_CxSizeBorder);
  247.   MaxWindowSize.Y := ScreenSize.Y * CharSize.Y +
  248.     WinQuerySysValue(hwnd_Desktop, sv_CyHScroll) +
  249.     WinQuerySysValue(hwnd_Desktop, sv_CyTitleBar) +
  250.     2 * WinQuerySysValue(hwnd_Desktop, sv_CySizeBorder);
  251.   DonePresentationSpace;
  252. end;
  253.  
  254. { Enables/Disables specified system menu item }
  255.  
  256. procedure EnableSysMenuItem(Item: ULong; Enable: Boolean);
  257. var
  258.   Value: ULong;
  259. begin
  260.   if Enable then Value := 0 else Value := mia_Disabled;
  261.   WinSendMsg(WinWindowFromID(CrtWindowFrame, fid_SysMenu),
  262.     mm_SetItemAttr, Item + 1 shl 16, mia_Disabled + Value shl 16);
  263. end;
  264.  
  265. { Show cursor }
  266.  
  267. procedure ShowCursor;
  268. begin
  269.   WinCreateCursor(CrtWindow,
  270.     (Cursor.X - Origin.X) * CharSize.X,                { X }
  271.     cyClient - (Cursor.Y - Origin.Y + 1) * CharSize.Y, { Y }
  272.     CharSize.X, 2, cursor_Solid + cursor_Flash, nil);
  273.   WinShowCursor(CrtWindow, True);
  274. end;
  275.  
  276. { Hide cursor }
  277.  
  278. procedure HideCursor;
  279. begin
  280.   WinDestroyCursor(CrtWindow);
  281. end;
  282.  
  283. { Update scroll bars }
  284.  
  285. procedure SetScrollBars;
  286. var
  287.   Swap: Swp;
  288. begin
  289.   WinQueryWindowPos(CrtWindow, Swap);
  290.   WinSendMsg(HScrollBar, sbm_SetScrollBar, Origin.X, 0 + Max(1, Range.X) shl 16);
  291.   WinSendMsg(VScrollBar, sbm_SetScrollBar, Origin.Y, 0 + Max(1, Range.Y) shl 16);
  292.   WinSendMsg(HScrollBar, sbm_SetThumbSize, Swap.cX + (ScreenSize.X * CharSize.X) shl 16, 0);
  293.   WinSendMsg(VScrollBar, sbm_SetThumbSize, Swap.cY + (ScreenSize.Y * CharSize.Y) shl 16, 0);
  294. end;
  295.  
  296. { Terminate CRT window }
  297.  
  298. procedure Terminate;
  299. begin
  300.   if Focused and Reading then HideCursor;
  301.   Halt(255);
  302. end;
  303.  
  304. { Set cursor position }
  305.  
  306. procedure CursorTo(X, Y: Integer);
  307. begin
  308.   Cursor.X := Max(0, Min(X, ScreenSize.X - 1));
  309.   Cursor.Y := Max(0, Min(Y, ScreenSize.Y - 1));
  310. end;
  311.  
  312. { Scroll window to given origin }
  313.  
  314. procedure ScrollTo(X, Y: Integer);
  315. begin
  316.   if Created then
  317.   begin
  318.     X := Max(0, Min(X, Range.X));
  319.     Y := Max(0, Min(Y, Range.Y));
  320.     if (X <> Origin.X) or (Y <> Origin.Y) then
  321.     begin
  322.       if X <> Origin.X then WinSendMsg(HScrollBar, sbm_SetPos, X, 0);
  323.       if Y <> Origin.Y then WinSendMsg(VScrollBar, sbm_SetPos, Y, 0);
  324.       WinScrollWindow(CrtWindow,
  325.         (Origin.X - X) * CharSize.X,
  326.         (Y - Origin.Y) * CharSize.Y, nil, nil, 0, nil, sw_InvalidateRgn);
  327.       Origin.X := X;
  328.       Origin.Y := Y;
  329.       WinUpdateWindow(CrtWindow);
  330.     end;
  331.   end;
  332. end;
  333.  
  334. { Scroll to make cursor visible }
  335.  
  336. procedure TrackCursor;
  337. begin
  338.   ScrollTo(Max(Cursor.X - ClientSize.X + 1, Min(Origin.X, Cursor.X)),
  339.     Max(Cursor.Y - ClientSize.Y + 1, Min(Origin.Y, Cursor.Y)));
  340. end;
  341.  
  342. { Return pointer to location in screen buffer }
  343.  
  344. function ScreenPtr(X, Y: Integer): PChar;
  345. begin
  346.   Inc(Y, FirstLine);
  347.   if Y >= ScreenSize.Y then Dec(Y, ScreenSize.Y);
  348.   ScreenPtr := @ScreenBuffer[Y * ScreenSize.X + X];
  349. end;
  350.  
  351. { Update text on cursor line }
  352.  
  353. procedure ShowText(L, R: Integer);
  354. var
  355.   P: PointL;
  356. begin
  357.   if L < R then
  358.   begin
  359.     InitPresentationSpace;
  360.     P.X := (L - Origin.X) * CharSize.X;
  361.     P.Y := cyClient - (Cursor.Y - Origin.Y + 1) * CharSize.Y + CharDescent;
  362.     GpiCharStringAt(PS, P, R - L, ScreenPtr(L, Cursor.Y));
  363.     DonePresentationSpace;
  364.   end;
  365. end;
  366.  
  367. { Write text buffer to CRT window }
  368.  
  369. procedure WriteBuf(Buffer: PChar; Count: Word);
  370. var
  371.   L, R: Integer;
  372.  
  373. procedure NewLine;
  374. begin
  375.   ShowText(L, R);
  376.   L := 0;
  377.   R := 0;
  378.   Cursor.X := 0;
  379.   Inc(Cursor.Y);
  380.   if Cursor.Y = ScreenSize.Y then
  381.   begin
  382.     Dec(Cursor.Y);
  383.     Inc(FirstLine);
  384.     if FirstLine = ScreenSize.Y then FirstLine := 0;
  385.     FillChar(ScreenPtr(0, Cursor.Y)^, ScreenSize.X, ' ');
  386.     WinScrollWindow(CrtWindow, 0, CharSize.Y, nil, nil, 0, nil, sw_InvalidateRgn);
  387.     WinUpdateWindow(CrtWindow);
  388.   end;
  389. end;
  390.  
  391. begin
  392.   InitWinCrt;
  393.   L := Cursor.X;
  394.   R := Cursor.X;
  395.   while Count > 0 do
  396.   begin
  397.     case Buffer^ of
  398.       #32..#255:
  399.         begin
  400.           ScreenPtr(Cursor.X, Cursor.Y)^ := Buffer^;
  401.           Inc(Cursor.X);
  402.           if Cursor.X > R then R := Cursor.X;
  403.           if Cursor.X = ScreenSize.X then NewLine;
  404.         end;
  405.       #13:
  406.         NewLine;
  407.       #9:
  408.         Cursor.X := (Cursor.X div 8)*8 + 8;
  409.       #8:
  410.         if Cursor.X > 0 then
  411.         begin
  412.           Dec(Cursor.X);
  413.           ScreenPtr(Cursor.X, Cursor.Y)^ := ' ';
  414.           if Cursor.X < L then L := Cursor.X;
  415.         end;
  416.       #7:
  417.         WinAlarm(hwnd_Desktop, wa_Note);
  418.     end;
  419.     Inc(Buffer);
  420.     Dec(Count);
  421.   end;
  422.   ShowText(L, R);
  423.   if AutoTracking then TrackCursor;
  424. end;
  425.  
  426. { Write character to CRT window }
  427.  
  428. procedure WriteChar(Ch: Char);
  429. begin
  430.   WriteBuf(@Ch, 1);
  431. end;
  432.  
  433. { Return keyboard status }
  434.  
  435. function KeyPressed: Boolean;
  436. var
  437.   M: QMsg;
  438. begin
  439.   InitWinCrt;
  440.   while WinPeekMsg(Anchor, M, 0, 0, 0, pm_Remove) do
  441.   begin
  442.     if M.Msg = wm_Quit then Terminate;
  443.     WinDispatchMsg(Anchor, M);
  444.   end;
  445.   KeyPressed := KeyCount > 0;
  446. end;
  447.  
  448. { Read key from CRT window }
  449.  
  450. function ReadKey: Char;
  451. begin
  452.   TrackCursor;
  453.   if not KeyPressed then
  454.   begin
  455.     Reading := True;
  456.     if Focused then ShowCursor;
  457.     repeat WinWaitMsg(Anchor, 0, 0) until KeyPressed;
  458.     if Focused then HideCursor;
  459.     Reading := False;
  460.   end;
  461.   ReadKey := KeyBuffer[0];
  462.   Dec(KeyCount);
  463.   Move(KeyBuffer[1], KeyBuffer[0], KeyCount);
  464. end;
  465.  
  466. { Read text buffer from CRT window }
  467.  
  468. function ReadBuf(Buffer: PChar; Count: Word): Word;
  469. var
  470.   Ch: Char;
  471.   I: Word;
  472. begin
  473.   I := 0;
  474.   repeat
  475.     Ch := ReadKey;
  476.     case Ch of
  477.       #8:
  478.         if I > 0 then
  479.         begin
  480.           Dec(I);
  481.           WriteChar(#8);
  482.         end;
  483.       #32..#255:
  484.         if I < Count - 2 then
  485.         begin
  486.           Buffer[I] := Ch;
  487.           Inc(I);
  488.           WriteChar(Ch);
  489.         end;
  490.     end;
  491.   until (Ch = #13) or (CheckEOF and (Ch = #26));
  492.   Buffer[I] := Ch;
  493.   Inc(I);
  494.   if Ch = #13 then
  495.   begin
  496.     Buffer[I] := #10;
  497.     Inc(I);
  498.     WriteChar(#13);
  499.   end;
  500.   TrackCursor;
  501.   ReadBuf := I;
  502. end;
  503.  
  504. { Set cursor position }
  505.  
  506. procedure GotoXY(X, Y: Integer);
  507. begin
  508.   CursorTo(X - 1, Y - 1);
  509. end;
  510.  
  511. { Return cursor X position }
  512.  
  513. function WhereX: Integer;
  514. begin
  515.   WhereX := Cursor.X + 1;
  516. end;
  517.  
  518. { Return cursor Y position }
  519.  
  520. function WhereY: Integer;
  521. begin
  522.   WhereY := Cursor.Y + 1;
  523. end;
  524.  
  525. { Clear screen }
  526.  
  527. procedure ClrScr;
  528. begin
  529.   InitWinCrt;
  530.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  531.   Cursor.X := 0; Cursor.Y := 0;
  532.   Origin.X := 0; Origin.Y := 0;
  533.   SetScrollBars;
  534.   WinInvalidateRect(CrtWindow, nil, False);
  535.   WinUpdateWindow(CrtWindow);
  536. end;
  537.  
  538. { Clear to end of line }
  539.  
  540. procedure ClrEol;
  541. begin
  542.   InitWinCrt;
  543.   FillChar(ScreenPtr(Cursor.X, Cursor.Y)^, ScreenSize.X - Cursor.X, ' ');
  544.   ShowText(Cursor.X, ScreenSize.X);
  545. end;
  546.  
  547. { wm_Create message handler }
  548.  
  549. procedure WindowCreate;
  550. begin
  551.   Created := True;
  552.   CrtWindowFrame := WinQueryWindow(CrtWindow, qw_Parent);
  553.   GetMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  554.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  555.   if not CheckBreak then EnableSysMenuItem(sc_Close, False);
  556.   VScrollBar := WinWindowFromID(CrtWindowFrame, fid_VertScroll);
  557.   HScrollBar := WinWindowFromID(CrtWindowFrame, fid_HorzScroll);
  558.   GetWindowParams;
  559. end;
  560.  
  561. { wm_Paint message handler }
  562.  
  563. procedure WindowPaint;
  564. var
  565.   X1, X2, Y1, Y2: Integer;
  566.   P: PointL;
  567.   R: RectL;
  568. begin
  569.   Painting := True;
  570.   InitPresentationSpace;
  571.   X1 := Max(0, PR.xLeft div CharSize.X + Origin.X);
  572.   X2 := Min(ScreenSize.X,
  573.     (PR.xRight + CharSize.X - 1) div CharSize.X + Origin.X);
  574.   Y1 := Max(0, (cyClient - PR.yTop) div CharSize.Y + Origin.Y);
  575.   Y2 := Min(ScreenSize.Y,
  576.     (cyClient - PR.yBottom + CharSize.Y - 1) div CharSize.Y + Origin.Y);
  577.   while Y1 < Y2 do
  578.   begin
  579.     P.X := (X1 - Origin.X) * CharSize.X;
  580.     P.Y := cyClient - (Y1 - Origin.Y + 1) * CharSize.Y + CharDescent;
  581.     GpiCharStringAt(PS, P, X2 - X1, ScreenPtr(X1, Y1));
  582.     Inc(Y1);
  583.   end;
  584.   R := PR;
  585.   R.yTop := P.Y - CharDescent;
  586.   if R.yTop > R.yBottom then WinFillRect(PS, R, clr_Background);
  587.   R := PR;
  588.   R.xLeft := (X2 - Origin.X) * CharSize.X;
  589.   if R.xLeft < R.xRight then WinFillRect(PS, R, clr_Background);
  590.   DonePresentationSpace;
  591.   Painting := False;
  592. end;
  593.  
  594. { wm_VScroll and wm_HScroll message handler }
  595.  
  596. procedure WindowScroll(Which, Action, Thumb: Integer);
  597. var
  598.   X, Y: Integer;
  599.  
  600. function GetNewPos(Pos, Page, Range: Integer): Integer;
  601. begin
  602.   case Action of
  603.     sb_LineUp: GetNewPos := Pos - 1;
  604.     sb_LineDown: GetNewPos := Pos + 1;
  605.     sb_PageUp: GetNewPos := Pos - Page;
  606.     sb_PageDown: GetNewPos := Pos + Page;
  607.     sb_SliderPosition: GetNewPos := Thumb;
  608.     sb_Top: GetNewPos := 0;
  609.     sb_Bottom: GetNewPos := Range;
  610.   else
  611.     GetNewPos := Pos;
  612.   end;
  613. end;
  614.  
  615. begin
  616.   X := Origin.X;
  617.   Y := Origin.Y;
  618.   case Which of
  619.     sbs_Horz: X := GetNewPos(X, ClientSize.X div 2, Range.X);
  620.     sbs_Vert: Y := GetNewPos(Y, ClientSize.Y, Range.Y);
  621.   end;
  622.   ScrollTo(X, Y);
  623. end;
  624.  
  625. { wm_Size message handler }
  626.  
  627. procedure WindowResize(X, Y: Integer);
  628. begin
  629.   if Focused and Reading then HideCursor;
  630.   cyClient := Y;
  631.   ClientSize.X := X div CharSize.X;
  632.   ClientSize.Y := Y div CharSize.Y;
  633.   Range.X := Max(0, ScreenSize.X - ClientSize.X);
  634.   Range.Y := Max(0, ScreenSize.Y - ClientSize.Y);
  635.   Origin.X := Min(Origin.X, Range.X);
  636.   Origin.Y := Min(Origin.Y, Range.Y);
  637.   SetScrollBars;
  638.   if Focused and Reading then ShowCursor;
  639. end;
  640.  
  641. { wm_Char message handler when characters are entered }
  642.  
  643. procedure WindowChar(Ch: Char);
  644. begin
  645.   if KeyCount < SizeOf(KeyBuffer) then
  646.   begin
  647.     KeyBuffer[KeyCount] := Ch;
  648.     Inc(KeyCount);
  649.   end;
  650. end;
  651.  
  652. { wm_Char message handler when non-character keys are pressed }
  653.  
  654. procedure WindowKeyDown(KeyDown: Word; CtrlDown: Boolean);
  655. var
  656.   I: Integer;
  657. begin
  658.   for I := 1 to ScrollKeyCount do
  659.     with ScrollKeys[I] do
  660.       if (Key = KeyDown) and (Ctrl = CtrlDown) then
  661.       begin
  662.         WindowScroll(SBar, Action, 0);
  663.         Exit;
  664.       end;
  665. end;
  666.  
  667. { wm_SetFocus message handler }
  668.  
  669. procedure WindowSetFocus(AFocused: Boolean);
  670. begin
  671.   Focused := AFocused;
  672.   if Reading then
  673.     if AFocused then ShowCursor else HideCursor;
  674. end;
  675.  
  676. { wm_Close message handler }
  677.  
  678. procedure WindowClose;
  679. begin
  680.   FreeMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  681.   Cursor.X := 0; Cursor.Y := 0;
  682.   Origin.X := 0; Origin.Y := 0;
  683.   WinPostMsg(CrtWindow, wm_Quit, 0, 0);
  684.   Created := False;
  685. end;
  686.  
  687. { CRT window procedure }
  688.  
  689. function CrtWinProc(Window: HWnd; Message: ULong; Mp1, Mp2: MParam): MResult;
  690. begin
  691.   CrtWinProc := 0;
  692.   CrtWindow := Window;
  693.   case Message of
  694.     wm_Create: WindowCreate;
  695.     wm_Paint: WindowPaint;
  696.     wm_VScroll: WindowScroll(sbs_Vert, LongRec(Mp2).Hi, LongRec(Mp2).Lo);
  697.     wm_HScroll: WindowScroll(sbs_Horz, LongRec(Mp2).Hi, LongRec(Mp2).Lo);
  698.     wm_Size: WindowResize(LongRec(Mp2).Lo, LongRec(Mp2).Hi);
  699.     wm_Char:
  700.       if (CharMsgMp1(Mp1).fs and kc_KeyUp) = 0 then
  701.       begin                                                     { Key is down }
  702.         if CheckBreak then                                      { Break enabled }
  703.           if (CharMsgMp2(Mp2).VKey = vk_Break) or               { Ctrl-Break }
  704.             (((CharMsgMp1(Mp1).fs and kc_Ctrl) <> 0) and
  705.              ((CharMsgMp2(Mp2).Chr = Ord('C')) or               { Ctrl-C }
  706.               (CharMsgMp2(Mp2).Chr = Ord('c')))) then Terminate;{ Ctrl-c }
  707.         if (CharMsgMp2(Mp2).Chr > 0) and (CharMsgMp2(Mp2).Chr <= 255) and
  708.           ((CharMsgMp1(Mp1).fs and (kc_Ctrl + kc_Alt)) = 0)
  709.           then WindowChar(Chr(CharMsgMp2(Mp2).Chr))
  710.           else WindowKeyDown(CharMsgMp2(Mp2).VKey, (CharMsgMp1(Mp1).fs and kc_Ctrl) <> 0);
  711.       end;
  712.     wm_SetFocus: WindowSetFocus(LongRec(Mp2).Lo <> 0);
  713.     wm_Close: WindowClose;
  714.   else
  715.     CrtWinProc := WinDefWindowProc(Window, Message, Mp1, Mp2);
  716.   end;
  717. end;
  718.  
  719. { CRT window frame procedure }
  720.  
  721. function FrameWndProc(Window: HWnd; Message: ULong; Mp1, Mp2: MParam): MResult;
  722. begin
  723.   FrameWndProc := OldFrameWndProc(Window, Message, Mp1, Mp2);
  724.   case Message of
  725.     wm_AdjustWindowPos:
  726.       with PSwp(Mp1)^ do
  727.       if (Fl and swp_Size) <> 0 then
  728.       begin
  729.         cX := Min(cX, MaxWindowSize.X);
  730.         cY := Min(cy, MaxWindowSize.Y);
  731.         if (Fl and swp_Maximize) <> 0 then
  732.         begin
  733.           X := (DesktopSize.X - cX) div 2;
  734.           Y := (DesktopSize.Y - cY) div 2;
  735.         end;
  736.       end;
  737.     wm_QueryTrackInfo:
  738.       with PTrackInfo(Mp2)^ do
  739.       begin
  740.         ptlMaxTrackSize.X := MaxWindowSize.X;
  741.         ptlMaxTrackSize.Y := MaxWindowSize.Y;
  742.       end;
  743.   end;
  744. end;
  745.  
  746. { Text file device driver output function }
  747.  
  748. function CrtOutput(var F: TTextRec): Integer; far;
  749. begin
  750.   if F.BufPos <> 0 then
  751.   begin
  752.     WriteBuf(PChar(F.BufPtr), F.BufPos);
  753.     F.BufPos := 0;
  754.     KeyPressed;
  755.   end;
  756.   CrtOutput := 0;
  757. end;
  758.  
  759. { Text file device driver input function }
  760.  
  761. function CrtInput(var F: TTextRec): Integer; far;
  762. begin
  763.   F.BufEnd := ReadBuf(PChar(F.BufPtr), F.BufSize);
  764.   F.BufPos := 0;
  765.   CrtInput := 0;
  766. end;
  767.  
  768. { Text file device driver close function }
  769.  
  770. function CrtClose(var F: TTextRec): Integer; far;
  771. begin
  772.   CrtClose := 0;
  773. end;
  774.  
  775. { Text file device driver open function }
  776.  
  777. function CrtOpen(var F: TTextRec): Integer; far;
  778. begin
  779.   if F.Mode = fmInput then
  780.   begin
  781.     F.InOutFunc := @CrtInput;
  782.     F.FlushFunc := nil;
  783.   end else
  784.   begin
  785.     F.Mode := fmOutput;
  786.     F.InOutFunc := @CrtOutput;
  787.     F.FlushFunc := @CrtOutput;
  788.   end;
  789.   F.CloseFunc := @CrtClose;
  790.   CrtOpen := 0;
  791. end;
  792.  
  793. { Assign text file to CRT device }
  794.  
  795. procedure AssignCrt(var F: Text);
  796. begin
  797.   with TTextRec(F) do
  798.   begin
  799.     Handle := $FFFFFFFF;
  800.     Mode := fmClosed;
  801.     BufSize := SizeOf(Buffer);
  802.     BufPtr := @Buffer;
  803.     OpenFunc := @CrtOpen;
  804.     Name[0] := #0;
  805.   end;
  806. end;
  807.  
  808. { Create CRT window if required }
  809.  
  810. procedure InitWinCrt;
  811. var
  812.   InitSize: PointL;
  813. begin
  814.   if not Created then
  815.   begin
  816.     DesktopSize.X := WinQuerySysValue(hwnd_Desktop, sv_CxScreen);
  817.     DesktopSize.Y := WinQuerySysValue(hwnd_Desktop, sv_CyScreen);
  818.     CrtWindowFrame := WinCreateStdWindow(hwnd_Desktop, 0, CrtCreateFlags,
  819.       CrtClassName, WindowTitle, 0, 0, 0, @CrtWindow);
  820.     InitSize.X := (DesktopSize.X * 3) div 4;
  821.     InitSize.Y := (DesktopSize.Y * 3) div 4;
  822.     if WindowSize.X = cw_UseDefault then WindowSize := InitSize;
  823.     WindowSize.X := Min(MaxWindowSize.X, WindowSize.X);
  824.     WindowSize.Y := Min(MaxWindowSize.Y, WindowSize.Y);
  825.     if WindowOrg.X = cw_UseDefault then
  826.     begin
  827.       WindowOrg.X := (DesktopSize.X - WindowSize.X) div 2;
  828.       WindowOrg.Y := (DesktopSize.Y - WindowSize.Y) div 2;
  829.     end;
  830.     WinSetWindowPos(
  831.       CrtWindowFrame, hNULL,
  832.       WindowOrg.X, WindowOrg.Y,
  833.       WindowSize.X, WindowSize.Y,
  834.       swp_Move + swp_Size + swp_Activate + swp_Show);
  835.     Pointer(@OldFrameWndProc) := WinSubclassWindow(CrtWindowFrame, FrameWndProc);
  836.   end;
  837. end;
  838.  
  839. { Destroy CRT window if required }
  840.  
  841. procedure DoneWinCrt;
  842. begin
  843.   if Created then
  844.   begin
  845.     WinDestroyWindow (Anchor);
  846.     WinDestroyMsgQueue (MsgQue);
  847.     WinTerminate (Anchor);
  848.   end;
  849.   Halt(0);
  850. end;
  851.  
  852. { WinCrt unit exit procedure }
  853.  
  854. procedure ExitWinCrt; far;
  855. var
  856.   Message: QMsg;
  857. begin
  858.   ExitProc := SaveExit;
  859.   if Created and (ErrorAddr = nil) then
  860.   begin
  861.     WinSetWindowText(CrtWindowFrame, InactiveTitle);
  862.     EnableSysMenuItem(sc_Close, True);
  863.     CheckBreak := False;
  864.     while WinGetMsg(Anchor, Message, 0, 0, 0) do WinDispatchMsg(Anchor, Message);
  865.   end;
  866. end;
  867.  
  868. begin
  869.   Anchor := WinInitialize(0);
  870.   MsgQue := WinCreateMsgQueue(Anchor, 0);
  871.   if MsgQue = 0 then Halt(254);
  872.   WinRegisterClass(Anchor, CrtClassName, CrtWinProc, cs_SizeRedraw, 0);
  873.   AssignCrt(Input);
  874.   Reset(Input);
  875.   AssignCrt(Output);
  876.   Rewrite(Output);
  877.   GetArgStr(WindowTitle, 0, SizeOf(WindowTitle));
  878.   StrPCopy(InactiveTitleBuf, '(Inactive ' + ParamStr(0) + ')');
  879.   SaveExit := ExitProc;
  880.   ExitProc := @ExitWinCrt;
  881.  
  882. {$ENDIF OS2}
  883. {$IFDEF WIN32}
  884.   // Win32 implementation
  885.  
  886. { MinMaxInfo array }
  887.  
  888. type
  889.   PMinMaxInfo = ^TMinMaxInfo;
  890.   TMinMaxInfo = array[0..4] of TPoint;
  891.  
  892. { CRT window procedure }
  893.  
  894. function CrtWinProc(Window: HWnd; Message, WParam: Word;
  895.   LParam: Longint): Longint; stdcall; forward;
  896.  
  897. { CRT window class }
  898.  
  899. const
  900.   CrtClass: TWndClass = (
  901.     style: cs_HRedraw + cs_VRedraw;
  902.     lpfnWndProc: @CrtWinProc;
  903.     cbClsExtra: 0;
  904.     cbWndExtra: 0;
  905.     hInstance: 0;
  906.     hIcon: 0;
  907.     hCursor: 0;
  908.     hbrBackground: 0;
  909.     lpszMenuName: nil;
  910.     lpszClassName: 'TPWinCrt');
  911.  
  912. const
  913.   CrtWindow: HWnd = 0;                  { CRT window handle }
  914.   FirstLine: Integer = 0;               { First line in circular buffer }
  915.   KeyCount: Integer = 0;                { Count of keys in KeyBuffer }
  916.   Created: Boolean = False;             { CRT window created? }
  917.   Focused: Boolean = False;             { CRT window focused? }
  918.   Reading: Boolean = False;             { Reading from CRT window? }
  919.   Painting: Boolean = False;            { Handling wm_Paint? }
  920.  
  921. var
  922.   SaveExit: Pointer;                    { Saved exit procedure pointer }
  923.   ScreenBuffer: PChar;                  { Screen buffer pointer }
  924.   ClientSize: TPoint;                   { Client area dimensions }
  925.   Range: TPoint;                        { Scroll bar ranges }
  926.   CharSize: TPoint;                     { Character cell size }
  927.   CharAscent: Integer;                  { Character ascent }
  928.   DC: HDC;                              { Global device context }
  929.   PS: TPaintStruct;                     { Global paint structure }
  930.   SaveFont: HFont;                      { Saved device context font }
  931.   KeyBuffer: array[0..63] of Char;      { Keyboard type-ahead buffer }
  932.  
  933. { Scroll keys table }
  934.  
  935. const
  936.   ScrollKeyCount = 12;
  937.   ScrollKeys: array[1..ScrollKeyCount] of TScrollKey = (
  938.     (Key: vk_Left;  Ctrl: False; SBar: sb_Horz; Action: sb_LineUp),
  939.     (Key: vk_Right; Ctrl: False; SBar: sb_Horz; Action: sb_LineDown),
  940.     (Key: vk_Left;  Ctrl: True;  SBar: sb_Horz; Action: sb_PageUp),
  941.     (Key: vk_Right; Ctrl: True;  SBar: sb_Horz; Action: sb_PageDown),
  942.     (Key: vk_Home;  Ctrl: False; SBar: sb_Horz; Action: sb_Top),
  943.     (Key: vk_End;   Ctrl: False; SBar: sb_Horz; Action: sb_Bottom),
  944.     (Key: vk_Up;    Ctrl: False; SBar: sb_Vert; Action: sb_LineUp),
  945.     (Key: vk_Down;  Ctrl: False; SBar: sb_Vert; Action: sb_LineDown),
  946.     (Key: vk_Prior; Ctrl: False; SBar: sb_Vert; Action: sb_PageUp),
  947.     (Key: vk_Next;  Ctrl: False; SBar: sb_Vert; Action: sb_PageDown),
  948.     (Key: vk_Home;  Ctrl: True;  SBar: sb_Vert; Action: sb_Top),
  949.     (Key: vk_End;   Ctrl: True;  SBar: sb_Vert; Action: sb_Bottom));
  950.  
  951. { Allocate device context }
  952.  
  953. procedure InitDeviceContext;
  954. begin
  955.   if Painting then
  956.     DC := BeginPaint(CrtWindow, PS) else
  957.     DC := GetDC(CrtWindow);
  958.   SaveFont := SelectObject(DC, GetStockObject(System_Fixed_Font));
  959.   SetTextColor(DC, GetSysColor(color_WindowText));
  960.   SetBkColor(DC, GetSysColor(color_Window));
  961. end;
  962.  
  963. { Release device context }
  964.  
  965. procedure DoneDeviceContext;
  966. begin
  967.   SelectObject(DC, SaveFont);
  968.   if Painting then
  969.     EndPaint(CrtWindow, PS) else
  970.     ReleaseDC(CrtWindow, DC);
  971. end;
  972.  
  973. { Show caret }
  974.  
  975. procedure ShowCursor;
  976. begin
  977.   CreateCaret(CrtWindow, 0, CharSize.X, 2);
  978.   SetCaretPos((Cursor.X - Origin.X) * CharSize.X,
  979.     (Cursor.Y - Origin.Y) * CharSize.Y + CharAscent);
  980.   ShowCaret(CrtWindow);
  981. end;
  982.  
  983. { Hide caret }
  984.  
  985. procedure HideCursor;
  986. begin
  987.   DestroyCaret;
  988. end;
  989.  
  990. { Update scroll bars }
  991.  
  992. procedure SetScrollBars;
  993. begin
  994.   SetScrollRange(CrtWindow, sb_Horz, 0, Max(1, Range.X), False);
  995.   SetScrollPos(CrtWindow, sb_Horz, Origin.X, True);
  996.   SetScrollRange(CrtWindow, sb_Vert, 0, Max(1, Range.Y), False);
  997.   SetScrollPos(CrtWindow, sb_Vert, Origin.Y, True);
  998. end;
  999.  
  1000. { Terminate CRT window }
  1001.  
  1002. procedure Terminate;
  1003. begin
  1004.   if Focused and Reading then HideCursor;
  1005.   Halt(255);
  1006. end;
  1007.  
  1008. { Set cursor position }
  1009.  
  1010. procedure CursorTo(X, Y: Integer);
  1011. begin
  1012.   Cursor.X := Max(0, Min(X, ScreenSize.X - 1));
  1013.   Cursor.Y := Max(0, Min(Y, ScreenSize.Y - 1));
  1014. end;
  1015.  
  1016. { Scroll window to given origin }
  1017.  
  1018. procedure ScrollTo(X, Y: Integer);
  1019. begin
  1020.   if Created then
  1021.   begin
  1022.     X := Max(0, Min(X, Range.X));
  1023.     Y := Max(0, Min(Y, Range.Y));
  1024.     if (X <> Origin.X) or (Y <> Origin.Y) then
  1025.     begin
  1026.       if X <> Origin.X then SetScrollPos(CrtWindow, sb_Horz, X, True);
  1027.       if Y <> Origin.Y then SetScrollPos(CrtWindow, sb_Vert, Y, True);
  1028.       ScrollWindow(CrtWindow,
  1029.         (Origin.X - X) * CharSize.X,
  1030.         (Origin.Y - Y) * CharSize.Y, nil, nil);
  1031.       Origin.X := X;
  1032.       Origin.Y := Y;
  1033.       UpdateWindow(CrtWindow);
  1034.     end;
  1035.   end;
  1036. end;
  1037.  
  1038. { Scroll to make cursor visible }
  1039.  
  1040. procedure TrackCursor;
  1041. begin
  1042.   ScrollTo(Max(Cursor.X - ClientSize.X + 1, Min(Origin.X, Cursor.X)),
  1043.     Max(Cursor.Y - ClientSize.Y + 1, Min(Origin.Y, Cursor.Y)));
  1044. end;
  1045.  
  1046. { Return pointer to location in screen buffer }
  1047.  
  1048. function ScreenPtr(X, Y: Integer): PChar;
  1049. begin
  1050.   Inc(Y, FirstLine);
  1051.   if Y >= ScreenSize.Y then Dec(Y, ScreenSize.Y);
  1052.   ScreenPtr := @ScreenBuffer[Y * ScreenSize.X + X];
  1053. end;
  1054.  
  1055. { Update text on cursor line }
  1056.  
  1057. procedure ShowText(L, R: Integer);
  1058. const
  1059.   z = 100;
  1060. const
  1061.   Tabs : Array[0..9] of Longint =
  1062.     ( 1*z, 2*z, 3*z, 4*z, 5*z, 6*z, 7*z, 8*z, 9*z, 10*z );
  1063. begin
  1064.   if L < R then
  1065.   begin
  1066.     InitDeviceContext;
  1067.     TabbedTextOut(DC, (L - Origin.X) * CharSize.X,
  1068.       (Cursor.Y - Origin.Y) * CharSize.Y,
  1069.       ScreenPtr(L, Cursor.Y), R - L,
  1070.       // Tab settings
  1071.       0, nil, 0);
  1072.     DoneDeviceContext;
  1073.   end;
  1074. end;
  1075.  
  1076. { Write text buffer to CRT window }
  1077.  
  1078. procedure WriteBuf(Buffer: PChar; Count: Word);
  1079. var
  1080.   L, R: Integer;
  1081.  
  1082. procedure NewLine;
  1083. begin
  1084.   ShowText(L, R);
  1085.   L := 0;
  1086.   R := 0;
  1087.   Cursor.X := 0;
  1088.   Inc(Cursor.Y);
  1089.   if Cursor.Y = ScreenSize.Y then
  1090.   begin
  1091.     Dec(Cursor.Y);
  1092.     Inc(FirstLine);
  1093.     if FirstLine = ScreenSize.Y then FirstLine := 0;
  1094.     FillChar(ScreenPtr(0, Cursor.Y)^, ScreenSize.X, ' ');
  1095.     ScrollWindow(CrtWindow, 0, -CharSize.Y, nil, nil);
  1096.     UpdateWindow(CrtWindow);
  1097.   end;
  1098. end;
  1099.  
  1100. begin
  1101.   InitWinCrt;
  1102.   L := Cursor.X;
  1103.   R := Cursor.X;
  1104.   while Count > 0 do
  1105.   begin
  1106.     case Buffer^ of
  1107.       #32..#255:
  1108.         begin
  1109.           ScreenPtr(Cursor.X, Cursor.Y)^ := Buffer^;
  1110.           Inc(Cursor.X);
  1111.           if Cursor.X > R then R := Cursor.X;
  1112.           if Cursor.X = ScreenSize.X then NewLine;
  1113.         end;
  1114.       #13:
  1115.         NewLine;
  1116.       #8:
  1117.         if Cursor.X > 0 then
  1118.         begin
  1119.           Dec(Cursor.X);
  1120.           ScreenPtr(Cursor.X, Cursor.Y)^ := ' ';
  1121.           if Cursor.X < L then L := Cursor.X;
  1122.         end;
  1123.       #7:
  1124.         MessageBeep(0);
  1125.     end;
  1126.     Inc(Buffer);
  1127.     Dec(Count);
  1128.   end;
  1129.   ShowText(L, R);
  1130.   if AutoTracking then TrackCursor;
  1131. end;
  1132.  
  1133. { Write character to CRT window }
  1134.  
  1135. procedure WriteChar(Ch: Char);
  1136. begin
  1137.   WriteBuf(@Ch, 1);
  1138. end;
  1139.  
  1140. { Return keyboard status }
  1141.  
  1142. function KeyPressed: Boolean;
  1143. var
  1144.   M: TMsg;
  1145. begin
  1146.   InitWinCrt;
  1147.   while PeekMessage(M, 0, 0, 0, pm_Remove) do
  1148.   begin
  1149.     if M.Message = wm_Quit then Terminate;
  1150.     TranslateMessage(M);
  1151.     DispatchMessage(M);
  1152.   end;
  1153.   KeyPressed := KeyCount > 0;
  1154. end;
  1155.  
  1156. { Read key from CRT window }
  1157.  
  1158. function ReadKey: Char;
  1159. begin
  1160.   TrackCursor;
  1161.   if not KeyPressed then
  1162.   begin
  1163.     Reading := True;
  1164.     if Focused then ShowCursor;
  1165.     repeat WaitMessage until KeyPressed;
  1166.     if Focused then HideCursor;
  1167.     Reading := False;
  1168.   end;
  1169.   ReadKey := KeyBuffer[0];
  1170.   Dec(KeyCount);
  1171.   Move(KeyBuffer[1], KeyBuffer[0], KeyCount);
  1172. end;
  1173.  
  1174. { Read text buffer from CRT window }
  1175.  
  1176. function ReadBuf(Buffer: PChar; Count: Word): Word;
  1177. var
  1178.   Ch: Char;
  1179.   I: Word;
  1180. begin
  1181.   I := 0;
  1182.   repeat
  1183.     Ch := ReadKey;
  1184.     case Ch of
  1185.       #8:
  1186.         if I > 0 then
  1187.         begin
  1188.           Dec(I);
  1189.           WriteChar(#8);
  1190.         end;
  1191.       #32..#255:
  1192.         if I < Count - 2 then
  1193.         begin
  1194.           Buffer[I] := Ch;
  1195.           Inc(I);
  1196.           WriteChar(Ch);
  1197.         end;
  1198.     end;
  1199.   until (Ch = #13) or (CheckEOF and (Ch = #26));
  1200.   Buffer[I] := Ch;
  1201.   Inc(I);
  1202.   if Ch = #13 then
  1203.   begin
  1204.     Buffer[I] := #10;
  1205.     Inc(I);
  1206.     WriteChar(#13);
  1207.   end;
  1208.   TrackCursor;
  1209.   ReadBuf := I;
  1210. end;
  1211.  
  1212. { Set cursor position }
  1213.  
  1214. procedure GotoXY(X, Y: Integer);
  1215. begin
  1216.   CursorTo(X - 1, Y - 1);
  1217. end;
  1218.  
  1219. { Return cursor X position }
  1220.  
  1221. function WhereX: Integer;
  1222. begin
  1223.   WhereX := Cursor.X + 1;
  1224. end;
  1225.  
  1226. { Return cursor Y position }
  1227.  
  1228. function WhereY: Integer;
  1229. begin
  1230.   WhereY := Cursor.Y + 1;
  1231. end;
  1232.  
  1233. { Clear screen }
  1234.  
  1235. procedure ClrScr;
  1236. begin
  1237.   InitWinCrt;
  1238.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  1239.   Cursor.X := 0;
  1240.   Cursor.Y := 0;
  1241.   Origin.X := 0;
  1242.   Origin.Y := 0;
  1243.   SetScrollBars;
  1244.   InvalidateRect(CrtWindow, nil, True);
  1245.   UpdateWindow(CrtWindow);
  1246. end;
  1247.  
  1248. { Clear to end of line }
  1249.  
  1250. procedure ClrEol;
  1251. begin
  1252.   InitWinCrt;
  1253.   FillChar(ScreenPtr(Cursor.X, Cursor.Y)^, ScreenSize.X - Cursor.X, ' ');
  1254.   ShowText(Cursor.X, ScreenSize.X);
  1255. end;
  1256.  
  1257. { wm_Create message handler }
  1258.  
  1259. procedure WindowCreate;
  1260. begin
  1261.   Created := True;
  1262.   GetMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  1263.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  1264.   if not CheckBreak then
  1265.     EnableMenuItem(GetSystemMenu(CrtWindow, False), sc_Close,
  1266.       mf_Disabled + mf_Grayed);
  1267. end;
  1268.  
  1269. { wm_Paint message handler }
  1270.  
  1271. procedure WindowPaint;
  1272. var
  1273.   X1, X2, Y1, Y2: Integer;
  1274. begin
  1275.   Painting := True;
  1276.   InitDeviceContext;
  1277.   X1 := Max(0, PS.rcPaint.left div CharSize.X + Origin.X);
  1278.   X2 := Min(ScreenSize.X,
  1279.     (PS.rcPaint.right + CharSize.X - 1) div CharSize.X + Origin.X);
  1280.   Y1 := Max(0, PS.rcPaint.top div CharSize.Y + Origin.Y);
  1281.   Y2 := Min(ScreenSize.Y,
  1282.     (PS.rcPaint.bottom + CharSize.Y - 1) div CharSize.Y + Origin.Y);
  1283.   while Y1 < Y2 do
  1284.   begin
  1285.     TextOut(DC, (X1 - Origin.X) * CharSize.X, (Y1 - Origin.Y) * CharSize.Y,
  1286.       ScreenPtr(X1, Y1), X2 - X1);
  1287.     Inc(Y1);
  1288.   end;
  1289.   DoneDeviceContext;
  1290.   Painting := False;
  1291. end;
  1292.  
  1293. { wm_VScroll and wm_HScroll message handler }
  1294.  
  1295. procedure WindowScroll(Which, Action, Thumb: Integer);
  1296. var
  1297.   X, Y: Integer;
  1298.  
  1299. function GetNewPos(Pos, Page, Range: Integer): Integer;
  1300. begin
  1301.   case Action of
  1302.     sb_LineUp: GetNewPos := Pos - 1;
  1303.     sb_LineDown: GetNewPos := Pos + 1;
  1304.     sb_PageUp: GetNewPos := Pos - Page;
  1305.     sb_PageDown: GetNewPos := Pos + Page;
  1306.     sb_Top: GetNewPos := 0;
  1307.     sb_Bottom: GetNewPos := Range;
  1308.     sb_ThumbPosition: GetNewPos := Thumb;
  1309.   else
  1310.     GetNewPos := Pos;
  1311.   end;
  1312. end;
  1313.  
  1314. begin
  1315.   X := Origin.X;
  1316.   Y := Origin.Y;
  1317.   case Which of
  1318.     sb_Horz: X := GetNewPos(X, ClientSize.X div 2, Range.X);
  1319.     sb_Vert: Y := GetNewPos(Y, ClientSize.Y, Range.Y);
  1320.   end;
  1321.   ScrollTo(X, Y);
  1322. end;
  1323.  
  1324. { wm_Size message handler }
  1325.  
  1326. procedure WindowResize(X, Y: Integer);
  1327. begin
  1328.   if Focused and Reading then HideCursor;
  1329.   ClientSize.X := X div CharSize.X;
  1330.   ClientSize.Y := Y div CharSize.Y;
  1331.   Range.X := Max(0, ScreenSize.X - ClientSize.X);
  1332.   Range.Y := Max(0, ScreenSize.Y - ClientSize.Y);
  1333.   Origin.X := Min(Origin.X, Range.X);
  1334.   Origin.Y := Min(Origin.Y, Range.Y);
  1335.   SetScrollBars;
  1336.   if Focused and Reading then ShowCursor;
  1337. end;
  1338.  
  1339. { wm_GetMinMaxInfo message handler }
  1340.  
  1341. procedure WindowMinMaxInfo(MinMaxInfo: PMinMaxInfo);
  1342. var
  1343.   X, Y: Integer;
  1344.   Metrics: TTextMetric;
  1345. begin
  1346.   InitDeviceContext;
  1347.   GetTextMetrics(DC, Metrics);
  1348.   CharSize.X := Metrics.tmMaxCharWidth;
  1349.   CharSize.Y := Metrics.tmHeight + Metrics.tmExternalLeading;
  1350.   CharAscent := Metrics.tmAscent;
  1351.   X := Min(ScreenSize.X * CharSize.X + GetSystemMetrics(sm_CXVScroll),
  1352.     GetSystemMetrics(sm_CXScreen)) + GetSystemMetrics(sm_CXFrame) * 2;
  1353.   Y := Min(ScreenSize.Y * CharSize.Y + GetSystemMetrics(sm_CYHScroll) +
  1354.     GetSystemMetrics(sm_CYCaption), GetSystemMetrics(sm_CYScreen)) +
  1355.     GetSystemMetrics(sm_CYFrame) * 2;
  1356.   MinMaxInfo^[1].x := X;
  1357.   MinMaxInfo^[1].y := Y;
  1358.   MinMaxInfo^[3].x := CharSize.X * 16 + GetSystemMetrics(sm_CXVScroll) +
  1359.     GetSystemMetrics(sm_CXFrame) * 2;
  1360.   MinMaxInfo^[3].y := CharSize.Y * 4 + GetSystemMetrics(sm_CYHScroll) +
  1361.     GetSystemMetrics(sm_CYFrame) * 2 + GetSystemMetrics(sm_CYCaption);
  1362.   MinMaxInfo^[4].x := X;
  1363.   MinMaxInfo^[4].y := Y;
  1364.   DoneDeviceContext;
  1365. end;
  1366.  
  1367. { wm_Char message handler }
  1368.  
  1369. procedure WindowChar(Ch: Char);
  1370. begin
  1371.   if CheckBreak and (Ch = #3) then Terminate;
  1372.   if KeyCount < SizeOf(KeyBuffer) then
  1373.   begin
  1374.     KeyBuffer[KeyCount] := Ch;
  1375.     Inc(KeyCount);
  1376.   end;
  1377. end;
  1378.  
  1379. { wm_KeyDown message handler }
  1380.  
  1381. procedure WindowKeyDown(KeyDown: Byte);
  1382. var
  1383.   CtrlDown: Boolean;
  1384.   I: Integer;
  1385. begin
  1386.   if CheckBreak and (KeyDown = vk_Cancel) then Terminate;
  1387.   CtrlDown := GetKeyState(vk_Control) < 0;
  1388.   for I := 1 to ScrollKeyCount do
  1389.     with ScrollKeys[I] do
  1390.       if (Key = KeyDown) and (Ctrl = CtrlDown) then
  1391.       begin
  1392.         WindowScroll(SBar, Action, 0);
  1393.         Exit;
  1394.       end;
  1395. end;
  1396.  
  1397. { wm_SetFocus message handler }
  1398.  
  1399. procedure WindowSetFocus;
  1400. begin
  1401.   Focused := True;
  1402.   if Reading then ShowCursor;
  1403. end;
  1404.  
  1405. { wm_KillFocus message handler }
  1406.  
  1407. procedure WindowKillFocus;
  1408. begin
  1409.   if Reading then HideCursor;
  1410.   Focused := False;
  1411. end;
  1412.  
  1413. { wm_Destroy message handler }
  1414.  
  1415. procedure WindowDestroy;
  1416. begin
  1417.   FreeMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  1418.   Cursor.X := 0;
  1419.   Cursor.Y := 0;
  1420.   Origin.X := 0;
  1421.   Origin.Y := 0;
  1422.   PostQuitMessage(0);
  1423.   Created := False;
  1424. end;
  1425.  
  1426. { CRT window procedure }
  1427.  
  1428. function CrtWinProc(Window: HWnd; Message, WParam: Word;
  1429.   LParam: Longint): Longint;
  1430. begin
  1431.   CrtWinProc := 0;
  1432.   CrtWindow := Window;
  1433.   case Message of
  1434.     wm_Create: WindowCreate;
  1435.     wm_Paint: WindowPaint;
  1436.     wm_VScroll: WindowScroll(sb_Vert, WParam, LongRec(LParam).Lo);
  1437.     wm_HScroll: WindowScroll(sb_Horz, WParam, LongRec(LParam).Lo);
  1438.     wm_Size: WindowResize( LongRec(LParam).Lo, LongRec(LParam).Hi);
  1439.     wm_GetMinMaxInfo: WindowMinMaxInfo(PMinMaxInfo(LParam));
  1440.     wm_Char: WindowChar(Char(WParam));
  1441.     wm_KeyDown: WindowKeyDown(Byte(WParam));
  1442.     wm_SetFocus: WindowSetFocus;
  1443.     wm_KillFocus: WindowKillFocus;
  1444.     wm_Destroy: WindowDestroy;
  1445.   else
  1446.     CrtWinProc := DefWindowProc(Window, Message, WParam, LParam);
  1447.   end;
  1448. end;
  1449.  
  1450. { Text file device driver output function }
  1451.  
  1452. function CrtOutput(var F: TTextRec): Integer; far;
  1453. begin
  1454.   if F.BufPos <> 0 then
  1455.   begin
  1456.     WriteBuf(PChar(F.BufPtr), F.BufPos);
  1457.     F.BufPos := 0;
  1458.     KeyPressed;
  1459.   end;
  1460.   CrtOutput := 0;
  1461. end;
  1462.  
  1463. { Text file device driver input function }
  1464.  
  1465. function CrtInput(var F: TTextRec): Integer; far;
  1466. begin
  1467.   F.BufEnd := ReadBuf(PChar(F.BufPtr), F.BufSize);
  1468.   F.BufPos := 0;
  1469.   CrtInput := 0;
  1470. end;
  1471.  
  1472. { Text file device driver close function }
  1473.  
  1474. function CrtClose(var F: TTextRec): Integer; far;
  1475. begin
  1476.   CrtClose := 0;
  1477. end;
  1478.  
  1479. { Text file device driver open function }
  1480.  
  1481. function CrtOpen(var F: TTextRec): Integer; far;
  1482. begin
  1483.   if F.Mode = fmInput then
  1484.   begin
  1485.     F.InOutFunc := @CrtInput;
  1486.     F.FlushFunc := nil;
  1487.   end else
  1488.   begin
  1489.     F.Mode := fmOutput;
  1490.     F.InOutFunc := @CrtOutput;
  1491.     F.FlushFunc := @CrtOutput;
  1492.   end;
  1493.   F.CloseFunc := @CrtClose;
  1494.   CrtOpen := 0;
  1495. end;
  1496.  
  1497. { Assign text file to CRT device }
  1498.  
  1499. procedure AssignCrt(var F: Text);
  1500. begin
  1501.   with TTextRec(F) do
  1502.   begin
  1503.     Handle := $FFFF;
  1504.     Mode := fmClosed;
  1505.     BufSize := SizeOf(Buffer);
  1506.     BufPtr := @Buffer;
  1507.     OpenFunc := @CrtOpen;
  1508.     Name[0] := #0;
  1509.   end;
  1510. end;
  1511.  
  1512. { Create CRT window if required }
  1513.  
  1514. procedure InitWinCrt;
  1515. begin
  1516.   if not Created then
  1517.   begin
  1518.     CrtWindow := CreateWindow(
  1519.       CrtClass.lpszClassName,
  1520.       WindowTitle,
  1521.       ws_OverlappedWindow + ws_HScroll + ws_VScroll,
  1522.       WindowOrg.X, WindowOrg.Y,
  1523.       WindowSize.X, WindowSize.Y,
  1524.       0,
  1525.       0,
  1526.       HInstance,
  1527.       nil);
  1528.     ShowWindow(CrtWindow, CmdShow);
  1529.     UpdateWindow(CrtWindow);
  1530.   end;
  1531. end;
  1532.  
  1533. { Destroy CRT window if required }
  1534.  
  1535. procedure DoneWinCrt;
  1536. begin
  1537.   if Created then DestroyWindow(CrtWindow);
  1538.   Halt(0);
  1539. end;
  1540.  
  1541. { WinCrt unit exit procedure }
  1542.  
  1543. procedure ExitWinCrt; far;
  1544. var
  1545.   P: PChar;
  1546.   Message: TMsg;
  1547.   Title: array[0..127] of Char;
  1548. begin
  1549.   ExitProc := SaveExit;
  1550.   if Created and (ErrorAddr = nil) then
  1551.   begin
  1552.     P := WindowTitle;
  1553.     WVSPrintF(Title, InactiveTitle, P);
  1554.     SetWindowText(CrtWindow, Title);
  1555.     EnableMenuItem(GetSystemMenu(CrtWindow, False), sc_Close, mf_Enabled);
  1556.     CheckBreak := False;
  1557.     while GetMessage(Message, 0, 0, 0) do
  1558.     begin
  1559.       TranslateMessage(Message);
  1560.       DispatchMessage(Message);
  1561.     end;
  1562.   end;
  1563. end;
  1564.  
  1565. begin
  1566.   if HPrevInst = 0 then
  1567.   begin
  1568.     CrtClass.hInstance := HInstance;
  1569.     CrtClass.hIcon := LoadIcon(0, idi_Application);
  1570.     CrtClass.hCursor := LoadCursor(0, idc_Arrow);
  1571.     CrtClass.hbrBackground := color_Window + 1;
  1572.     RegisterClass(CrtClass);
  1573.   end;
  1574.   AssignCrt(Input);
  1575.   Reset(Input);
  1576.   AssignCrt(Output);
  1577.   Rewrite(Output);
  1578.   GetModuleFileName(HInstance, WindowTitle, SizeOf(WindowTitle));
  1579.   OemToAnsi(WindowTitle, WindowTitle);
  1580.   SaveExit := ExitProc;
  1581.   ExitProc := @ExitWinCrt;
  1582. {$ENDIF WIN32}
  1583.  
  1584. {$IFDEF DPMI32_LINUX}
  1585.  
  1586. procedure InitWinCrt;
  1587.   begin
  1588.   end;
  1589.  
  1590. procedure DoneWinCrt;
  1591.   begin
  1592.   end;
  1593.  
  1594. procedure WriteBuf(Buffer: PChar; Count: Word);
  1595.   const
  1596.     clear_char  :char=' ';
  1597.   var
  1598.     MaxX,MaxY,f :word;
  1599.     x,y,t       :smallword;
  1600.  
  1601. procedure NewLine;
  1602.   begin
  1603.     x:=0;
  1604.     if y+1>=MaxY then
  1605.       SysScrollUp(0,0,MaxX-1,MaxY-1,1,WinCrt_Cell)
  1606.     else
  1607.       Inc(y);
  1608.   end;
  1609.  
  1610. begin
  1611.   SysGetVideoModeInfo(MaxX,MaxY,f);
  1612.   SysGetCurPos(x,y);
  1613.   while Count > 0 do
  1614.     begin
  1615.       case Buffer^ of
  1616.         #32..#255:
  1617.           begin
  1618.             SysWrtCharStrAtt(Buffer,1,x,y,Mem[Ofs(WinCrt_Cell)+1]);
  1619.             Inc(x);
  1620.             if x>=MaxX then
  1621.               Newline;
  1622.           end;
  1623.       #13:
  1624.         NewLine;
  1625.       #9:
  1626.         begin
  1627.           T:=x;
  1628.           repeat
  1629.             SysWrtCharStrAtt(@clear_char,1,x,y,Mem[Ofs(WinCrt_Cell)+1]);
  1630.             Inc(x);
  1631.             if x>=MaxX then
  1632.               Newline;
  1633.             Inc(T);
  1634.           until (T mod 8)=0;
  1635.         end;
  1636.       #8:
  1637.         if x>0 then
  1638.           begin
  1639.             Dec(x);
  1640.             SysWrtCharStrAtt(Addr(clear_char),1,x,y,Mem[Ofs(WinCrt_Cell)+1]);
  1641.           end;
  1642.       #7:
  1643.         SysBeep;
  1644.       end;
  1645.  
  1646.       Inc(Buffer);
  1647.       Dec(Count);
  1648.     end;
  1649.  
  1650.   SysTVSetCurPos(x,y);
  1651. end;
  1652.  
  1653. procedure WriteChar(Ch: Char);
  1654.   begin
  1655.     WriteBuf(@Ch, 1);
  1656.   end;
  1657.  
  1658. function KeyPressed: Boolean;
  1659.   begin
  1660.     KeyPressed:=SysKeyPressed;
  1661.   end;
  1662.  
  1663. function ReadKey: Char;
  1664.   begin
  1665.     ReadKey:=SysReadKey;
  1666.   end;
  1667.  
  1668. function ReadBuf(Buffer: PChar; Count: Word): Word;
  1669. var
  1670.   Ch: Char;
  1671.   I: Word;
  1672. begin
  1673.   I := 0;
  1674.   repeat
  1675.     Ch := ReadKey;
  1676.     case Ch of
  1677.       #8:
  1678.         if I > 0 then
  1679.         begin
  1680.           Dec(I);
  1681.           WriteChar(#8);
  1682.         end;
  1683.       #32..#255:
  1684.         if I < Count - 2 then
  1685.         begin
  1686.           Buffer[I] := Ch;
  1687.           Inc(I);
  1688.           WriteChar(Ch);
  1689.         end;
  1690.     end;
  1691.   until (Ch = #13) or (CheckEOF and (Ch = #26));
  1692.   Buffer[I] := Ch;
  1693.   Inc(I);
  1694.   if Ch = #13 then
  1695.   begin
  1696.     Buffer[I] := #10;
  1697.     Inc(I);
  1698.     WriteChar(#13);
  1699.   end;
  1700.   TrackCursor;
  1701.   ReadBuf := I;
  1702. end;
  1703.  
  1704. procedure GotoXY(X, Y: Integer);
  1705.   begin
  1706.     CursorTo(X - 1, Y - 1);
  1707.   end;
  1708.  
  1709. function WhereX: Integer;
  1710.   var
  1711.     x,y         :smallword;
  1712.   begin
  1713.     SysGetCurPos(x,y);
  1714.     WhereX:=x+1;
  1715.   end;
  1716.  
  1717. function WhereY: Integer;
  1718.   var
  1719.     x,y         :smallword;
  1720.   begin
  1721.     SysGetCurPos(x,y);
  1722.     WhereY:=y+1;
  1723.   end;
  1724.  
  1725. procedure ClrScr;
  1726.   var
  1727.     MaxX,MaxY,f :word;
  1728.   begin
  1729.     SysGetVideoModeInfo(MaxX,MaxY,f);
  1730.     SysScrollUp(0,0,MaxX-1,MaxY-1,MaxY,WinCrt_Cell);
  1731.     CursorTo(0,0);
  1732.   end;
  1733.  
  1734. procedure ClrEol;
  1735.   var
  1736.     maxx,maxy,f :word;
  1737.     x,y         :smallword;
  1738.     fill        :array[0..132] of char;
  1739.   begin
  1740.     SysGetVideoModeInfo(MaxX,MaxY,f);
  1741.     SysGetCurPos(x,y);
  1742.     FillChar(fill,SizeOf(fill),0);
  1743.     SysWrtCharStrAtt(@fill,MaxX-x,x,y,Mem[Ofs(WinCrt_Cell)+1]);
  1744.   end;
  1745.  
  1746. procedure CursorTo(X, Y: Integer);
  1747.   begin
  1748.     SysTVSetCurPos(x,y);
  1749.   end;
  1750.  
  1751. procedure ScrollTo(X, Y: Integer);
  1752.   begin
  1753.     // not implemented
  1754.   end;
  1755.  
  1756. procedure TrackCursor;
  1757.   begin
  1758.   end;
  1759.  
  1760. function CrtOutput(var F: TTextRec): Integer; far;
  1761. begin
  1762.   if F.BufPos <> 0 then
  1763.   begin
  1764.     WriteBuf(PChar(F.BufPtr), F.BufPos);
  1765.     F.BufPos := 0;
  1766.     KeyPressed;
  1767.   end;
  1768.   CrtOutput := 0;
  1769. end;
  1770.  
  1771. { Text file device driver input function }
  1772.  
  1773. function CrtInput(var F: TTextRec): Integer; far;
  1774. begin
  1775.   F.BufEnd := ReadBuf(PChar(F.BufPtr), F.BufSize);
  1776.   F.BufPos := 0;
  1777.   CrtInput := 0;
  1778. end;
  1779.  
  1780. { Text file device driver close function }
  1781.  
  1782. function CrtClose(var F: TTextRec): Integer; far;
  1783. begin
  1784.   CrtClose := 0;
  1785. end;
  1786.  
  1787. { Text file device driver open function }
  1788.  
  1789. function CrtOpen(var F: TTextRec): Integer; far;
  1790. begin
  1791.   if F.Mode = fmInput then
  1792.   begin
  1793.     F.InOutFunc := @CrtInput;
  1794.     F.FlushFunc := nil;
  1795.   end else
  1796.   begin
  1797.     F.Mode := fmOutput;
  1798.     F.InOutFunc := @CrtOutput;
  1799.     F.FlushFunc := @CrtOutput;
  1800.   end;
  1801.   F.CloseFunc := @CrtClose;
  1802.   CrtOpen := 0;
  1803. end;
  1804.  
  1805. { Assign text file to CRT device }
  1806.  
  1807. procedure AssignCrt(var F: Text);
  1808. begin
  1809.   with TTextRec(F) do
  1810.   begin
  1811.     Handle := $FFFFFFFF;
  1812.     Mode := fmClosed;
  1813.     BufSize := SizeOf(Buffer);
  1814.     BufPtr := @Buffer;
  1815.     OpenFunc := @CrtOpen;
  1816.     Name[0] := #0;
  1817.   end;
  1818. end;
  1819.  
  1820.  
  1821. begin
  1822.   AssignCrt(Input);
  1823.   Reset(Input);
  1824.   AssignCrt(Output);
  1825.   Rewrite(Output);
  1826. {$ENDIF DPMI32_LINUX}
  1827.  
  1828.  
  1829. end.
  1830.  
  1831.