⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_msdos.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 3 页
字号:
/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved	by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

/*
 * os_msdos.c
 *
 * MSDOS system-dependent routines.
 * A cheap plastic imitation of the amiga dependent code.
 * A lot in this file was made by Juergen Weigert (jw).
 *
 * DJGPP changes by Gert van Antwerpen
 * Faster text screens by John Lange (jlange@zilker.net)
 *
 */

#include <io.h>
#include "vim.h"

#include <conio.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include <bios.h>
#ifdef DJGPP
# include <dpmi.h>
# include <signal.h>
# include <sys/movedata.h>
#else
# include <alloc.h>
#endif

#if defined(DJGPP) || defined(PROTO)
# define _cdecl	    /* DJGPP doesn't have this */
#endif

static int cbrk_pressed = FALSE;    /* set by ctrl-break interrupt */
static int ctrlc_pressed = FALSE;   /* set when ctrl-C or ctrl-break detected */
static int delayed_redraw = FALSE;  /* set when ctrl-C detected */

#ifdef USE_MOUSE
static int mouse_avail = FALSE;		/* mouse present */
static int mouse_active;		/* mouse enabled */
static int mouse_hidden;		/* mouse not shown */
static int mouse_click = -1;		/* mouse status */
static int mouse_last_click = -1;	/* previous status at click */
static int mouse_x = -1;		/* mouse x coodinate */
static int mouse_y = -1;		/* mouse y coodinate */
static long mouse_click_time = 0;	/* biostime() of last click */
static int mouse_click_count = 0;	/* count for multi-clicks */
static int mouse_click_x = 0;		/* x of previous mouse click */
static int mouse_click_y = 0;		/* y of previous mouse click */
static linenr_t mouse_topline = 0;	/* topline at previous mouse click */
static int mouse_x_div = 8;		/* column = x coord / mouse_x_div */
static int mouse_y_div = 8;		/* line   = y coord / mouse_y_div */
#endif

#define BIOSTICK    55		    /* biostime() increases one tick about
					every 55 msec */

#ifdef DJGPP
/*
 * For DJGPP, use our own functions for fast text screens.  JML 1/18/98
 */

unsigned long	S_ulScreenBase = 0xb8000;
unsigned short	S_uiAttribute = 7 << 8;
int		S_iCurrentRow = 0;	/* These are 0 offset */
int		S_iCurrentColumn = 0;
int		S_iLeft = 0;	/* These are 1 offset */
int		S_iTop = 0;
int		S_iRight = 0;
int		S_iBottom = 0;
short		S_selVideo;	/* Selector for DJGPP direct video transfers */

    static void
mygotoxy(int x, int y)
{
    S_iCurrentRow = y - 1;
    S_iCurrentColumn = x - 1;
    gotoxy(x,y);		/* set cursor position */
}

    static void
myscroll(void)
{
    short iRow, iColumn;
    unsigned short uiValue;

    /* Copy the screen */
    for (iRow = S_iTop; iRow < S_iBottom; iRow++)
	movedata(S_selVideo, (iRow * Columns) << 1,
		S_selVideo, ((iRow - 1) * Columns) << 1,
		(S_iRight - S_iLeft + 1) << 1);

    /* Clear the bottom row */
    uiValue = S_uiAttribute | ' ';
    for (iColumn = S_iLeft - 1; iColumn < S_iRight; iColumn++)
	_dosmemputw(&uiValue, 1, S_ulScreenBase
			 + (S_iBottom - 1) * (Columns << 1) + (iColumn << 1));
}

    static int
myputch(int iChar)
{
    unsigned int *puiLocation;
    unsigned short uiValue;

    if (iChar == '\n')
    {
	if (S_iCurrentRow >= S_iBottom - S_iTop)
	    myscroll();
	else
	    mygotoxy(S_iLeft, S_iCurrentRow + 2);
    }
    else if (iChar == '\r')
	mygotoxy(S_iLeft, S_iCurrentRow + 1);
    else if (iChar == '\b')
	mygotoxy(S_iCurrentColumn, S_iCurrentRow + 1);
    else if (iChar == 7)
    {
	sound(440);	/* short beep */
	delay(200);
	nosound();
    }
    else
    {
	uiValue = S_uiAttribute | (unsigned char)iChar;

	_dosmemputw(&uiValue, 1, S_ulScreenBase
		  + S_iCurrentRow * (Columns << 1) + (S_iCurrentColumn << 1));

	S_iCurrentColumn++;
	if (S_iCurrentColumn >= S_iRight && S_iCurrentRow >= S_iBottom - S_iTop)
	{
	    myscroll();
	    mygotoxy(S_iLeft, S_iCurrentRow + 2);
	}
	else
	    mygotoxy(S_iCurrentColumn + 1, S_iCurrentRow + 1);
    }

    return 0;
}

    static void
