home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 8 Other
/
08-Other.zip
/
setlines.zip
/
setlines.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-01-11
|
34KB
|
634 lines
/************************************************************************
* *
* setlines: use BIOS video interrupts to set colour text mode 3 on *
* VGA with 12, 14, 21, 25, 30, 34, 28, 43, 50, 60 lines: *
* *
* ROM font 8 x 8, 14, 16 - Some old VGA support only 50, 28, 25 lines *
* scanlines ------------ - Some old ATI report mode 5Bh for 30 x 80 *
* 200 | (25) 14 12 - Some old ATI report mode 23h for 25 x 132 *
* 350 | 43 (25) 21 - Some old ATI don't support VESA 108h, 10Ch *
* 400 | 50 28 25 - Some old VGA don't support VESA text modes *
* 480 | 60 34 30 - ANSI.SYS confused by NNx132, use VANSI.SYS *
* - Setlines -1 requires VESA power management *
* - Setlines +1 is a 2nd special case: 25 x 40 *
* - With 60 x 132 there is only ONE video page *
* Revision history: *
* 1.0 Support 12, 14, 21, 25, 28, 43, and 50 lines (EGA: 25, 43). *
* 1.1 Toggle screen height (25x80 and 28x80) as default, *
* replaced stdio.h fprintf() by smaller conio.h cputs(). *
* 1.2 Replaced int86x() by Watcom's smaller intr(). *
* 1.3 Support 30, 34, 60 lines based on 480 scan lines, uses the *
* standard VGA function INT 10 AX 1C02 "restore video state". *
* 2.0 Support 132 columns, specified as -21, -25, ..., -50, -60: *
* based on VESA modes 109, 10A, 10C. Use VESA mode 108 for *
* 60x80 if available. But my ATI Mach32 is a bit stupid :-) *
* 2.1 Toggle screen width (NNx80 and NNx132) as default. *
* 2.2 Save current screen contents if width is the same, does not *
* work as expected with PC DOS 7 ANSI.SYS, but VANSI.SYS or *
* no ANSI-driver are okay, and then even DOS accepts 60x132. *
* 2.3 Patch BIOS data for get video mode result 3 instead of 83h, *
* this prevents NC.EXE from clearing the saved screen because *
* it did not understand the "keep video memory" bit 7 in 83h. *
* 2.4 Special argument: setlines -1 to switch VESA display power *
* OFF, awaits any key pressed before exit switching power ON. *
* 2.5 setlines 0 or setlines ? usage() return code == getlines(). *
* setlines 1 supports 25x40 text mode 1 as 2nd special case. *
* 2.6 Switch screen off during setlines() setting and scrolling. *
* Save current screen contents even if screen width changed. *
* 3.0 Support ATI Rage Pro (missing VESA text modes replaced by *
* proprietary ATI modes 23 and 33 #ifdef ATI). *
* *
* 1998, 2002 by Frank Ellermann *
* *
************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <conio.h>
#include <dos.h>
#define BYTE unsigned char
#define WORD unsigned short
#define VIDEO 0x10
#define KEYB 0x16
#define IDLE 0x28
#define DOS 0x21
#define DOS_FREEMEM 0x49 /* _dos_freemem() w/out WATCOM overhead */
#define PSP_ENV_SEG 0x2C /* environment segment in our PSP */
#ifdef __WATCOMC__
#define SEG( nptr ) FP_SEG( nptr )
#define OFS( nptr ) FP_OFF( nptr )
#else
#define SEG( nptr ) ((_segment)(void _far *)( nptr ))
#define OFS( nptr ) ((WORD)(long)(void _far *)( nptr ))
#define INTR_CF 0x0001 /* carry flag compatible with WATCOM C */
#define INTR_ZF 0x0040 /* zero flag compatible with WATCOM C */
union REGPACK /* for WATCOM compatible intr( int, union REGPACK *r ): */
{ struct /* access on byte registers */
{ BYTE al, ah, bl, bh, cl, ch, dl, dh;
} h;
struct /* access on word registers and flags */
{ WORD ax, bx, cx, dx;
WORD bp, si, di, ds, es;
unsigned flags;
} x;
};
#endif
#ifndef MK_FP
#define MK_FP( s, o ) (((_segment)(s)):>((void _based(void) *)(o)))
#endif
static union REGPACK os_regs; /* register work area for intr */
/* -------------------------------------------------------------------- */
/* MS C 6.0 int86x() is buggy: carry not cleared for interrupt < 0x25. */
/* MS C 6.0 has no intr(), which is much easier to use than int86x(): */
#ifndef __WATCOMC__ /* WATCOM C 10.0 has intr() */
#pragma optimize( "leg", off ) /* optimize does not like _asm */
void _cdecl intr( int num, union REGPACK *R )
{ _asm
{ push bp ;MS C 6 saves DI, SI
push ds ;(please check this!)
pushf ;save interrupt state
cli ;disable interrupts
mov al, byte ptr num
mov cs:byte ptr X+1, al
#if defined( M_I86SM ) || defined( M_I86MM )
mov bx, R ;DS:BX == *R
#else
lds bx, R ;DS:BX == *R
#endif
push ds
push bx
mov ax, [bx]R.x.ax
mov cx, [bx]R.x.cx
mov dx, [bx]R.x.dx
mov bp, [bx]R.x.bp ;sets wanted BP
mov si, [bx]R.x.si
mov di, [bx]R.x.di
mov es, [bx]R.x.es ;sets wanted ES
push [bx]R.x.bx ;save wanted BX
mov ds, [bx]R.x.ds ;sets wanted DS
pop bx ;sets wanted BX
X: int 0 ;user interrupt
push ds ;save result DS
push bx ;save result BX
pushf ;save result flags
mov bx, sp
lds bx, ss:[bx+6] ;DS:BX == *R
pop [bx]R.x.flags ;sets result flags
pop [bx]R.x.bx ;sets result BX
pop [bx]R.x.ds ;sets result DS
pop bx
pop ds ;DS:BX == *R
mov [bx]R.x.es, es ;sets result ES
mov [bx]R.x.di, di
mov [bx]R.x.si, si
mov [bx]R.x.bp, bp ;sets result BP
mov [bx]R.x.dx, dx
mov [bx]R.x.cx, cx
mov [bx]R.x.ax, ax
popf ;reset interrupt state
pop ds ;reset DS, BP for leave
pop bp ;compiler resets SI, DI
} }
#pragma optimize( "", on ) /* restore user's optimization */
#endif
/*----------------------------------------------------------------------*/
static void intr_video_on_os_regs( void )
{ intr( VIDEO, &os_regs ); /* shorthand (saving 168 bytes) */
}
/*----------------------------------------------------------------------*/
/* basically equivalent to _bios_keybrd(), shows use of os_regs.x.flags */
static WORD intr_keyb( BYTE function )
{ os_regs.h.ah = function; intr( KEYB, &os_regs );
if (( function & 0xEF ) == 1 && ( os_regs.x.flags & INTR_ZF ))
return 0; /* 0x01 or 0x11 invalid if NZ */
else return os_regs.x.ax; /* else return valid result AX */
}
/*----------------------------------------------------------------------*/
/* if setlines -1 (display power off) worked, then this system supports */
/* the enhanced keyboard functions 10h, 11h, and 12h (new XT or better) */
static void idle( void )
{ WORD shift; /* pressed key can be shift key */
for ( shift = intr_keyb( 0x12 ); /* initial shift status */
shift == intr_keyb( 0x12 ); /* compare shift status */
intr( IDLE, &os_regs )) /* time slice for TSRs */
{ if ( intr_keyb( 0x11 )) /* if key pressed "eat" */
{ intr_keyb( 0x10 ); return; /* key and exit */
} } }
/*----------------------------------------------------------------------*/
/* vgapatch() handles 2 cases using function 1Ch save/restore VGA state */
/* - VGA supports 480 scan lines, but function 12h BL 30h is limited to */
/* 400 scan lines. If VESA text modes 108h and 10Ch are unavailable, */
/* then vgapatch( 0 ) "restores" 480 scan lines (for mode 3 or 109h). */
/* - VGA function 0Fh returns a video mode with "keep RAM" bit 7, which */
/* confuses some applications. Therefore vgapatch( N ) clears bit 7 */
/* in BIOS data byte 40:87. N is the number of rows, i.e. lines - 1. */
static void vgapatch( BYTE rows )
{ static BYTE * state;
os_regs.x.ax = 0x1C00; /* video 1C00h: VGA state size */
os_regs.x.cx = (WORD)( rows ? 2 : 1 );
intr_video_on_os_regs(); /* CX 1: hardware, 2: BIOS etc. */
if ( os_regs.h.al != 0x1C /* video 1Ch not supported (?) */
|| 0 == ( state = malloc( 64 * os_regs.x.bx ))) return;
os_regs.x.ax = 0x1C01; /* video 1C01: save VGA state */
os_regs.x.es = SEG( state ); /* ES:BX whatever state buffer */
os_regs.x.bx = OFS( state ); intr_video_on_os_regs();
switch ( rows ) /* 0 hardware, else BIOS state: */
{ case 0: if ( state[ 0x20 + 0x40 ] != 0xD4 /* CRTC */
|| state[ 0x20 + 0x41 ] != 0x03 ) /* base */
break; /* ignore unknown buffer layout */
state[ 0x20 + 0x09 ] |= 0xC0;
/* 3CC misc. output: enable 480 */
state[ 0x20 + 0x10 ] = 0x0D;
/* CRTC 06h vertical total 20Dh */
state[ 0x20 + 0x11 ] = 0x3E;
/* CRTC 07h overflow register */
state[ 0x20 + 0x1A ] = 0xEA;
/* CRTC 10h start retrace 1EAh */
state[ 0x20 + 0x1B ] = 0x8C;
/* CRTC 11h vert. retrace end */
state[ 0x20 + 0x1C ] = 0xDF;
/* CRTC 12h end display 1DFh */
state[ 0x20 + 0x1F ] = 0xE7;
/* CRTC 15h start blanking 1E7h */
state[ 0x20 + 0x20 ] = 0x06;
/* CRTC 16h end blanking */
break;
default: /* use rows to determine layout */
if ( state[ 0x20 + 0x1E ] == rows /* 40:84 */
&& ( state[ 0x3E + 3 ] & 0x80 )) /* 40:87 */
{ state[ 0x3E + 3 ] ^= 0x80; /* bit 7 */
break; /* Phoenix AT video BIOS layout */
} /* as documented in tech. ref. */
if ( state[ 0x20 + 0x1F ] == rows /* 40:84 */
&& ( state[ 0x3F + 3 ] & 0x80 )) /* 40:87 */
{ state[ 0x3F + 3 ] ^= 0x80; /* bit 7 */
break; /* ATI layout (Phoenix +1 byte) */
} /* found in PCI onboard Mach32 */
if ( state[ 0x20 + 0x3B ] == rows /* 40:84 */
&& ( state[ 0x5B + 3 ] & 0x80 )) /* 40:87 */
{ state[ 0x5B + 3 ] ^= 0x80; /* bit 7 */
break; /* simple copy started at 40:49 */
} } /* as documented by Ralph Brown */
os_regs.x.ax = 0x1C02; /* video 1C02: restore state */
intr_video_on_os_regs(); free( state ); /* just in case */
}
/*----------------------------------------------------------------------*/
/* All VGA support 480 scan lines, but have no BIOS function to set it, */
/* so either VESA modes 108h, 10Ch, or vgapatch( 0 ) enforce 480 lines. */
/* VESA 108h is 60x80, 109h is 25x132, 10Ah is 43x132, 10Bh is 50x132, */
/* 10Ch is 60x132. VESA 108h is the same as vgapatch( 0 ) mode 3, and */
/* VESA 10Ch is the same as vgapatch( 0 ) VESA 109h. ATI Mach32 does */
/* not support 108h, 10Bh, or 10Ch directly, so these modes have to be */
/* derived from supported modes (this could be extended if necessary): */
/* 108h 60x 80: set mode 3, vgapatch( 0 ) 480 scan lines, load 8x8 font */
/* 10Bh 50x132: set mode 109h 25x132 (uses 8x16 font) and load 8x8 font */
/* 10Ch 60x132: set mode 109h, force 480 scan lines, then load 8x8 font */
static void vesa( WORD mode )
{ os_regs.x.ax = 0x4F02; /* VESA 02: set VBE mode in BX */
os_regs.x.bx = 0x8000 | mode; /* bit 15: keep video buffer */
intr_video_on_os_regs(); /* result AH == 00h successful */
if ( os_regs.x.ax != 0x004F ) /* result AL == 4Fh supported */
{ if ( mode == 0x108 ) vgapatch( 0 ); /* "resets" 480 */
if ( mode == 0x10C )
{ vesa( 0x109 ); vgapatch( 0 ); /* patch 25x132 */
} } }
/*----------------------------------------------------------------------*/
/* Setting 200 (CGA), 350 (EGA), or 400 (VGA) scan lines works only if */
/* followed by a mode set. Here we set mode 0x83 preserving the video */
/* memory (otherwise identical to mode 3). Later vgapatch( N ) cheats */
/* silly programs not recognizing mode 0x83 by "restoring" text mode 3. */
static char scanlines( BYTE mode )
{ os_regs.h.ah = 0x12; /* video 12h alternate select: */
os_regs.h.bl = 0x30; /* BL 30h text mode scan lines */
os_regs.h.al = mode; /* AL 0: 200, 1: 350, 2: 400 */
intr_video_on_os_regs(); /* result AL == 12h supported */
mode = (BYTE)( os_regs.h.al == 0x12 );
os_regs.x.ax = 0x0083; /* set mode 3 before font 111?h */
intr_video_on_os_regs(); /* bit 7: keep old video buffer */
return (char) mode; /* 0 if no EGA/VGA, else 1 okay */
}
/*----------------------------------------------------------------------*/
/* this function works only for EGA or better, but this is implicitly */
/* checked by the initial call of scanlines( 200 ) in setlines(). */
static void loadfont( BYTE mode ) /* call only after scanlines() */
{ os_regs.x.bx = 0; /* using character font block 0 */
os_regs.h.ah = 0x11; /* AX 1111h 8x14 text mode font */
os_regs.h.al = mode; /* AX 1112h 8x8 text mode font */
intr_video_on_os_regs(); /* AX 1114h 8x16 text mode font */
}
/*----------------------------------------------------------------------*/
/* this function works only for EGA or better, but this is implicitly */
/* checked by the initial call of scanlines( 200 ) in setlines(). */
static signed char getlines( void )
{ os_regs.x.ax = 0x1130; /* get font pointer information */
os_regs.h.bh = 0; /* font 0 (dummy, any 0..7 ok.) */
intr_video_on_os_regs(); /* only EGA or VGA: DL == rows */
os_regs.h.ah = 0x0F; /* video 0Fh get mode, here use */
intr_video_on_os_regs(); /* result AH == columns 80, 132 */
if ( os_regs.h.ah == 40 ) /* I treat NNx40 as 25x40, i.e. */
return 1; /* mode 1 (a special case here) */
if ( os_regs.h.ah == 80 ) /* I treat anything else as 132 */
return (signed char)( 1 + os_regs.h.dl ); /* pos. */
else return (signed char)( -1 - os_regs.h.dl ); /* neg. */
}
/*----------------------------------------------------------------------*/
/* off == 0: switch VESA power and screen refresh ON, ignore result 0 */
/* off == 1: (don't switch power), screen refresh OFF, ignore result 1 */
/* off == -1: switch VESA power and screen refresh OFF, result 1 = done */
static char display( signed char off )
{ if ( off <= 0 ) /* 0: display power on, -1: off */
{ os_regs.x.ax = 0x4F10; /* VESA 10 BL 1 set power state */
os_regs.h.bl = 1; /* BH 4 (bit 2): off, BH 0: on */
os_regs.h.bh = (BYTE)( off ? 4 : 0 );
intr_video_on_os_regs();
off = (signed char)( off && os_regs.x.ax == 0x004F );
}
os_regs.h.ah = 0x12; /* video 12h alternate select: */
os_regs.h.bl = 0x36; /* BL 36h screen AL 0/1 on/off */
os_regs.h.al = (BYTE) off; /* 0: screen refresh on, 1: off */
intr_video_on_os_regs(); return (char) off;
}
/*----------------------------------------------------------------------*/
/* move a screen character with its attribute, used to adjust new width */
static void move_char( BYTE srow, BYTE scol, BYTE trow, BYTE tcol )
{
os_regs.h.bh = 0; /* page BH 0 */
os_regs.h.dh = srow; os_regs.h.dl = scol; /* source pos. */
os_regs.h.ah = 2; intr_video_on_os_regs();
os_regs.h.ah = 8; intr_video_on_os_regs();
os_regs.x.cx = os_regs.x.ax; /* source char. */
os_regs.h.dh = trow; os_regs.h.dl = tcol; /* target pos. */
os_regs.h.ah = 2; intr_video_on_os_regs();
os_regs.h.al = os_regs.h.cl; /* character AL */
os_regs.h.bl = os_regs.h.ch; /* attribute BL */
os_regs.x.cx = 1; /* copy 1 char. */
os_regs.h.ah = 9; intr_video_on_os_regs();
}
/*----------------------------------------------------------------------*/
/* Clear MORE (i.e. new) columns and lines. First adjust the screen to */
/* MORE columns from lower right to upper left corner of the old image: */
static void post_adjust( BYTE oldrow, BYTE oldcol, BYTE newrow,
BYTE newcol, BYTE colour, WORD cursor )
{ if ( oldcol < newcol ) /* MORE columns, adjust screen: */
{ div_t npos; /* screen source row and column */
BYTE nrow = (BYTE)( oldrow + 1 ); /* target row */
BYTE ncol = (BYTE)( oldcol + 1 ); /* target col. */
int opos = nrow * ncol; /* source off. */
for ( ; nrow-- ; ncol = (BYTE)( oldcol + 1 ))
while ( ncol-- )
{ npos = div( --opos, ( newcol + 1 ));
move_char( (BYTE)( npos.quot ),
(BYTE)( npos.rem ),
nrow, ncol );
}
os_regs.x.ax = 0x0600; /* video 0600h clear window */
os_regs.h.bh = colour; /* BH attribute for blank lines */
os_regs.h.ch = 0; /* upper left of added columns */
os_regs.h.cl = (BYTE)( oldcol + 1 );
os_regs.h.dh = newrow; /* lower line of added columns */
os_regs.h.dl = newcol; /* lower right edge of window */
intr_video_on_os_regs();
}
if ( oldrow < newrow || cursor == 0xFFFF )
{ os_regs.x.ax = 0x0600; /* video 0600h: clear window */
os_regs.h.bh = colour; /* BH attribute for blank lines */
os_regs.x.cx = 0; /* upper left CH row 0 CL col 0 */
os_regs.h.dh = newrow; /* lower right row DH new lines */
os_regs.h.dl = newcol; /* lower right col DL new lines */
if ( cursor == 0xFFFF ) /* after failures clear screen, */
cursor = 0; /* else clear lower MORE lines */
else os_regs.h.ch = (BYTE)( oldrow + 1 );
intr_video_on_os_regs();
}
os_regs.x.dx = cursor; /* cursor restore resp. home */
os_regs.h.ah = 2; /* video 02h set pos., page BH */
os_regs.h.bh = 0; intr_video_on_os_regs();
}
/*----------------------------------------------------------------------*/
/* Scroll LESS (i.e. lost) lines up. Adjust the screen to LESS columns */
/* if necessary from upper left to lower right corner of the new image: */
static WORD init_adjust( BYTE oldrow, BYTE oldcol,
BYTE newrow, BYTE newcol, BYTE colour )
{ WORD cursor; /* saved cursor position page 0 */
os_regs.h.ah = 3; /* video 03h get pos., page BH */
os_regs.h.bh = 0; intr_video_on_os_regs();
os_regs.x.ax = 0x0500; cursor = os_regs.x.dx;
intr_video_on_os_regs(); /* video 05h set page, AL == 0 */
if ( newrow < oldrow ) /* LESS lines, scroll screen up */
{ os_regs.h.ah = 0x06; /* video 06h: scroll up window */
os_regs.h.al = (BYTE)( oldrow - newrow );
os_regs.h.bh = colour; /* BH attribute for blank lines */
os_regs.x.cx = 0; /* upper left row CH 0 col CL 0 */
os_regs.h.dh = oldrow; /* lower right row DH is oldrow */
os_regs.h.dl = oldcol; /* lower right col DL is oldcol */
intr_video_on_os_regs();
os_regs.x.dx = cursor; os_regs.h.dh += newrow;
if ( oldrow <= os_regs.h.dh ) /* scroll cursor up too */
os_regs.h.dh -= oldrow;
else os_regs.x.dx = 0; /* cursor out of bounds */
cursor = os_regs.x.dx; /* note pos. for restore at end */
}
if ( newcol < oldcol ) /* LESS columns, adjust screen: */
{ BYTE nrow, ncol; /* screen source row and column */
div_t npos; /* screen target row and column */
int opos = 0; /* target offset index from 0:0 */
for ( nrow = 0; nrow <= newrow; ++nrow )
for ( ncol = 0; ncol <= newcol; ++ncol )
{ npos = div( opos++, ( oldcol + 1 ));
move_char( nrow, ncol,
(BYTE)( npos.quot ),
(BYTE)( npos.rem ));
}
os_regs.x.dx = cursor; /* adjust invalid cursor column */
if ( newcol < os_regs.h.dl ) os_regs.h.dl = newcol;
cursor = os_regs.x.dx; /* as a very simple approach... */
}
return cursor;
}
/*----------------------------------------------------------------------*/
/* If scanlines( 200 ) does not work, then it's no EGA/VGA, but as the */
/* screen is already scrolled up in the case of LESS lines, it will be */
/* cleared completely. The same is done for an invalid number of lines */
/* like 50 on EGA, -25 without VESA, or other rubbish. */
static char setlines( signed char wanted )
{ BYTE border; /* ANSI.SYS saves only palette */
BYTE colour; /* attribute for cleared areas */
WORD cursor; /* saved cursor position page 0 */
BYTE oldrow, oldcol, newrow, newcol; /* lower right position */
/* ---- special case: -1 to switch power off ------------------ */
if ( wanted == -1 ) return display( -1 );
display( 1 ); /* screen refresh temporary OFF */
/* ---- determine old and new row x col ----------------------- */
oldcol = newcol = 79; /* anything else treated as 131 */
if ((signed char)( newrow = (BYTE) wanted ) < 0 ) /* abs: */
{ newrow = (BYTE)( 0 - (signed char) newrow ); newcol = 131;
}
if ((signed char)( oldrow = (BYTE) getlines()) < 0 ) /* abs: */
{ oldrow = (BYTE)( 0 - (signed char) oldrow ); oldcol = 131;
}
if ( --newrow == 0 ) ( newrow = 24, newcol = 39 ); /* 1: 25x40 */
if ( --oldrow == 0 ) ( oldrow = 24, oldcol = 39 ); /* 1: 25x40 */
/* ---- save border colour and cursor ------------------------- */
os_regs.x.ax = 0x1008; /* 1008h read overscan register */
intr_video_on_os_regs(); border = os_regs.h.bh;
os_regs.h.bh = 0; /* mode set will force page 0 */
os_regs.h.ah = 8; /* video 08h get char, page BH */
intr_video_on_os_regs(); colour = os_regs.h.ah;
cursor = init_adjust( oldrow, oldcol, newrow, newcol, colour );
/* ---- select scan lines and font ---------------------------- */
if ( scanlines( 2 )) switch( wanted ) /* 400 VGA scan lines */
{ case 21: scanlines( 1 ); /* 350 EGA scan lines */
case 25: loadfont( 20 ); /* use 8x16 generator */
break;
case 12: scanlines( 0 ); /* 200 CGA scan lines */
loadfont( 20 ); /* use 8x16 generator */
break;
case 14: scanlines( 0 ); /* 200 CGA scan lines */
case 28: loadfont( 17 ); /* use 8x14 generator */
break;
case 43: scanlines( 1 ); /* 350 EGA scan lines */
case 50: loadfont( 18 ); /* use 8x8 generator */
break;
case 30: vesa( 0x108 ); /* 480 VGA scan lines */
loadfont( 20 ); /* use 8x16 generator */
break;
case 34: vesa( 0x108 ); /* 480 VGA scan lines */
loadfont( 17 ); /* use 8x14 generator */
break;
case 60: vesa( 0x108 ); /* 480 VGA scan lines */
loadfont( 18 ); /* use 8x8 generator */
break;
#ifdef ATI
case -21: os_regs.x.ax = 0x00B3;
intr_video_on_os_regs();
loadfont( 20 ); /* use 8x16 generator */
break;
case -25: os_regs.x.ax = 0x00A3;
intr_video_on_os_regs();
loadfont( 20 ); /* use 8x16 generator */
break;
case -28: os_regs.x.ax = 0x00A3;
intr_video_on_os_regs();
loadfont( 17 ); /* use 8x14 generator */
break;
case -30: os_regs.x.ax = 0x00A3;
intr_video_on_os_regs(); vgapatch( 0 );
loadfont( 20 ); /* use 8x16 generator */
break;
case -34: os_regs.x.ax = 0x00A3;
intr_video_on_os_regs(); vgapatch( 0 );
loadfont( 17 ); /* use 8x14 generator */
break;
case -43: os_regs.x.ax = 0x00B3;
intr_video_on_os_regs();
loadfont( 18 ); /* use 8x8 generator */
break;
case -50: os_regs.x.ax = 0x00A3;
intr_video_on_os_regs();
loadfont( 18 ); /* use 8x8 generator */
break;
case -60: os_regs.x.ax = 0x00A3;
intr_video_on_os_regs(); vgapatch( 0 );
loadfont( 18 ); /* use 8x8 generator */
break; /* only ONE video page */
#else
case -21: vesa( 0x10A ); /* VESA 10A, 43 x 132 */
loadfont( 20 ); /* use 8x16 generator */
break;
case -25: vesa( 0x109 ); /* VESA 109, 25 x 132 */
loadfont( 20 ); /* use 8x16 generator */
break;
case -28: vesa( 0x109 ); /* VESA 109, 25 x 132 */
loadfont( 17 ); /* use 8x14 generator */
break;
case -30: vesa( 0x10C ); /* VESA 10C, 60 x 132 */
loadfont( 20 ); /* use 8x16 generator */
break;
case -34: vesa( 0x10C ); /* VESA 10C, 60 x 132 */
loadfont( 17 ); /* use 8x14 generator */
break;
case -43: vesa( 0x10A ); /* VESA 10A, 43 x 132 */
loadfont( 18 ); /* use 8x8 generator */
break;
case -50: vesa( 0x109 ); /* VESA 109, 25 x 132 */
loadfont( 18 ); /* use 8x8 generator */
break; /* aka VESA 10B 50x132 */
case -60: vesa( 0x10C ); /* VESA 10C, 60 x 132 */
loadfont( 18 ); /* use 8x8 generator */
break; /* only ONE video page */
#endif
case 1: /* mode 1 == 25 x 40 */
os_regs.x.ax = 0x0081;
intr_video_on_os_regs();
default: break; /* unusual row number ? */
}
/* ---- restore border colour and cursor ---------------------- */
os_regs.x.ax = 0x1001; os_regs.h.bh = border;
intr_video_on_os_regs(); /* 1001h set overscan register */
if ( wanted == getlines() ) /* check result of operations: */
vgapatch( newrow ); /* okay, reset clear RAM flag */
else cursor = 0xFFFF; /* else 0xFFFF indicates error */
post_adjust( oldrow, oldcol, newrow, newcol, colour, cursor );
display( 0 ); /* screen refresh again enabled */
return (char)( cursor != 0xFFFF ); /* 1: okay, 0: failure */
}
/*----------------------------------------------------------------------*/
static int usage( char const *name )
{ cputs( "\r\nusage: " ); cputs( name );
cputs( " [lines [command [args]]]\n"
"\r\nlines = 12, 14, 21, 25, 28, 30, 34, 43, 50, 60,"
"\r\nfor NNx132 use -21,-25,-28,-30,-34,-43,-50,-60.\n"
"\r\nFor 25x40 use +1, +/-1 are special cases here."
"\r\nOmit lines to toggle between NNx80 and NNx132.\n"
"\r\nSpecify a command to execute it in a subshell"
"\r\nwith the given number of lines.\n"
"\r\nUse -1 to switch VESA display power OFF until"
"\r\na key pressed or the subshell command returns."
"\r\n" );
return getlines(); /* exit code current -60 ... 60 */
}
/************************************************************************/
int main( int argc, char *argv[] )
{ int rc = 0;
signed char wanted, preset = getlines();
char *alias = argv[ 0 ];
if ( argc == 1 ) /* no argument: toggle 80 / 132 */
wanted = (signed char) -preset;
else wanted = (signed char) atoi( argv[ 1 ] );
if ( wanted == 0 ) return usage( alias ); /* invalid arg. */
if ( ! setlines( wanted )) /* bad number of rows or no VGA */
{ cputs( "\r\n" ); cputs( alias ); cputs( ": " );
cputs( argc == 1 ? "toggle" : argv[ 1 ] );
cputs( " not supported\r\n" ); return 1;
}
if ( argc > 2 ) /* try subshell command spawn */
{
os_regs.x.es = *(WORD _far *) MK_FP( _psp, PSP_ENV_SEG );
os_regs.h.ah = DOS_FREEMEM;
intr( DOS, &os_regs ); /* release environment memory */
for ( rc = 2; rc <= argc; ++rc ) /* double shift */
argv[ rc - 2 ] = argv[ rc ]; /* arguments */
rc = spawnvp( P_WAIT, argv[ 0 ], argv );
setlines( preset ); /* reset user's text mode lines */
if ( rc == -1 ) /* if spawn failed completely */
{ cputs( "\r\n" ); cputs( argv[ 0 ] );
cputs( ": " ); cputs( strerror( errno ));
cputs( "\r\n" );
} }
else if ( wanted == -1 ) /* await any key pressed, then */
{ idle(); display( 0 ); /* switch VESA display power ON */
}
return rc;
}