home *** CD-ROM | disk | FTP | other *** search
- /* pc.c */
-
- /* Author:
- * Guntram Blohm
- * Buchenstrasse 19
- * 7904 Erbach, West Germany
- * Tel. ++49-7305-6997
- * sorry - no regular network connection
- */
-
- /* This file implements the ibm pc bios interface. See IBM documentation
- * for details.
- * If TERM is set upon invocation of elvis, this code is ignored completely,
- * and the standard termcap functions are used, thus, even not-so-close
- * compatibles can run elvis. For close compatibles however, bios output
- * is much faster (and permits reverse scrolling, adding and deleting lines,
- * and much more ansi.sys isn't capable of). GB.
- */
-
- /* The routines for setting raw mode were written by Dan Kegel. They were
- * taken [with slight modifications] from the "raw.c" file that he distributes
- * with his NANSI.SYS console driver. Email: dank@moc.jpl.nasa.gov
- */
-
- #include "config.h"
- #include "vi.h"
-
- #if MSDOS
-
- #include <dos.h>
-
- static void video();
-
- /* vmode contains the screen attribute index and is set by attrset.*/
-
- int vmode;
-
- /* The following array contains attribute definitions for
- * color/monochrome attributes. Screen selects one of the sets.
- * Maybe i'll put them into elvis options one day.
- */
-
- static int screen;
- static char attr[2][8] =
- {
- /* :se: :so: :VB: :ul: :as: popup visible quit */
- { 0x1f, 0x1d, 0x1e, 0x1a, 0x1c, 0x2f, 0x3f, 0x07}, /* color */
- { 0x07, 0x70, 0x0f, 0x01, 0x0f, 0x70, 0x70, 0x07}, /* mono */
- };
-
- /*
- * bios interface functions for elvis - pc version
- */
-
- int biosquit()
- {
- int cx = 1;
-
- vmode = 7;
- v_ce();
- }
-
-
- /* This function changes the table of attribute bytes used during BIOS output.
- */
- int bioscolor(mode, attrbyte)
- int mode; /* e.g. A_NORMAL */
- int attrbyte;/* color code, as a PC attribute byte */
- {
- attr[0][mode] = attrbyte;
- return 0;
- }
-
- /* IOCTL GETBITS/SETBITS bits. */
- #define DEVICE 0x80
- #define RAW 0x20
-
- /* IOCTL operations */
- #define GETBITS 0
- #define SETBITS 1
- #define GETINSTATUS 6
-
- /* DOS function numbers. */
- #define BREAKCHECK 0x33
- #define IOCTL 0x44
-
- /* A nice way to call the DOS IOCTL function */
- static int
- ioctl(int handle, int mode, unsigned setvalue)
- {
- union REGS regs;
-
- regs.h.ah = IOCTL;
- regs.h.al = (char) mode;
- regs.x.bx = handle;
- regs.h.dl = (char) setvalue;
- regs.h.dh = 0; /* Zero out dh */
- intdos(®s, ®s);
- return (regs.x.dx);
- }
-
-
- /*--------------------------------------------------------------------------
- Call this routine to set or clear RAW mode for the device associated with
- the given file.
- Example: raw_set(1, TRUE);
- --------------------------------------------------------------------------*/
- void raw_set(fd, rawstate)
- int fd;
- int rawstate;
- {
- int bits;
- bits = ioctl(fd, GETBITS, 0);
- if (DEVICE & bits) {
- if (rawstate)
- bits |= RAW;
- else
- bits &= ~RAW;
- (void) ioctl(fd, SETBITS, bits);
- }
- }
-
- /* A nice way to call the DOS BREAKCHECK function */
- static int breakctl(int mode, int setvalue)
- {
- union REGS regs;
-
- regs.h.ah = BREAKCHECK;
- regs.h.al = (char) mode;
- regs.h.dl = (char) setvalue;
- intdos(®s, ®s);
- return (regs.x.dx & 0xff);
- }
-
- /*--------------------------------------------------------------------------
- Call this routine to determine whether DOS is checking for break (Control-C)
- before it executes any DOS function call.
- Return value is FALSE if it only checks before console I/O function calls,
- TRUE if it checks before any function call.
- --------------------------------------------------------------------------*/
- int break_get(void)
- {
- return ( 0 != breakctl(GETBITS, 0));
- }
-
- /*--------------------------------------------------------------------------
- Call this routine with TRUE to tell DOS to check for break (Control-C)
- before it executes any DOS function call.
- Call this routine with FALSE to tell DOS to only check for break before
- it executes console I/O function calls.
- --------------------------------------------------------------------------*/
- void break_set(check)
- int check;
- {
- (void) breakctl(SETBITS, check);
- }
-
- /*--------------------------------------------------------------------------
- One routine to set (or clear) raw mode on stdin and stdout,
- clear (or restore) break checking, and turn off input buffering on stdin.
- This is the most common configuration; under MS-DOS, since setting raw mode
- on stdout sometimes sets it on stdin, it's best to set it on both & be done
- with it.
- --------------------------------------------------------------------------*/
- void raw_set_stdio(rawstate)
- int rawstate; /* TRUE -> set raw mode; FALSE -> clear raw mode */
- {
- static int was_break_checking = 0;
-
- raw_set(0, rawstate);
- raw_set(1, rawstate);
- if (rawstate) {
- was_break_checking = break_get();
- break_set(0);
- } else {
- break_set(was_break_checking);
- }
- }
-
-
-
-
-
-
- /* cursor up: determine current position, decrement row, set position */
-
- void v_up()
- {
- int dx;
- video(0x300,(int *)0,&dx);
- dx-=0x100;
- video(0x200,(int *)0,&dx);
- }
-
- #ifndef NO_CURSORSHAPE
- /* cursor big: set begin scan to end scan - 4 */
- void v_cb()
- {
- int cx;
- video(0x300, &cx, (int *)0);
- cx=((cx&0xff)|(((cx&0xff)-4)<<8));
- video(0x100, &cx, (int *)0);
- }
-
- /* cursor small: set begin scan to end scan - 1 */
- void v_cs()
- {
- int cx;
- video(0x300, &cx, (int *)0);
- cx=((cx&0xff)|(((cx&0xff)-1)<<8));
- video(0x100, &cx, (int *)0);
- }
- #endif
-
- /* clear to end: get cursor position and emit the aproppriate number
- * of spaces, without moving cursor.
- */
-
- void v_ce()
- {
- int cx, dx;
- video(0x300,(int *)0,&dx);
- cx=COLS-(dx&0xff);
- video(0x920,&cx,(int *)0);
- }
-
- /* clear screen: clear all and set cursor home */
-
- void v_cl()
- {
- int cx=0, dx=((LINES-1)<<8)+COLS-1;
- video(0x0600,&cx,&dx);
- dx=0;
- video(0x0200,&cx,&dx);
- }
-
- /* clear to bottom: get position, clear to eol, clear next line to end */
-
- void v_cd()
- {
- int cx, dx, dxtmp;
- video(0x0300,(int *)0,&dx);
- dxtmp=(dx&0xff00)|(COLS-1);
- cx=dx;
- video(0x0600,&cx,&dxtmp);
- cx=(dx&0xff00)+0x100;
- dx=((LINES-1)<<8)+COLS-1;
- video(0x600,&cx,&dx);
- }
-
- /* add line: scroll rest of screen down */
-
- void v_al()
- {
- int cx,dx;
- video(0x0300,(int *)0,&dx);
- cx=(dx&0xff00);
- dx=((LINES-1)<<8)+COLS-1;
- video(0x701,&cx,&dx);
- }
-
- /* delete line: scroll rest up */
-
- void v_dl()
- {
- int cx,dx;
- video(0x0300,(int *)0,&dx);
- cx=(dx&0xff00)/*+0x100*/;
- dx=((LINES-1)<<8)+COLS-1;
- video(0x601,&cx,&dx);
- }
-
- /* scroll reverse: scroll whole screen */
-
- void v_sr()
- {
- int cx=0, dx=((LINES-1)<<8)+COLS-1;
- video(0x0701,&cx,&dx);
- }
-
- /* set cursor */
-
- void v_move(x,y)
- int x, y;
- {
- int dx=(y<<8)+x;
- video(0x200,(int *)0,&dx);
- }
-
- /* put character: set attribute first, then execute char.
- * Also remember if current line has changed.
- */
-
- int v_put(ch)
- int ch;
- {
- int cx=1;
- ch&=0xff;
- if (ch>=' ')
- video(0x900|ch,&cx,(int *)0);
- video(0xe00|ch,(int *)0, (int *)0);
- if (ch=='\n')
- { exwrote = TRUE;
- video(0xe0d, (int *)0, (int *)0);
- }
- return ch;
- }
-
- /* determine number of screen columns. Also set attrset according
- * to monochrome/color screen.
- */
-
- int v_cols()
- {
- union REGS regs;
- regs.h.ah=0x0f;
- int86(0x10, ®s, ®s);
- if (regs.h.al==7) /* monochrome mode ? */
- screen=1;
- else
- screen=0;
- return regs.h.ah;
- }
-
- /* Getting the number of rows is hard. Most screens support 25 only,
- * EGA/VGA also support 43/50 lines, and some OEM's even more.
- * Unfortunately, there is no standard bios variable for the number
- * of lines, and the bios screen memory size is always rounded up
- * to 0x1000. So, we'll really have to cheat.
- * When using the screen memory size, keep in mind that each character
- * byte has an associated attribute byte.
- *
- * uses: word at 40:4c contains memory size
- * byte at 40:84 # of rows-1 (sometimes)
- * byte at 40:4a # of columns
- */
-
- int v_rows()
- {
- int line, oldline;
-
- /* screen size less then 4K? then we have 25 lines only */
-
- if (*(int far *)(0x0040004cl)<=4096)
- return 25;
-
- /* VEGA vga uses the bios byte at 0x40:0x84 for # of rows.
- * Use that byte, if it makes sense together with memory size.
- */
-
- if ((((*(unsigned char far *)(0x0040004aL)*2*
- (*(unsigned char far *)(0x00400084L)+1))+0xfff)&(~0xfff))==
- *(unsigned int far *)(0x0040004cL))
- return *(unsigned char far *)(0x00400084L)+1;
-
- /* uh oh. Emit '\n's until screen starts scrolling. */
-
- v_move(oldline=0, 0);
- for (;;)
- {
- video(0xe0a,(int *)0,(int *)0);
- video(0x300,(int *)0,&line);
- line>>=8;
- if (oldline==line)
- return line+1;
- oldline=line;
- }
- }
-
- /* the REAL bios interface -- used internally only. */
-
- static void video(ax, cx, dx)
- int ax, *cx, *dx;
- {
- union REGS regs;
-
- regs.x.ax=ax;
- if ((ax&0xff00)==0x600 || (ax&0xff00)==0x700)
- regs.h.bh=attr[screen][vmode];
- else
- {
- regs.h.bh=0;
- regs.h.bl=attr[screen][vmode];
- }
- if (cx) regs.x.cx=*cx;
- if (dx) regs.x.dx=*dx;
- int86(0x10, ®s, ®s);
- if (dx) *dx=regs.x.dx;
- if (cx) *cx=regs.x.cx;
- }
-
- /* The following function determines which character is used for
- * commandline-options by command.com. This system call is undocumented
- * and valid for versions < 4.00 only.
- */
-
- int switchar()
- {
- union REGS regs;
- regs.x.ax=0x3700;
- int86(0x21, ®s, ®s);
- return regs.h.dl;
- }
-
-
- /* this function returns the DOS time, as a 32-bit long int representing
- * hundredths of a second since midnight. Some systems may be limited to
- * a resolution of whole seconds, but the values will still represent
- * hundredths.
- */
- static long dostime()
- {
- union REGS regs;
-
- regs.h.ah = 0x2c; /* MS-DOS "get time" service */
- intdos(®s, ®s);
- return (((regs.h.ch * 60L) + regs.h.cl) * 60L + regs.h.dh) * 100L + regs.h.dl;
- }
-
-
- /*ARGSUSED*/
- /* This function implements a raw read from the keyboard, with timeout. */
- int ttyread(buf, len, time)
- char *buf; /* where to store the keystrokes */
- int len; /* maximum number of characters to get -- ignored */
- int time; /* maximum time to wait, in 1/9th second increments */
- {
- long stop;
-
- /* are we going to timeout? */
- if (time != 0)
- {
- /* compute the time when we'll give up */
- stop = dostime() + time * 10L;
-
- /* wait for either keystroke or timeout */
- while (!kbhit())
- {
- if (dostime() > stop)
- {
- /* we couldn't read any characters
- * before timeout
- */
- return 0;
- }
- }
- }
-
- /* get a keystroke */
- buf[0] = getch();
- if (buf[0] == 0) /* function key? */
- {
- buf[0] = '#';
- buf[1] = getch();
- return 2;
- }
- else
- {
- return 1;
- }
- }
-
- #if !TURBOC
- /* Turboc provides sleep, declared as void sleep(unsigned seconds) */
- int sleep(seconds)
- unsigned seconds;
- {
- long stop;
-
- stop = dostime() + 100L * seconds;
- while (dostime() < stop)
- {
- }
- return 0;
- }
- #endif
- #endif
-