mywindow(int iLeft, int iTop, int iRight, int iBottom)
{
    S_iLeft = iLeft;
    S_iTop = iTop;
    S_iRight = iRight;
    S_iBottom = iBottom;
    window(iLeft, iTop, iRight, iBottom);
}

    static void
mytextinit(struct text_info *pTextinfo)
{
    S_selVideo = __dpmi_segment_to_descriptor(S_ulScreenBase >> 4);
    S_uiAttribute = pTextinfo->normattr << 8;
    mywindow(1, 1, Columns, Rows);
}

    static void
get_screenbase(void)
{
    static union REGS	    regs;

    /* old Hercules grafic card has different base address (Macewicz) */
    regs.h.ah = 0x0f;
    (void)int86(0x10, &regs, &regs);	/* int 10 0f */
    if (regs.h.al == 0x07)		/* video mode 7 -- hercules mono */
	S_ulScreenBase = 0xb0000;
    else
	S_ulScreenBase = 0xb8000;
}

    static void
mynormvideo(void)
{
    S_uiAttribute = 0x700;
    textbackground(0);			/*for delline() etc*/
}

    static void
mytextattr(int iAttribute)
{
    S_uiAttribute = (unsigned short)iAttribute << 8;
    iAttribute >>= 4;
    if (iAttribute < 8)
	textbackground(iAttribute);	/*for delline() etc*/
    else
	textbackground(0);
}

    static void
mytextcolor(int iTextColor)
{
    S_uiAttribute = (unsigned short)((S_uiAttribute & 0xf000)
					   | (unsigned short)iTextColor << 8);
    textcolor(iTextColor);		/*for delline() etc*/
}

    static void
mytextbackground(int iBkgColor)
{
    S_uiAttribute = (unsigned short)((S_uiAttribute & 0x0f00)
					 | (unsigned short)(iBkgColor << 12));
    if (iBkgColor < 8)
	textbackground(iBkgColor);	/*for delline() etc*/
    else
	textbackground(0);
}

#else
# define mygotoxy gotoxy
# define myputch putch
# define myscroll scroll
# define mywindow window
# define mynormvideo normvideo
# define mytextattr textattr
# define mytextcolor textcolor
# define mytextbackground textbackground
#endif

/*
 * Save/restore the shape of the cursor.
 * call with FALSE to save, TRUE to restore
 */
    static void
mch_restore_cursor_shape(int restore)
{
    static union REGS	    regs;
    static int		    saved = FALSE;

    if (restore)
    {
	if (saved)
	    regs.h.ah = 0x01;	    /*Set Cursor*/
	else
	    return;
    }
    else
    {
	regs.h.ah = 0x03;	    /*Get Cursor*/
	regs.h.bh = 0x00;	    /*Page */
	saved = TRUE;
    }

    (void)int86(0x10, &regs, &regs);
}

/*
 * Set the shape of the cursor.
 * 'thickness' can be from 0 (thin) to 7 (block)
 */
    static void
mch_set_cursor_shape(int thickness)
{
    union REGS	    regs;

    regs.h.ch = 7 - thickness;	    /*Starting Line*/
    regs.h.cl = 7;		    /*Ending Line*/
    regs.h.ah = 0x01;		    /*Set Cursor*/
    (void)int86(0x10, &regs, &regs);
}

    void
mch_update_cursor(void)
{
    int		idx;
    int		thickness;

    /*
     * How the cursor is drawn depends on the current mode.
     */
    idx = get_cursor_idx();

    if (cursor_table[idx].shape == SHAPE_BLOCK)
	thickness = 7;
    else
	thickness = (7 * cursor_table[idx].percentage + 90) / 100;
    mch_set_cursor_shape(thickness);
}

    long_u
