home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
vile-src.zip
/
vile-8.1
/
gppconio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-04-28
|
19KB
|
774 lines
/* This file is properly part of the excellent DJGPP compiler/tools package
put out by DJ Delorie for use under DOS. Unfortunately, the module
as distributed in many versions of the DJGPP is buggy -- this copy
of gppconio.c fixes many of those bugs. I understand that these
changes have been sent back to the DJGPP maintainers -- hopefully
vile will not need to include this file in the future. -pgf 9/95
*/
#if __DJGPP__ < 2
/**********************************************************************
*
* NAME: gppconio.c
*
* DESCRIPTION: simulate Borland text video funcs for GNU C++
*
* copyright (c) 1991 J. Alan Eldridge
*
* M O D I F I C A T I O N H I S T O R Y
*
* when who what
* -------------------------------------------------------------------
* 10/27/91 J. Alan Eldridge created
* 01/06/92 D. Buerssner make it work with extended characters
* (buers@dg1.chemie.uni-konstanz.de) speed-up of cputs
* some missing brackets in VIDADDR
* don't need scrollwindow anymore
* 07/15/93 D. Buerssner take care of cursor tracking
* txinfo.curx and txinfo.cury
* fill in missing functionality
* - textmode
* - cscanf
* - cgets
* - getch and ungetch
* - _setcursortype
* - kbhit
* (hpefully) proper initialization of
* txinfo.normattrib and txinfo.attribute
* gotoxy(1,1) in clrscr (bug introduced
* by my previous patches)
* gotoxy(1,1) in window
* take care of BELL and BACKSPACE
* in putch and cputs
* take care of blinking bit in textcolor
* and textbackground
* declare (and ignore) directvideo
* 10/09/93 DJ Delorie Switch to dosmem*() for DPMI
* 05/01/94 DJ Delorie Add _wscroll
*********************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <dos.h>
#include <pc.h>
#include <go32.h>
#include "gppconio.h"
int _wscroll = 1;
int directvideo = 1; /* We ignore this */
static void setcursor(unsigned int shape);
static int getvideomode(void);
static void bell(void);
static int get_screenattrib(void);
static int isEGA(void);
static int _scan_getche(FILE *fp);
static int _scan_ungetch(int c, FILE *fp);
#define DBGGTINFO 0
static unsigned ScreenAddress = 0xb8000UL; /* initialize just in case */
static struct text_info txinfo;
static int ungot_char;
static int char_avail = 0;
#define VIDADDR(r,c) (ScreenAddress + 2*(((r) * txinfo.screenwidth) + (c)))
int puttext(int c, int r, int c2, int r2, void *buf)
{
short *cbuf = (short *)buf;
/* we should check for valid parameters, and maybe return 0 */
r--, r2--, c--, c2--;
for (; r <= r2; r++)
{
dosmemput(cbuf, (c2-c+1)*2, VIDADDR(r, c));
cbuf += c2-c+1;
}
return 1;
}
int gettext(int c, int r, int c2, int r2, void *buf)
{
short *cbuf = (short *)buf;
/* we should check for valid parameters, and maybe return 0 */
r--, r2--, c--, c2--;
for (; r <= r2; r++)
{
dosmemget(VIDADDR(r, c), (c2-c+1)*2, cbuf);
cbuf += c2-c+1;
}
return 1;
}
void gotoxy(int col, int row)
{
ScreenSetCursor(row + txinfo.wintop - 2, col + txinfo.winleft - 2);
txinfo.curx = col;
txinfo.cury = row;
}
int wherex(void)
{
int row, col;
ScreenGetCursor(&row, &col);
return col - txinfo.winleft + 2;
}
int wherey(void)
{
int row, col;
ScreenGetCursor(&row, &col);
return row - txinfo.wintop + 2;
}
void textmode(int mode)
{
union REGS regs;
int mode_to_set = mode;
if (mode == LASTMODE)
mode = mode_to_set = txinfo.currmode;
if (mode == C4350)
/*
* just set mode 3 and load 8x8 font, idea taken
* (and code translated from Assembler to C)
* form Csaba Biegels stdvga.asm
*/
mode_to_set = 0x03;
regs.h.ah = 0x00; /* set mode */
regs.h.al = mode_to_set;
int86(0x10, ®s, ®s);
if (mode == C80 || mode == BW80 || mode == C4350)
{
if (isEGA())
{
/*
* enable cursor size emulation, see Ralf Browns
* interrupt list
*/
regs.h.ah = 0x12;
regs.h.bl = 0x34;
regs.h.al = 0x00; /* 0: enable (1: disable) */
int86(0x10, ®s, ®s);
}
}
if (mode == C4350)
{
if (!isEGA())
return;
/* load 8x8 font */
regs.x.ax = 0x1112;
regs.x.bx = 0;
int86(0x10, ®s, ®s);
}
/* _setcursortype(_NORMALCURSOR); */
/* reinitialize txinfo structure to take into account new mode */
gppconio_init();
#if 0
/*
* For mode C4350 the screen is not cleared on my OAK-VGA.
* Should we clear it here? TURBOC doesn't so we don't bother either.
*/
clrscr();
#endif
}
void textattr(int attr)
{
txinfo.attribute = ScreenAttrib = (unsigned char)attr;
}
void textcolor(int color)
{
/* strip blinking (highest) bit and textcolor */
ScreenAttrib &= 0x70; /* strip blinking (highest) bit and textcolor */
txinfo.attribute=(ScreenAttrib |= (color & 0x8f));
}
void textbackground(int color)
{
/* strip background color, keep blinking bit */
ScreenAttrib &= 0x8f;
/* high intensity background colors (>7) are not allowed
so we strip 0x08 bit (and higher bits) of color */
txinfo.attribute=(ScreenAttrib |= ((color & 0x07) << 4));
}
void highvideo(void)
{
txinfo.attribute=(ScreenAttrib |= 0x08);
}
void lowvideo(void)
{
txinfo.attribute=(ScreenAttrib &= 0x07);
}
void normvideo(void)
{
txinfo.attribute = ScreenAttrib = txinfo.normattr;
}
void _setcursortype(int type)
{
unsigned cursor_shape;
switch (type)
{
case _NOCURSOR:
cursor_shape = 0x0700;
break;
case _SOLIDCURSOR:
cursor_shape = 0x0007;
break;
/* case _NORMALCURSOR: */
default:
cursor_shape = 0x0607;
break;
}
setcursor(cursor_shape);
}
static void setcursor(unsigned int cursor_shape)
/* Sets the shape of the cursor */
{
union REGS reg;
reg.h.ah = 1;
reg.x.cx = cursor_shape;
int86(0x10, ®, ®);
} /* setcursor */
static void getwincursor(int *row, int *col)
{
ScreenGetCursor(row, col);
}
void clreol(void)
{
short image[ 256 ];
short val = ' ' | (ScreenAttrib << 8);
int c, row, col, ncols;
getwincursor(&row, &col);
ncols = txinfo.winright - col;
for (c = 0; c < ncols; c++)
image[ c ] = val;
puttext(col + 1, row + 1, txinfo.winright, row + 1, image);
}
static void fillrow(int row, int left, int right, int fill)
{
int col;
short filler[right-left+1];
for (col = left; col <= right; col++)
filler[col-left] = fill;
dosmemput(filler, (right-left+1)*2, VIDADDR(row, left));
}
void clrscr(void)
{
short filler[txinfo.winright - txinfo.winleft + 1];
int row, col;
for (col=0; col < txinfo.winright - txinfo.winleft + 1; col++)
filler[col] = ' ' | (ScreenAttrib << 8);
for (row=txinfo.wintop-1; row < txinfo.winbottom; row++)
dosmemput(filler, (txinfo.winright - txinfo.winleft + 1)*2,
VIDADDR(row, txinfo.winleft - 1));
gotoxy(1, 1);
}
int putch(int c)
{
int row, col;
ScreenGetCursor(&row, &col);
/* first, handle the character */
if (c == '\n')
{
row++;
}
else if (c == '\r')
{
col = txinfo.winleft - 1;
}
else if (c == '\b')
{
if (col > txinfo.winleft - 1)
col--;
else if (row > txinfo.wintop -1)
{
/*
* Turbo-C ignores this case; we are smarter.
*/
row--;
col = txinfo.winright-1;
}
}
else if (c == 0x07)
bell();
else {
/* short val = c | (ScreenAttrib << 8); */
/* puttext(col + 1, row + 1, col + 1, row + 1, &val); */
ScreenPutChar(c, ScreenAttrib, col, row);
col++;
}
/* now, readjust the window */
if (col >= txinfo.winright) {
col = txinfo.winleft - 1;
row++;
}
if (row >= txinfo.winbottom) {
/* scrollwin(0, txinfo.winbottom - txinfo.wintop, 1); */
if (_wscroll)
{
ScreenSetCursor(txinfo.wintop-1,0);
delline();
}
row--;
}
ScreenSetCursor(row, col);
txinfo.cury = row - txinfo.wintop + 2;
txinfo.curx = col - txinfo.winleft + 2;
return c;
}
int getche(void)
{
if (char_avail)
/*
* We don't know, wether the ungot char was already echoed
* we assume yes (for example in cscanf, probably the only
* place where ungetch is ever called.
* There is no way to check for this really, because
* ungetch could have been called with a character that
* hasn't been got by a conio function.
* We don't echo again.
*/
return(getch());
return (putch(getch()));
}
int getch(void)
{
union REGS regs;
int c;
if (char_avail)
{
c = ungot_char;
char_avail = 0;
}
else
{
regs.x.ax = 0x0700;
int86(0x21, ®s, ®s);
c = regs.h.al;
}
return(c);
}
int ungetch(int c)
{
if (char_avail)
return(EOF);
ungot_char = c;
char_avail = 1;
return(c);
}
/*
* kbhit from libc in libsrc/c/dos/kbhit.s doesn't check
* for ungotten chars, so we have to provide a new one
* Don't call it kbhit, rather use a new name (_conio_kbhit)
* and do a #define kbhit _conio_kbhit in gppconio.h.
* The old kbhit still can be used if gppconio.h
* is not included of after #undef kbhit
* If you don't use ungetch (directly or indirectly by cscanf)
* both kbhit and _conio_kbhit are the same.
* So this shouldn't cause any trouble with previously written
* source, because ungetch wasn't available.
* The only problem might be, if anybody just included gppconio.h
* and has not linked with libpc, (I can't think of a good reason
* for this). This will result a link error (undefined symbol _conio_kbhit).
*/
#undef kbhit /* want to be able to call kbhit from libc */
/* The kbhit in libc doesn't work for the second byte of extended chars. */
int kbhit(void)
{
union REGS regs;
regs.h.ah = 0x0b;
int86(0x21, ®s, ®s);
return regs.h.al ? -1 : 0;
}
int _conio_kbhit(void)
{
if (char_avail)
return(1);
else
return(kbhit());
}
/*
* The next two functions are needed by cscanf
*/
static int _scan_getche(FILE *fp)
{
return(getche());
}
static int _scan_ungetch(int c, FILE *fp)
{
return(ungetch(c));
}
void insline(void)
{
int row, col, left, right, nbytes, bot, fill;
ScreenGetCursor(&row, &col);
left = txinfo.winleft - 1;
right = txinfo.winright - 1;
nbytes = (right-left+1)*2;
bot = txinfo.winbottom-1;
fill = ' ' | (ScreenAttrib << 8);
while(bot > row)
{
movedata(_go32_conventional_mem_selector(), VIDADDR(bot-1, left),
_go32_conventional_mem_selector(), VIDADDR(bot, left),
nbytes);
bot--;
}
if (row <= bot)
{
fillrow(row,left,right,fill);
}
}
void delline(void)
{
int row, col, left, right, nbytes, bot, fill;
ScreenGetCursor(&row, &col);
left = txinfo.winleft - 1;
right = txinfo.winright - 1;
nbytes = (right-left+1)*2;
bot = txinfo.winbottom-1;
fill = ' ' | (ScreenAttrib << 8);
while(row < bot)
{
movedata(_go32_conventional_mem_selector(), VIDADDR(row+1, left),
_go32_conventional_mem_selector(), VIDADDR(row, left),
nbytes);
row++;
}
fillrow(bot,left,right,fill);
}
void window(int left, int top, int right, int bottom)
{
if (top < 1 || left < 1 || right > txinfo.screenwidth ||
bottom > txinfo.screenheight)
return;
txinfo.wintop = top;
txinfo.winleft = left;
txinfo.winright = right;
txinfo.winbottom = bottom;
gotoxy(1,1);
}
int cputs(const char *s)
{
int row, col,c;
const unsigned char *ss = (const unsigned char *)s;
short *viaddr;
short sa = ScreenAttrib << 8;
ScreenGetCursor(&row, &col);
viaddr = (short *)VIDADDR(row,col);
/*
* Instead of just calling putch; we do everything by hand here,
* This is much faster. We don't move the cursor after each character,
* only after the whole string is written, because ScreenSetCursor
* needs to long because of switching to real mode needed with djgpp.
* You won't recognize the difference.
*/
while ((c = *ss++))
{
/* first, handle the character */
if (c == '\n')
{
row++;
viaddr += txinfo.screenwidth;
}
else if (c == '\r')
{
col = txinfo.winleft - 1;
viaddr = (short *)VIDADDR(row,col);
}
else if (c == '\b')
{
if (col > txinfo.winleft-1)
{
col--;
viaddr--;
}
else if (row > txinfo.wintop -1)
{
/*
* Turbo-C ignores this case. We want to be able to
* edit strings with backspace in gets after
* a linefeed, so we are smarter
*/
row--;
col = txinfo.winright-1;
viaddr = (short *)VIDADDR(row,col);
}
}
else if (c == 0x07)
bell();
else {
short q = c | sa;
dosmemput(&q, 2, (int)viaddr);
viaddr++;
col++;
}
/* now, readjust the window */
if (col >= txinfo.winright) {
col = txinfo.winleft - 1;
row++;
viaddr = (short *)VIDADDR(row,col);
}
if (row >= txinfo.winbottom) {
ScreenSetCursor(txinfo.wintop-1,0); /* goto first line in window */
delline(); /* and delete it */
row--;
viaddr -= txinfo.screenwidth;
}
}
ScreenSetCursor(row, col);
txinfo.cury = row - txinfo.wintop + 2;
txinfo.curx = col - txinfo.winleft + 2;
return(*(--ss));
}
int cprintf(const char *fmt, ...)
{
int cnt;
char buf[ 2048 ]; /* this is buggy, because buffer might be too small. */
va_list ap;
va_start(ap, fmt);
cnt = vsprintf(buf, fmt, ap);
va_end(ap);
cputs(buf);
return cnt;
}
char *cgets(char *string)
{
unsigned len = 0;
unsigned int maxlen_wanted;
char *sp;
int c;
/*
* Be smart and check for NULL pointer.
* Don't know wether TURBOC does this.
*/
if (!string)
return(NULL);
maxlen_wanted = (unsigned int)((unsigned char)string[0]);
sp = &(string[2]);
/*
* Should the string be shorter maxlen_wanted including or excluding
* the trailing '\0' ? We don't take any risk.
*/
while(len < maxlen_wanted-1)
{
c=getch();
/*
* shold we check for backspace here?
* TURBOC does (just checked) but doesn't in cscanf (thats harder
* or even impossible). We do the same.
*/
if (c == '\b')
{
if (len > 0)
{
cputs("\b \b"); /* go back, clear char on screen with space
and go back again */
len--;
sp[len] = '\0'; /* clear the character in the string */
}
}
else if (c == '\r')
{
sp[len] = '\0';
break;
}
else if (c == 0)
{
/* special character ends input */
sp[len] = '\0';
ungetch(c); /* keep the char for later processing */
break;
}
else
{
sp[len] = putch(c);
len++;
}
}
sp[maxlen_wanted-1] = '\0';
string[1] = (char)((unsigned char)len);
return(sp);
}
int cscanf(const char *fmt, ...)
{
return(_doscan_low(NULL, _scan_getche, _scan_ungetch,
fmt, (void **)((&fmt)+1)));
}
int movetext(int left, int top, int right, int bottom, int dleft, int dtop)
{
char *buf = malloc((right - left + 1) * (bottom - top + 1) * 2);
if (!buf)
return 0;
gettext(left, top, right, bottom, buf);
puttext(dleft, dtop, dleft + right - left, dtop + bottom - top, buf);
free(buf);
return 1;
}
static void _gettextinfo(struct text_info *t)
{
int row, col;
t->winleft = t->wintop = 1;
t->winright = t->screenwidth = ScreenCols();
t->winbottom = t->screenheight = ScreenRows();
ScreenAttrib = t->attribute = t->normattr = get_screenattrib();
t->currmode = getvideomode();
ScreenGetCursor(&row, &col);
t->curx = col+1;
t->cury = row+1;
#if DBGGTINFO
printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n",t->winleft,
t->winright,t->wintop,t->winbottom);
printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
t->screenheight, t->screenwidth, t->normattr, t->currmode,
t->curx, t->cury);
#endif
}
void gettextinfo(struct text_info *t)
{
*t = txinfo;
#if DBGGTINFO
printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n",t->winleft,
t->winright,t->wintop,t->winbottom);
printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
t->screenheight, t->screenwidth, t->normattr, t->currmode,
t->curx, t->cury);
#endif
}
static int
getvideomode(void)
{
int mode = ScreenMode();
/*
* in mode C80 we might have loaded a different font
*/
if (mode == C80)
if (ScreenRows() > 25)
mode = C4350;
return(mode);
}
static void bell(void)
{
union REGS regs;
#if 0
/* use BIOS */
regs.h.ah = 0x0e; /* write */
regs.h.al = 0x07; /* bell */
int86(0x10, ®s, ®s);
#else
/* use DOS */
regs.h.ah = 0x06; /* write */
regs.h.dl = 0x07; /* bell */
int86(0x21, ®s, ®s);
#endif
}
static int
get_screenattrib(void)
{
union REGS regs;
regs.h.ah = 0x08; /* read character and attribute */
regs.h.bh = 0; /* video page 0 */
int86(0x10, ®s, ®s);
return(regs.h.ah & 0x7f); /* strip highest (BLINK) bit */
}
/* check if we have at least EGA (idea form Ralf Browns interrupt list) */
static int
isEGA(void)
{
union REGS regs;
regs.h.ah = 0x12;
regs.h.bl = 0x10;
regs.h.bh = 0xff;
int86(0x10, ®s, ®s);
return(regs.h.bh != 0xff);
}
extern int _gppconio_init;
void gppconio_init(void)
{
static int oldattrib = -1;
if (oldattrib == -1)
oldattrib = get_screenattrib();
_gettextinfo(&txinfo);
if (txinfo.currmode == 7) /* MONO */
ScreenAddress = 0xb0000UL;
else
ScreenAddress = 0xb8000UL;
ScreenAttrib = txinfo.normattr = txinfo.attribute = oldattrib;
_gppconio_init = 1;
}
#endif /* __DJGPP__ < 2 */