home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 1995 December / SOFM_Dec1995.bin / pc / os2 / vpascal / source / rtl / crt.pas < prev    next >
Pascal/Delphi Source File  |  1995-10-31  |  16KB  |  620 lines

  1. {█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█}
  2. {█                                                       █}
  3. {█      Virtual Pascal Runtime Library.  Version 1.0.    █}
  4. {█      CRT Interface unit for OS/2                      █}
  5. {█      ─────────────────────────────────────────────────█}
  6. {█      Copyright (C) 1995 B&M&T Corporation             █}
  7. {█      ─────────────────────────────────────────────────█}
  8. {█      Written by Vitaly Miryanov                       █}
  9. {█                                                       █}
  10. {▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀}
  11.  
  12. {$S-,R-,Q-,I-,Cdecl-,OrgName-,AlignRec-}
  13.  
  14. unit Crt;
  15.  
  16. interface
  17.  
  18. uses Use32;
  19.  
  20. const
  21.  
  22. { CRT modes }
  23.  
  24.   BW40          = 0;            { 40x25 B/W on Color Adapter   }
  25.   CO40          = 1;            { 40x25 Color on Color Adapter }
  26.   BW80          = 2;            { 80x25 B/W on Color Adapter   }
  27.   CO80          = 3;            { 80x25 Color on Color Adapter }
  28.   Mono          = 7;            { 80x25 on Monochrome Adapter  }
  29.   Font8x8       = 256;          { Add-in for 8x8 font          }
  30.  
  31. { Foreground and background color constants }
  32.  
  33.   Black         = 0;
  34.   Blue          = 1;
  35.   Green         = 2;
  36.   Cyan          = 3;
  37.   Red           = 4;
  38.   Magenta       = 5;
  39.   Brown         = 6;
  40.   LightGray     = 7;
  41.  
  42. { Foreground color constants }
  43.  
  44.   DarkGray      = 8;
  45.   LightBlue     = 9;
  46.   LightGreen    = 10;
  47.   LightCyan     = 11;
  48.   LightRed      = 12;
  49.   LightMagenta  = 13;
  50.   Yellow        = 14;
  51.   White         = 15;
  52.  
  53. { Add-in for blinking }
  54.  
  55.   Blink         = 128;
  56.  
  57. { Interface variables }
  58.  
  59. const
  60.   CheckBreak: Boolean = True;   { Enable Ctrl-Break      }
  61.   CheckEOF: Boolean = False;    { Allow Ctrl-Z for EOF?  }
  62.   TextAttr: Byte = LightGray;   { Current text attribute }
  63.  
  64. var
  65.   LastMode: Word;               { Current text mode }
  66.   WindMin: Word;                { Window upper left coordinates }
  67.   WindMax: Word;                { Window lower right coordinates }
  68.  
  69. { The following interface variables are not used (for compatibility only) }
  70.  
  71. const
  72.   DirectVideo: Boolean = False; { Enable direct video addressing }
  73.   CheckSnow: Boolean = True;    { Enable snow filtering }
  74.  
  75. { Interface procedures }
  76.  
  77. procedure AssignCrt(var F: Text);
  78. function KeyPressed: Boolean;
  79. function ReadKey: Char;
  80. procedure TextMode(Mode: Integer);
  81. procedure Window(X1,Y1,X2,Y2: Byte);
  82. procedure GotoXY(X,Y: Byte);
  83. function WhereX: Byte;
  84. function WhereY: Byte;
  85. procedure ClrScr;
  86. procedure ClrEol;
  87. procedure InsLine;
  88. procedure DelLine;
  89. procedure TextColor(Color: Byte);
  90. procedure TextBackground(Color: Byte);
  91. procedure LowVideo;
  92. procedure HighVideo;
  93. procedure NormVideo;
  94. procedure Delay(MS: Longint);
  95.  
  96. { The following procedures are not implemented
  97.  
  98. procedure Sound(Hz: Word);
  99. procedure NoSound;
  100.  
  101. use new procedure PlaySound instead
  102.  
  103. }
  104.  
  105. procedure PlaySound(Freq,Duration: Longint);
  106.  
  107. implementation
  108.  
  109. uses Dos, Os2Def, Os2Base, Xcpt;
  110.  
  111. { Private variables }
  112.  
  113. var
  114.   VioMode: VioModeInfo;
  115.   NormAttr: Byte;
  116.   DelayCount: Longint;
  117.  
  118. const
  119.   ScanCode: Byte = 0;
  120.  
  121. { Determines if a key has been pressed on the keyboard and returns True }
  122. { if a key has been pressed                                             }
  123.  
  124. function KeyPressed: Boolean;
  125. var
  126.   Key: KbdKeyInfo;
  127. begin
  128.   KbdPeek(Key,0);
  129.   KeyPressed := (ScanCode <> 0) or ((Key.fbStatus and kbdtrf_Final_Char_In) <> 0);
  130. end;
  131.  
  132. { Reads a character from the keyboard and returns a character or an     }
  133. { extended scan code.                                                   }
  134.  
  135. function ReadKey: Char;
  136. var
  137.   Key: KbdKeyInfo;
  138. begin
  139.   If ScanCode <> 0 then
  140.   begin
  141.     ReadKey  := Chr(ScanCode);
  142.     ScanCode := 0;
  143.   end
  144.  else
  145.   begin
  146.     KbdCharIn(Key,io_Wait,0);
  147.     case Key.chChar of
  148.       #0: ScanCode := Key.chScan;
  149.       #$E0:           {   Up, Dn, Left Rt Ins Del Home End PgUp PgDn C-Home C-End C-PgUp C-PgDn C-Left C-Right C-Up C-Dn }
  150.         if Key.chScan in [$48,$50,$4B,$4D,$52,$53,$47, $4F,$49, $51, $77,   $75,  $84,   $76,   $73,   $74,    $8D, $91] then
  151.         begin
  152.           ScanCode := Key.chScan;
  153.           Key.chChar := #0;
  154.         end;
  155.     end;
  156.     ReadKey := Key.chChar;
  157.   end;
  158. end;
  159.  
  160. { Reads normal character attribute }
  161.  
  162. procedure ReadNormAttr;
  163. var
  164.   Cell,Size: SmallWord;
  165. begin
  166.   Size := 2;
  167.   VioReadCellStr(Cell, Size, WhereY-1, WhereX-1, 0);
  168.   NormAttr := Hi(Cell) and $7F;
  169.   NormVideo;
  170. end;
  171.  
  172. { Setups window coordinates }
  173.  
  174. procedure SetWindowPos;
  175. begin
  176.   WindMin := 0;
  177.   WindMax := VioMode.Col - 1 + (VioMode.Row - 1) shl 8;
  178. end;
  179.  
  180. { Stores current video mode in LastMode }
  181.  
  182. procedure GetLastMode;
  183. begin
  184.   VioMode.cb := SizeOf(VioMode);
  185.   VioGetMode(VioMode, 0);
  186.   with VioMode do
  187.   begin
  188.     if Col = 40 then LastMode := BW40 else LastMode := BW80;
  189.     if (fbType and vgmt_DisableBurst) = 0 then
  190.       if LastMode = BW40 then LastMode := CO40 else LastMode := CO80;
  191.     if Color = 0 then LastMode := Mono;
  192.     if Row > 25 then Inc(LastMode,Font8x8);
  193.   end;
  194. end;
  195.  
  196. { Selects a specific text mode. The valid text modes are:               }
  197. {   BW40: 40x25 Black and white                                         }
  198. {   CO40  40x25 Color                                                   }
  199. {   BW80  80x25 Black and white                                         }
  200. {   CO80  80x25 Color                                                   }
  201. {   Mono  80x25 Black and white                                         }
  202. {   Font8x8 (Add-in) 43-/50-line mode                                   }
  203.  
  204. procedure TextMode(Mode: Integer);
  205. var BiosMode: Byte; Cell: SmallWord; VideoConfig: VioConfigInfo;
  206. begin
  207.   GetLastMode;
  208.   TextAttr := LightGray;
  209.   BiosMode := Lo(Mode);
  210.   VideoConfig.cb := SizeOf(VideoConfig);
  211.   VioGetConfig(0, VideoConfig, 0);
  212.   with VioMode do
  213.   begin
  214.     cb := SizeOf(VioMode);
  215.     fbType := vgmt_Other;
  216.     Color := colors_16;         { Color }
  217.     Row := 25;                  { 80x25 }
  218.     Col := 80;
  219.     VRes := 400;
  220.     HRes := 720;
  221.     case BiosMode of            { 40x25 }
  222.       BW40,CO40:
  223.         begin
  224.           Col := 40; HRes := 360;
  225.         end;
  226.     end;
  227.     if (Mode and Font8x8) <> 0 then
  228.     case VideoConfig.Adapter of { 80x43 }
  229.       display_Monochrome..display_CGA: ;
  230.       display_EGA:
  231.         begin
  232.           Row := 43; VRes := 350; HRes := 640;
  233.         end;
  234.       else                      { 80x50 }
  235.         begin
  236.           Row := 50; VRes := 400; HRes := 720;
  237.         end;
  238.     end;
  239.     case BiosMode of            { Black and white }
  240.       BW40,BW80: fbType := vgmt_Other + vgmt_DisableBurst;
  241.       Mono:
  242.         begin                   { Monochrome }
  243.           HRes := 720; VRes := 350; Color := 0; fbType := 0;
  244.         end;
  245.     end;
  246.   end;
  247.   VioSetMode(VioMode, 0);
  248.   VioGetMode(VioMode, 0);
  249.   NormVideo;
  250.   SetWindowPos;
  251.   Cell := Ord(' ') + TextAttr shl 8;    { Clear entire screen }
  252.   VioScrollUp(0,0,65535,65535,65535,Cell,0);
  253. end;
  254.  
  255. { Defines a text window on the screen.                                  }
  256.  
  257. procedure Window(X1,Y1,X2,Y2: Byte);
  258. begin
  259.   if (X1 <= X2) and (Y1 <= Y2) then
  260.   begin
  261.     Dec(X1);
  262.     Dec(Y1);
  263.     if (X1 >= 0) and (Y1 >= 0) then
  264.     begin
  265.       Dec(X2);
  266.       Dec(Y2);
  267.       if (X2 < VioMode.Col) and (Y2 < VioMode.Row) then
  268.       begin
  269.         WindMin := X1 + Y1 shl 8;
  270.         WindMax := X2 + Y2 shl 8;
  271.         GotoXY(1,1);
  272.       end;
  273.     end;
  274.   end;
  275. end;
  276.  
  277. { Moves the cursor to the given coordinates within the screen.          }
  278.  
  279. procedure GotoXY(X,Y: Byte);
  280. var
  281.   X1,Y1: Word;
  282. begin
  283.   if (X > 0) and (Y > 0) then
  284.   begin
  285.     X1 := X - 1 + Lo(WindMin);
  286.     Y1 := Y - 1 + Hi(WindMin);
  287.     if (X1 <= Lo(WindMax)) and (Y1 <= Hi(WindMax)) then VioSetCurPos(Y1,X1,0);
  288.   end;
  289. end;
  290.  
  291. { Returns the X coordinate of the current cursor location.              }
  292.  
  293. function WhereX: Byte;
  294. var
  295.   X,Y: SmallWord;
  296. begin
  297.   VioGetCurPos(Y,X,0);
  298.   WhereX := X - Lo(WindMin) + 1;
  299. end;
  300.  
  301. { Returns the Y coordinate of the current cursor location.              }
  302.  
  303. function WhereY: Byte;
  304. var
  305.   X,Y: SmallWord;
  306. begin
  307.   VioGetCurPos(Y,X,0);
  308.   WhereY := Y - Hi(WindMin) + 1;
  309. end;
  310.  
  311. { Clears the screen and returns the cursor to the upper-left corner.    }
  312.  
  313. procedure ClrScr;
  314. var
  315.   Cell: SmallWord;
  316. begin
  317.   Cell := Ord(' ') + TextAttr shl 8;
  318.   VioScrollUp(Hi(WindMin),Lo(WindMin),Hi(WindMax),Lo(WindMax),Hi(WindMax)-Hi(WindMin)+1,Cell,0);
  319.   GotoXY(1,1);
  320. end;
  321.  
  322. { Clears all characters from the cursor position to the end of the line }
  323. { without moving the cursor.                                            }
  324.  
  325. procedure ClrEol;
  326. var
  327.   Cell,X,Y: SmallWord;
  328. begin
  329.   Cell := Ord(' ') + TextAttr shl 8;
  330.   VioGetCurPos(Y,X,0);
  331.   VioScrollUp(Y,X,Y,Lo(WindMax),1,Cell,0);
  332. end;
  333.  
  334. { Inserts an empty line at the cursor position.                         }
  335.  
  336. procedure InsLine;
  337. var
  338.   Cell,X,Y: SmallWord;
  339. begin
  340.   Cell := Ord(' ') + TextAttr shl 8;
  341.   VioGetCurPos(Y,X,0);
  342.   VioScrollDn(Y,Lo(WindMin),Hi(WindMax),Lo(WindMax),1,Cell,0);
  343. end;
  344.  
  345. { Deletes the line containing the cursor.                               }
  346.  
  347. procedure DelLine;
  348. var
  349.   Cell,X,Y: SmallWord;
  350. begin
  351.   Cell := Ord(' ') + TextAttr shl 8;
  352.   VioGetCurPos(Y,X,0);
  353.   VioScrollUp(Y,Lo(WindMin),Hi(WindMax),Lo(WindMax),1,Cell,0);
  354. end;
  355.  
  356. { Selects the foreground character color.                               }
  357.  
  358. procedure TextColor(Color: Byte);
  359. begin
  360.   if Color > White then Color := (Color and $0F) or $80;
  361.   TextAttr := (TextAttr and $70) or Color;
  362. end;
  363.  
  364. { Selects the background color.                                         }
  365.  
  366. procedure TextBackground(Color: Byte);
  367. begin
  368.   TextAttr := (TextAttr and $8F) or ((Color and $07) shl 4);
  369. end;
  370.  
  371. { Selects low intensity characters.                                     }
  372.  
  373. procedure LowVideo;
  374. begin
  375.   TextAttr := TextAttr and $F7;
  376. end;
  377.  
  378. { Selects normal intensity characters.                                  }
  379.  
  380. procedure NormVideo;
  381. begin
  382.   TextAttr := NormAttr;
  383. end;
  384.  
  385. { Selects high-intensity characters.                                    }
  386.  
  387. procedure HighVideo;
  388. begin
  389.   TextAttr := TextAttr or $08;
  390. end;
  391.  
  392. { Waits for next timer tick or delays 1ms }
  393.  
  394. function DelayLoop(Count: Longint; var StartValue: ULong): Longint;
  395. var
  396.   Value: ULong;
  397. begin
  398.   repeat
  399.     DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,Value,SizeOf(Value));
  400.     Dec(Count);
  401.   until (Value <> StartValue) or (Count = -1);
  402.   StartValue := Value;
  403.   DelayLoop := Count;
  404. end;
  405.  
  406. { Delays a specified number of milliseconds. DosSleep is too inexact on }
  407. { small time intervals. More over, the least time interval for DosSleep }
  408. { is 1 timer tick (usually 31ms). That is why for small time intervals  }
  409. { special delay routine is used. Unfortunately, even this routine cannot}
  410. { be exact in the multitasking environment.                             }
  411.  
  412. procedure Delay(MS: Longint);
  413. var
  414.   StartValue,Value: ULong;
  415.   Count: Longint;
  416. begin
  417.   if MS >= 5*31 then DosSleep(MS)
  418.  else
  419.   begin
  420.     DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,StartValue,SizeOf(StartValue));
  421.     Value := StartValue;
  422.     Count := MS;
  423.     repeat
  424.       DelayLoop(DelayCount,Value);
  425.       Dec(Count)
  426.     until (Value-StartValue >= MS) or (Count <= 0);
  427.   end;
  428. end;
  429.  
  430. { Calculates 1ms delay count for DelayLoop routine. }
  431. { CalcDelayCount is called once at startup.         }
  432.  
  433. procedure CalcDelayCount;
  434. var
  435.   Interval,StartValue,Value: ULong;
  436. begin
  437.   DosQuerySysInfo(qsv_Timer_Interval,qsv_Timer_Interval,Interval,SizeOf(Interval));
  438.   DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,StartValue,SizeOf(StartValue));
  439.   repeat
  440.     DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,Value,SizeOf(Value));
  441.   until Value <> StartValue;
  442.   DelayCount := -DelayLoop(-1,Value) div Interval * 10;
  443. end;
  444.  
  445. { Plays sound of a specified frequency and duration.                    }
  446.  
  447. procedure PlaySound(Freq,Duration: Longint);
  448. begin
  449.   DosBeep(Freq,Duration);
  450. end;
  451.  
  452. { Do line feed operation }
  453.  
  454. procedure LineFeed;
  455. var
  456.   Cell: SmallWord;
  457. begin
  458.   Cell := Ord(' ') + TextAttr shl 8;
  459.   VioScrollUp(Hi(WindMin),Lo(WindMin),Hi(WindMax),Lo(WindMax),1,Cell,0);
  460. end;
  461.  
  462. { Outputs packed string to the CRT device }
  463.  
  464. procedure WritePackedString(S: PChar; Len: Longint);
  465. var
  466.   X,Y: SmallWord;
  467.   C: Char;
  468.   i: Longint;
  469. begin
  470.   for i := 0 to Len - 1 do
  471.   begin
  472.     C := S[i];
  473.     VioGetCurPos(Y,X,0);
  474.     case C of
  475.       ^J: if Y >= Hi(WindMax) then LineFeed else Inc(Y); { Line Feed       }
  476.       ^M: X := Lo(WindMin);                              { Carriage return }
  477.       ^H: if X > Lo(WindMin) then Dec(X);                { Backspace       }
  478.       ^G: VioWrtTTY(@C,1,0);                             { Bell            }
  479.       else
  480.         begin
  481.           VioWrtCharStrAtt(@C,1,Y,X,TextAttr,0);
  482.           Inc(X);
  483.           if X > Lo(WindMax) then
  484.           begin
  485.             X := Lo(WindMin);
  486.             Inc(Y);
  487.           end;
  488.           if Y > Hi(WindMax) then
  489.           begin
  490.             LineFeed;
  491.             Y := Hi(WindMax);
  492.           end;
  493.         end;
  494.     end;
  495.     VioSetCurPos(Y,X,0);
  496.   end;
  497. end;
  498.  
  499. { CRT text file I/O functions }
  500.  
  501. function CrtRead(var F: Text): Longint;
  502. var
  503.   CurPos: Longint;
  504.   C: Char;
  505. begin
  506.   with TextRec(F) do
  507.   begin
  508.     CurPos := 0;
  509.     repeat
  510.       ScanCode := 0;
  511.       C := ReadKey;
  512.       case C of
  513.         ^H:                     { Backspace }
  514.           if CurPos > 0 then
  515.           begin
  516.             WritePackedString(^H' '^H, 3);
  517.             Dec(CurPos);
  518.           end;
  519.         #27:                    { Escape }
  520.           while CurPos > 0 do
  521.           begin
  522.             WritePackedString(^H' '^H, 3);
  523.             Dec(CurPos);
  524.           end;
  525.         ' '..#255:
  526.           if CurPos < BufSize - 2 then
  527.           begin
  528.             BufPtr^[CurPos] := C;
  529.             Inc(CurPos);
  530.             WritePackedString(@C,1);
  531.           end;
  532.       end; { case }
  533.     until (C = ^M) or (CheckEOF and (C = ^Z));
  534.     BufPtr^[CurPos] := C;
  535.     Inc(CurPos);
  536.     if C = ^M then              { Carriage Return }
  537.     begin
  538.       BufPtr^[CurPos] := ^J;    { Line Feed }
  539.       Inc(CurPos);
  540.       WritePackedString(^M^J,2);
  541.     end;
  542.     BufPos := 0;
  543.     BufEnd := CurPos;
  544.   end;
  545.   CrtRead := 0;                 { I/O result = 0: success }
  546. end;
  547.  
  548. function CrtWrite(var F: Text): Longint;
  549. begin
  550.   with TextRec(F) do
  551.   begin
  552.     WritePackedString(PChar(BufPtr),BufPos);
  553.     BufPos := 0;
  554.   end;
  555.   CrtWrite := 0;                { I/O result = 0: success }
  556. end;
  557.  
  558. function CrtReturn(var F: Text): Longint;
  559. begin
  560.   CrtReturn := 0;               { I/O result = 0: success }
  561. end;
  562.  
  563. function CrtOpen(var F: Text): Longint;
  564. begin
  565.   with TextRec(F) do
  566.   begin
  567.     CloseFunc := @CrtReturn;
  568.     if Mode = fmInput then
  569.     begin
  570.       InOutFunc := @CrtRead;
  571.       FlushFunc := @CrtReturn;
  572.     end
  573.    else
  574.     begin
  575.       Mode := fmOutput;
  576.       InOutFunc := @CrtWrite;
  577.       FlushFunc := @CrtWrite;
  578.     end;
  579.   end;
  580.   CrtOpen := 0;                 { I/O result = 0: success }
  581. end;
  582.  
  583. { Associates a text file with CRT device.                               }
  584.  
  585. procedure AssignCrt(var F: Text);
  586. begin
  587.   with TextRec(F) do
  588.   begin
  589.     Handle := $FFFFFFFF;
  590.     Mode := fmClosed;
  591.     BufSize := SizeOf(Buffer);
  592.     BufPtr := @Buffer;
  593.     OpenFunc := @CrtOpen;
  594.     Name[0] := #0;
  595.   end;
  596. end;
  597.  
  598. { Signal Handler }
  599.  
  600. function CtrlBreakHandler(Report:       PExceptionReportRecord;
  601.                           Registration: PExceptionRegistrationRecord;
  602.                           Context:      PContextRecord;
  603.                           P:            Pointer): ULong; cdecl;
  604. begin
  605.   if not CheckBreak and (Report^.ExceptionNum = xcpt_Signal)
  606.     then CtrlBreakHandler := xcpt_Continue_Execution
  607.     else CtrlBreakHandler := xcpt_Continue_Search;
  608. end;
  609.  
  610. begin
  611.   GetLastMode;
  612.   if (VioMode.fbType and vgmt_Graphics) <> 0 then TextMode(CO80);
  613.   ReadNormAttr;
  614.   SetWindowPos;
  615.   AssignCrt(Input);  Reset(Input);
  616.   AssignCrt(Output); ReWrite(Output);
  617.   CalcDelayCount;
  618.   SetExceptionHandler(@CtrlBreakHandler);
  619. end.
  620.