mch_avail_mem(int special)
{
#ifdef DJGPP
    return _go32_dpmi_remaining_virtual_memory();
#else
    return coreleft();
#endif
}

#ifdef USE_MOUSE

/*
 * Set area where mouse can be moved to: The whole screen.
 * Rows must be valid when calling!
 */
    static void
mouse_area(void)
{
    union REGS	    regs;
    int		    mouse_y_max;	    /* maximum mouse y coord */

    if (mouse_avail)
    {
	mouse_y_max = Rows * mouse_y_div - 1;
	if (mouse_y_max < 199)	    /* is this needed? */
	    mouse_y_max = 199;
	regs.x.cx = 0;	/* mouse visible between cx and dx */
	regs.x.dx = 639;
	regs.x.ax = 7;
	(void)int86(0x33, &regs, &regs);
	regs.x.cx = 0;	/* mouse visible between cx and dx */
	regs.x.dx = mouse_y_max;
	regs.x.ax = 8;
	(void)int86(0x33, &regs, &regs);
    }
}

    static void
show_mouse(int on)
{
    static int	    was_on = FALSE;
    union REGS	    regs;

    if (mouse_avail)
    {
	if (!mouse_active || mouse_hidden)
	    on = FALSE;
	/*
	 * Careful: Each switch on must be compensated by exactly one switch
	 * off
	 */
	if (on && !was_on || !on && was_on)
	{
	    was_on = on;
	    regs.x.ax = on ? 1 : 2;
	    int86(0x33, &regs, &regs);	/* show mouse */
	    if (on)
		mouse_area();
	}
    }
}

#endif

#ifdef DJGPP
/*
 * DJGPP provides a kbhit() function that goes to the BIOS instead of DOS.
 * This doesn't work for terminals connected to a serial port.
 * Redefine kbhit() here to make it work.
 */
    static int
vim_kbhit(void)
{
    union REGS regs;

    regs.h.ah = 0x0b;
    (void)intdos(&regs, &regs);
    return regs.h.al;
}

#ifdef kbhit
# undef kbhit	    /* might have been defined in conio.h */
#endif

#define kbhit()	vim_kbhit()
#endif

/*
 * Simulate WaitForChar() by slowly polling with bioskey(1) or kbhit().
 *
 * If Vim should work over the serial line after a 'ctty com1' we must use
 * kbhit() and getch(). (jw)
 * Usually kbhit() is not used, because then CTRL-C and CTRL-P
 * will be catched by DOS (mool).
 *
 * return TRUE if a character is available, FALSE otherwise
 */

#define FOREVER 1999999999L

    static  int
WaitForChar(long msec)
{
    union REGS	regs;
    long	starttime;
    int		x, y;

    starttime = biostime(0, 0L);

    for (;;)
    {
#ifdef USE_MOUSE
	long		clicktime;
	static int	last_status = 0;

	if (mouse_avail && mouse_active && mouse_click < 0)
	{
	    regs.x.ax = 3;
	    int86(0x33, &regs, &regs);	    /* check mouse status */
		/* only recognize button-down and button-up event */
	    x = regs.x.cx / mouse_x_div;
	    y = regs.x.dx / mouse_y_div;
	    if ((last_status == 0) != (regs.x.bx == 0))
	    {
		if (last_status)	/* button up */
		    mouse_click = MOUSE_RELEASE;
		else			/* button down */
		{
		    /*
		     * Translate MSDOS mouse events to Vim mouse events.
		     * TODO: should handle middle mouse button, by pressing
		     * left and right at the same time.
		     */
		    if (regs.x.bx & MSDOS_MOUSE_LEFT)
			mouse_click = MOUSE_LEFT;
		    else if (regs.x.bx & MSDOS_MOUSE_RIGHT)
			mouse_click = MOUSE_RIGHT;
		    else if (regs.x.bx & MSDOS_MOUSE_MIDDLE)
			mouse_click = MOUSE_MIDDLE;

		    /*
		     * Find out if this is a multi-click
		     */
		    clicktime = biostime(0, 0L);
		    if (mouse_click_x == x && mouse_click_y == y &&
			    mouse_topline == curwin->w_topline &&
			    mouse_click_count != 4 &&
			    mouse_click == mouse_last_click &&
			    clicktime < mouse_click_time + p_mouset / BIOSTICK)
			++mouse_click_count;
		    else
			mouse_click_count = 1;
		    mouse_click_time = clicktime;
		    mouse_last_click = mouse_click;
		    mouse_click_x = x;
		    mouse_click_y = y;
		    mouse_topline = curwin->w_topline;
		    SET_NUM_MOUSE_CLICKS(mouse_click, mouse_click_count);
		}
	    }
	    else if (last_status && (x != mouse_x || y != mouse_y))
		mouse_click = MOUSE_DRAG;
	    last_status = regs.x.bx;
	    if (mouse_hidden && mouse_x >= 0 && (mouse_x != x || mouse_y != y))
	    {
		mouse_hidden = FALSE;
		show_mouse(TRUE);
	    }
	    mouse_x = x;
	    mouse_y = y;
	}
#endif

	if ((p_biosk ? bioskey(1) : kbhit()) || cbrk_pressed
#ifdef USE_MOUSE
						    || mouse_click >= 0
#endif
		)
	    return TRUE;
	/*
	 * Use biostime() to wait until our time is done.
	 * We busy-wait here.  Unfortunately, delay() and usleep() have been
	 * reported to give problems with the original Windows 95.  This is
	 * fixed in service pack 1, but not everybody installed that.
	 */
	if (msec != FOREVER && biostime(0, 0L) > starttime + msec / BIOSTICK)
	    break;
    }
    return FALSE;
}

