home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
ddjmag
/
ddj8903.arc
/
DUNTEMAN.LST
< prev
next >
Wrap
File List
|
1989-02-10
|
20KB
|
613 lines
_STRUCTURED PROGRAMMING COLUMN_
by Jeff Duntemann
[LISTING ONE]
{--------------------------------------------------------------}
{ TextInfo }
{ }
{ Text video information library }
{ }
{ by Jeff Duntemann }
{ Turbo Pascal V5.0 }
{ Last update 11/20/88 }
{--------------------------------------------------------------}
UNIT TextInfo;
INTERFACE
USES DOS;
TYPE
AdapterType = (None,MDA,CGA,EGAMono,EGAColor,VGAMono,
VGAColor,MCGAMono,MCGAColor);
FontSize = (Font8,Font14,Font16);
{ The following type definition *requires* Turbo Pascal 5.0! }
OverrideProc = PROCEDURE(VAR ForceX : Byte; VAR ForceY : Byte);
VAR
TextBufferOrigin : Pointer;
TextBufferSize : Word;
VisibleX,VisibleY : Byte;
FUNCTION GetBIOSTextMode : Byte; { Returns BIOS text mode }
FUNCTION GetFontSize : FontSize; { Returns font height code }
FUNCTION GetTextBufferOrigin : Pointer; { Returns pointer to text buffer }
{ Returns visible X and Y extent plus buffer size in bytes: }
PROCEDURE GetTextBufferStats(VAR BX : Byte;
VAR BY : Byte;
VAR BuffSize : Word;
CheckForOverride : OverrideProc);
PROCEDURE NullOverride(VAR ForceX : Byte; VAR ForceY : Byte);
FUNCTION QueryAdapterType : AdapterType; { Returns installed display }
FUNCTION FontCode(Height : Byte) : FontSize; { Returns font height code }
FUNCTION FontHeight(Code : FontSize) : Byte; { Returns font height value}
IMPLEMENTATION
FUNCTION GetBIOSTextMode : Byte;
VAR
Regs : Registers; { Type Registers is exported by the DOS unit }
BEGIN
Regs.AH := $0F; { BIOS VIDEO Service $F: Get Current Video Mode }
Intr($10,Regs);
GetBIOSTextMode := Regs.AL; { Mode is returned in AL }
END;
FUNCTION QueryAdapterType : AdapterType;
VAR
Regs : Registers; { Type Registers is exported by the DOS unit }
Code : Byte;
BEGIN
Regs.AH := $1A; { Attempt to call VGA Identify Adapter Function }
Regs.AL := $00; { Must clear AL to 0 ... }
Intr($10,Regs);
IF Regs.AL = $1A THEN { ...so that if $1A comes back in AL... }
BEGIN { ...we know a PS/2 video BIOS is out there. }
CASE Regs.BL OF { Code comes back in BL }
$00 : QueryAdapterType := None;
$01 : QueryAdapterType := MDA;
$02 : QueryAdapterType := CGA;
$04 : QueryAdapterType := EGAColor;
$05 : QueryAdapterType := EGAMono;
$07 : QueryAdapterType := VGAMono;
$08 : QueryAdapterType := VGAColor;
$0A,$0C : QueryAdapterType := MCGAColor;
$0B : QueryAdapterType := MCGAMono;
ELSE QueryAdapterType := CGA
END { CASE }
END
ELSE
{ If it's not PS/2 we have to check for the presence of an EGA BIOS: }
BEGIN
Regs.AH := $12; { Select Alternate Function service }
Regs.BX := $10; { BL=$10 means return EGA information }
Intr($10,Regs); { Call BIOS VIDEO }
IF Regs.BX <> $10 THEN { BX unchanged means EGA is NOT there...}
BEGIN
Regs.AH := $12; { Once we know Alt Function exists... }
Regs.BL := $10; { ...we call it again to see if it's... }
Intr($10,Regs); { ...EGA color or EGA monochrome. }
IF (Regs.BH = 0) THEN QueryAdapterType := EGAColor
ELSE QueryAdapterType := EGAMono
END
ELSE { Now we know we have an CGA or MDA; let's see which: }
BEGIN
Intr($11,Regs); { Equipment determination service }
Code := (Regs.AL AND $30) SHR 4;
CASE Code of
1 : QueryAdapterType := CGA;
2 : QueryAdapterType := CGA;
3 : QueryAdapterType := MDA
ELSE QueryAdapterType := None
END { Case }
END
END;
END;
{ All we're doing here is converting numeric font heights }
{ to their corresponding values of type FontSize. }
FUNCTION FontCode(Height : Byte) : FontSize;
BEGIN
CASE Height OF
8 : FontCode := Font8;
14 : FontCode := Font14;
16 : FontCode := Font16;
END { CASE }
END;
{ Likewise, this function converts values of type FontSize }
{ to their corresponding numeriuc values. }
FUNCTION FontHeight(Code : FontSize) : Byte;
BEGIN
CASE Code OF
Font8 : FontHeight := 8;
Font14 : FontHeight := 14;
Font16 : FontHeight := 16;
END { CASE }
END;
FUNCTION GetFontSize : FontSize;
VAR
Regs : Registers; { Type Registers is exported by the DOS unit }
BEGIN
CASE QueryAdapterType OF
CGA : GetFontSize := Font8;
MDA : GetFontSize := Font14;
MCGAMono,
MCGAColor : GetFontSize := Font16; { Wretched thing knows but 1 font! }
EGAMono, { These adapters may be using any of several different }
EGAColor, { font cell heights, so we need to query the BIOS to }
VGAMono, { find out which is currently in use. }
VGAColor : BEGIN
WITH Regs DO
BEGIN
AH := $11; { EGA/VGA Information Call }
AL := $30;
BH := 0;
END;
Intr($10,Regs); { On return, CX contains the font height }
GetFontSize := FontCode(Regs.CX);
END
END { CASE }
END;
FUNCTION GetTextBufferOrigin : Pointer;
{ The rule is: For boards attached to monochrome monitors, the buffer }
{ origin is $B000:0; for boards attached to color monitors (including }
{ all composite monitors and TV's) the buffer origin is $B800:0. }
BEGIN
CASE QueryAdapterType OF
CGA,MCGAColor,EGAColor,VGAColor : GetTextBufferOrigin := Ptr($B800,0);
MDA,MCGAMono, EGAMono, VGAMono : GetTextBufferOrigin := Ptr($B000,0);
END { CASE }
END;
{ This proc provides initial values for the dimensions of the visible }
{ display and (hence) the size of the visible refresh buffer. It is }
{ called by the initialization section during startup *BUT* you must }
{ call it again after any mode change or font change to be sure of }
{ having accurate values in the three variables! }
PROCEDURE GetTextBufferStats(VAR BX : Byte; { Visible X dimension }
VAR BY : Byte; { Visible Y dimension }
VAR BuffSize : Word; { Refresh buffer size }
{ This requires TP5.0! } CheckForOverride : OverrideProc);
CONST
ScreenLinesMatrix : ARRAY[AdapterType,FontSize] OF Integer =
{ Font8: Font14: Font16: }
{ None: } ((25, 25, 25),
{ MDA: } (-1, 25, -1),
{ CGA: } (25, -1, -1),
{ EGAMono: } (43, 25, -1),
{ EGAColor: } (43, 25, -1),
{ VGAMono: } (50, 28, 25),
{ VGAColor: } (50, 28, 25),
{ MCGAMono: } (-1, -1, 25),
{ MCGAColor: } (-1, -1, 25));
VAR
Regs : Registers; { Type Registers is exported by the DOS unit }
BEGIN
Regs.AH := $0F; { BIOS VIDEO Service $F: Get Current Video Mode }
Intr($10,Regs);
BX := Regs.AH; { Number of characters in a line returned in AH }
BY := ScreenLinesMatrix[QueryAdapterType,GetFontSize];
IF BY > 0 THEN
BEGIN
CheckForOverride(BX,BY); { See if something weird is on the bus... }
BuffSize := (BX * 2) * BY { Calculate the buffer size in bytes }
END
ELSE BuffSize := 0;
END;
{ This is the default override proc, and is called anytime you're }
{ not concerned about finding a nonstandard text adapter on the }
{ bus. (Funny graphics cards with normal text modes don't matter }
{ to this library.) If you want to capture any weird cards, you }
{ must provide your own override proc that can detect the card }
{ and return correct values for the visible X and Y dimensions. }
PROCEDURE NullOverride(VAR ForceX : Byte; VAR ForceY : Byte);
BEGIN
{ Like I said; Null... }
END;
{ The initialization section provides some initial values for the }
{ exported variables TextBufferOrigin, VisibleX, VisibleY, and }
{ TextBufferSize, so that you can use the variables without further }
{ kafeuthering. }
BEGIN
TextBufferOrigin := GetTextBufferOrigin;
GetTextBufferStats(VisibleX,VisibleY,TextBufferSize,NullOverride);
END.
[LISTING TWO]
PROGRAM TextTest;
USES TextInfo;
BEGIN
Write('The installed adapter is ');
CASE QueryAdapterType OF
None : Writeln('nothing I''ve ever seen.');
MDA : Writeln('an MDA .');
CGA : Writeln('a CGA.');
EGAMono,EGAColor : Writeln('an EGA.');
VGAMono,VGAColor : Writeln('a VGA.');
MCGAMono,MCGAColor : Writeln('an MCGA.');
END; { CASE }
Writeln('The current font height is ',FontHeight(GetFontSize),'.');
Writeln('The current BIOS text mode is ',GetBIOSTextMode,'.');
Writeln('The current screen is ',VisibleX,' character wide',
' and ',VisibleY,' characters wide;');
Writeln(' and occupies ',TextBufferSize,' bytes in memory.');
END.
[LISTING THREE]
(*--------------------------------------------------------------*)
(* TEXTINFO *)
(* *)
(* Text video information library -- Definition module *)
(* *)
(* by Jeff Duntemann *)
(* TopSpeed Modula 2 V1.12 *)
(* Last update 12/7/88 *)
(*--------------------------------------------------------------*)
DEFINITION MODULE TextInfo;
TYPE
AdapterType = (None,MDA,CGA,EGAMono,EGAColor,VGAMono,
VGAColor,MCGAMono,MCGAColor);
FontSize = (Font8,Font14,Font16);
OverrideProc = PROCEDURE(VAR BYTE,VAR BYTE);
VAR
TextBufferOrigin : ADDRESS; (* Address of video refresh buffer *)
TextBufferSize : CARDINAL; (* Bytes contained in refresh buffer *)
VisibleX,VisibleY : SHORTCARD; (* Dimensions of the visible display *)
PROCEDURE GetBIOSTextMode() : SHORTCARD;
PROCEDURE GetTextBufferOrigin() : ADDRESS;
PROCEDURE GetTextBufferStats(VAR BufX : BYTE; (* Visible X dimension *)
VAR BufY : BYTE; (* Visible Y dimension *)
VAR BuffSize : CARDINAL; (* Refresh buffer size *)
CheckForOverride : OverrideProc);
PROCEDURE QueryAdapterType() : AdapterType;
PROCEDURE FontCode(Height : SHORTCARD) : FontSize;
PROCEDURE FontHeight(Code : FontSize) : SHORTCARD;
PROCEDURE GetFontSize() : FontSize;
PROCEDURE NullOverride(VAR ForceX : BYTE; VAR ForceY : BYTE);
END TextInfo.
[LISTING FOUR]
(*--------------------------------------------------------------*)
(* TEXTINFO *)
(* *)
(* Text video information library -- Implementation module *)
(* *)
(* by Jeff Duntemann *)
(* TopSpeed Modula 2 V1.12 *)
(* Last update 12/7/88 *)
(*--------------------------------------------------------------*)
IMPLEMENTATION MODULE TextInfo;
FROM SYSTEM IMPORT Registers;
FROM Lib IMPORT Intr;
VAR
ColorBufOrg [0B800H:0] : WORD; (* First word in color refresh buffer *)
MonoBufOrg [0B000H:0] : WORD; (* First word in mono refresh buffer *)
PROCEDURE GetBIOSTextMode() : SHORTCARD;
VAR
Regs : Registers;
BEGIN
Regs.AH := 0FH; (* VIDEO service 0FH *)
Intr(Regs,10H);
RETURN Regs.AL (* AL contains current text mode on return *)
END GetBIOSTextMode;
PROCEDURE QueryAdapterType() : AdapterType;
VAR
Regs : Registers;
Code : SHORTCARD;
BEGIN
Regs.AH := 1AH; (* Attempt to call VGA Identify Adapter Function *)
Regs.AL := 0; (* Must clear AL to 0 ... *)
Intr(Regs,10H);
IF Regs.AL = 1AH THEN (* ...so that if $1A comes back in AL... *)
(* ...we know a PS/2 video BIOS is out there. *)
CASE Regs.BL OF (* Code comes back in BL *)
0 : RETURN None |
1 : RETURN MDA; |
2 : RETURN CGA; |
4 : RETURN EGAColor; |
5 : RETURN EGAMono; |
7 : RETURN VGAMono; |
8 : RETURN VGAColor; |
0AH,0CH : RETURN MCGAColor; |
0BH : RETURN MCGAMono; |
ELSE RETURN CGA
END (* CASE *)
ELSE
(* If it's not PS/2 we have to check for the presence of an EGA BIOS: *)
Regs.AH := 12H; (* Select Alternate Function service *)
Regs.BX := 10H; (* BL=$10 means return EGA information *)
Intr(Regs,10H); (* Call BIOS VIDEO *)
IF Regs.BX <> 10H THEN (* BX unchanged means EGA is NOT there...*)
Regs.AH := 12H; (* Once we know Alt Function exists... *)
Regs.BL := 10H; (* ...we call it again to see if it's... *)
Intr(Regs,10H); (* ...EGA color or EGA monochrome. *)
IF (Regs.BH = 0) THEN RETURN EGAColor
ELSE RETURN EGAMono
END
ELSE (* Now we know we have an CGA or MDA; let's see which: *)
Intr(Regs,11H); (* Equipment determination service *)
Code := SHORTCARD(BITSET(Regs.AL) * BITSET{4..5}) >> 4;
CASE Code OF
1 : RETURN CGA |
2 : RETURN CGA |
3 : RETURN MDA
ELSE RETURN None
END (* Case *)
END
END
END QueryAdapterType;
(* This is a simple "clean conversion" function for relating the *)
(* enumerated font size constants to SHORTCARD numeric font size *)
(* values. *)
PROCEDURE FontCode(Height : SHORTCARD) : FontSize;
BEGIN
CASE Height OF
8 : RETURN Font8 |
14 : RETURN Font14 |
16 : RETURN Font16
ELSE RETURN Font8
END (* CASE *)
END FontCode;
(* This is a simple "clean conversion" function for relating the *)
(* SHORTCARD numeric font size values to the enumerated font size *)
(* constants *)
PROCEDURE FontHeight(Code : FontSize) : SHORTCARD;
BEGIN
CASE Code OF
Font8 : RETURN 8 |
Font14 : RETURN 14 |
Font16 : RETURN 16
END (* CASE *)
END FontHeight;
PROCEDURE GetFontSize() : FontSize;
VAR
Regs : Registers;
BEGIN
CASE QueryAdapterType() OF
CGA : RETURN Font8 |
MDA : RETURN Font14 |
MCGAMono,
MCGAColor : RETURN Font16 |
EGAMono, (* These adapters may be using any of several *)
EGAColor, (* different font cell heights, so we need to query *)
VGAMono, (* BIOS to find out which is currently in use. *)
VGAColor : WITH Regs DO
AH := 11H; (* EGA/VGA Information Call *)
AL := 30H;
BL := 0;
END;
Intr(Regs,10H);
RETURN FontCode(SHORTCARD(Regs.CX))
END (* CASE *)
END GetFontSize;
PROCEDURE GetTextBufferOrigin() : ADDRESS;
(* The rule is: For boards attached to monochrome monitors, the buffer *)
(* origin is $B000:0; for boards attached to color monitors (including *)
(* all composite monitors and TV's) the buffer origin is $B800:0. *)
BEGIN
CASE QueryAdapterType() OF
CGA,MCGAColor,EGAColor,VGAColor : RETURN ADR(ColorBufOrg) |
MDA,MCGAMono, EGAMono, VGAMono : RETURN ADR(MonoBufOrg)
END (* CASE *)
END GetTextBufferOrigin;
(* This one function returns essential screen/buffer size information. *)
(* It is called by the initializing body of this module but should be *)
(* called again after *any* mode change or font change! *)
PROCEDURE GetTextBufferStats(VAR BufX : BYTE; (* Visible X dimension *)
VAR BufY : BYTE; (* Visible Y dimension *)
VAR BuffSize : CARDINAL; (* Refresh buffer size *)
CheckForOverride : OverrideProc);
TYPE
FontPoints = ARRAY[Font8..Font16] OF INTEGER;
PointsArray = ARRAY[None..MCGAColor] OF FontPoints;
VAR
Regs : Registers; (* Type Registers is exported by the DOS unit *)
ScreenLinesMatrix : PointsArray;
Adapter : AdapterType;
Font : FontSize;
(* TopSpeed can't do two-dimensional array aggregates, Turbo Pascal *)
(* style (arrgh) so we have to make it an array of arrays: *)
BEGIN
ScreenLinesMatrix := PointsArray(
(* None: *) FontPoints(25, 25, 25),
(* MDA: *) FontPoints(-1, 25, -1),
(* CGA: *) FontPoints(25, -1, -1),
(* EGAMono: *) FontPoints(43, 25, -1),
(* EGAColor: *) FontPoints(43, 25, -1),
(* VGAMono: *) FontPoints(50, 28, 25),
(* VGAColor: *) FontPoints(50, 28, 25),
(* MCGAMono: *) FontPoints(-1, -1, 25),
(* MCGAColor: *) FontPoints(-1, -1, 25));
Regs.AH := 0FH; (* BIOS VIDEO Service $F: Get Current Video Mode *)
Intr(Regs,10H);
BufX := Regs.AH; (* Number of characters in a line returned in AH *)
BufY := SHORTCARD(ScreenLinesMatrix[QueryAdapterType(),GetFontSize()]);
IF SHORTCARD(BufY) > 0 THEN
CheckForOverride(BufX,BufY); (* See if odd adapter is on the bus... *)
(* Calculate the buffer size in bytes: *)
BuffSize := (CARDINAL(BufX) * 2) * CARDINAL(BufY)
ELSE BuffSize := 0
END
END GetTextBufferStats;
(* This is the "default" override proc, called when there is no *)
(* suspicion of anything nonstandard on the bus. Replace with *)
(* a custom proc that looks for any nonstandard video adapter. *)
PROCEDURE NullOverride(VAR ForceX : BYTE; VAR ForceY : BYTE);
BEGIN
(* Like I said; Null... *)
END NullOverride;
(* The module body, like a Pascal unit initialization section, is *)
(* executed before the client program that imports this module or *)
(* any part of it. *)
BEGIN
TextBufferOrigin := GetTextBufferOrigin();
GetTextBufferStats(VisibleX,VisibleY,TextBufferSize,NullOverride);
END TextInfo.
[LISTING FIVE]
MODULE TextTest;
FROM IO IMPORT WrStr,WrLn,WrCard,WrShtCard;
FROM TextInfo IMPORT AdapterType,QueryAdapterType,GetFontSize,
FontHeight,GetBIOSTextMode,VisibleX,VisibleY,
TextBufferSize;
BEGIN
WrStr("The installed adapter is ");
CASE QueryAdapterType() OF
None : WrStr("nothing I've ever seen.") |
MDA : WrStr("an MDA.") |
CGA : WrStr("a CGA.") |
EGAMono,EGAColor : WrStr("an EGA.") |
VGAMono,VGAColor : WrStr("a VGA.") |
MCGAMono,MCGAColor : WrStr("an MCGA.");
END; (* CASE *)
WrLn;
WrStr('The current font height is ');
WrShtCard(FontHeight(GetFontSize()),2);
WrStr("."); WrLn;
WrStr("The current BIOS text mode is ");
WrShtCard(GetBIOSTextMode(),2);
WrStr("."); WrLn;
(* VisibleX and VisibleY are initialized by TextInfo module body *)
WrStr("The current screen is ");
WrShtCard(VisibleX,2);
WrStr(" character wide and ");
WrShtCard(VisibleY,2);
WrStr(" characters high;");
WrLn;
WrStr(" and occupies ");
(* TextBufferSize is initialized by TextInfo module body *)
WrCard(TextBufferSize,6);
WrStr(" bytes in memory."); WrLn;
END TextTest.