/*
 * don't do anything for about "msec" msec
 */
    void
mch_delay(
    long	msec,
    int		ignoreinput)
{
    long	starttime;

    if (ignoreinput)
    {
	/*
	 * We busy-wait here.  Unfortunately, delay() and usleep() have been
	 * reported to give problems with the original Windows 95.  This is
	 * fixed in service pack 1, but not everybody installed that.
	 */
	starttime = biostime(0, 0L);
	while (biostime(0, 0L) < starttime + msec / BIOSTICK)
	    ;
    }
    else
	WaitForChar(msec);
}

/*
 * this version of remove is not scared by a readonly (backup) file
 *
 * returns -1 on error, 0 otherwise (just like remove())
 */
    int
mch_remove(char_u *name)
{
    (void)mch_setperm(name, 0);    /* default permissions */
    return unlink((char *)name);
}

/*
 * mch_write(): write the output buffer to the screen
 */
    void
mch_write(
    char_u	*s,
    int		len)
{
    char_u	*p;
    int		row, col;

    if (term_console)	    /* translate ESC | sequences into bios calls */
	while (len--)
	{
	    if (p_wd)	    /* testing: wait a bit for each char */
		WaitForChar(p_wd);

	    if (s[0] == '\n')
		myputch('\r');
	    else if (s[0] == ESC && len > 1 && s[1] == '|')
	    {
		switch (s[2])
		{
#ifdef DJGPP
		case 'B':   ScreenVisualBell();
			    goto got3;
#endif
		case 'J':   clrscr();
			    goto got3;

		case 'K':   clreol();
			    goto got3;

		case 'L':   insline();
			    goto got3;

		case 'M':   delline();
got3:			    s += 3;
			    len -= 2;
			    continue;

		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':   p = s + 2;
			    row = getdigits(&p);    /* no check for length! */
			    if (p > s + len)
				break;
			    if (*p == ';')
			    {
				++p;
				col = getdigits(&p); /* no check for length! */
				if (p > s + len)
				    break;
				if (*p == 'H' || *p == 'r')
				{
				    if (*p == 'H')  /* set cursor position */
					mygotoxy(col, row);
				    else	    /* set scroll region  */
					mywindow(1, row, Columns, col);
				    len -= p - s;
				    s = p + 1;
				    continue;
				}
			    }
			    else if (*p == 'm' || *p == 'f' || *p == 'b')
			    {
				if (*p == 'm')	    /* set color */
				{
				    if (row == 0)
					mynormvideo();/* reset color */
				    else
					mytextattr(row);
				}
				else if (*p == 'f') /* set foreground color */
				    mytextcolor(row);
				else		    /* set background color */
				    mytextbackground(row);

				len -= p - s;
				s = p + 1;
				continue;
			    }
		}
	    }
	    myputch(*s++);
	}
    else
	write(1, s, (unsigned)len);
}

/*
 * mch_inchar(): low level input funcion.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -