diff options
Diffstat (limited to 'src/os_msdos.c')
-rw-r--r-- | src/os_msdos.c | 3086 |
1 files changed, 0 insertions, 3086 deletions
diff --git a/src/os_msdos.c b/src/os_msdos.c deleted file mode 100644 index 5596e346d..000000000 --- a/src/os_msdos.c +++ /dev/null @@ -1,3086 +0,0 @@ -/* 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. - * See README.txt for an overview of the Vim source code. - */ - -/* - * 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) - * Windows clipboard functionality added by David Kotchan (dk) - * - * Some functions are also used for Win16 (MS-Windows 3.1). - */ - -#include "vim.h" - -/* cproto fails on missing include files */ -#ifndef PROTO -# include <conio.h> -#endif - -#ifndef PROTO -# include <bios.h> -# ifdef DJGPP -# include <dpmi.h> -# include <signal.h> -# include <sys/movedata.h> -# include <crt0.h> -# ifdef FEAT_CLIPBOARD -# include <sys/segments.h> -# endif -# else -# include <alloc.h> -# endif -#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 */ - -static int bioskey_read = _NKEYBRD_READ; /* bioskey() argument: read key */ -static int bioskey_ready = _NKEYBRD_READY; /* bioskey() argument: key ready? */ - -#ifdef FEAT_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 coordinate */ -static int mouse_y = -1; /* mouse y coordinate */ -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; /* w_topline at previous mouse click */ -#ifdef FEAT_DIFF -static int mouse_topfill = 0; /* w_topfill at previous mouse click */ -#endif -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 */ - -static int orig_attr = 0x0700; /* video attributes when starting */ - -static int S_iLeft = 0; /* Scroll window; these are 1 offset */ -static int S_iTop = 0; -static int S_iRight = 0; -static int S_iBottom = 0; - -/* - * Need to remember the values, because we set horizontal and vertical - * edges separately. - */ - 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); -} - -#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 = 0; -int S_iCurrentRow = 0; /* These are 0 offset */ -int S_iCurrentColumn = 0; -short S_selVideo; /* Selector for DJGPP direct video transfers */ - -/* - * Use burst writes to improve mch_write speed - VJN 01/10/99 - */ -unsigned short S_linebuffer[8000]; /* <VN> enough for 160x50 */ -unsigned short S_blankbuffer[256]; /* <VN> max length of console line */ -unsigned short *S_linebufferpos = S_linebuffer; -int S_iBufferRow; -int S_iBufferColumn; - - static void -myflush(void) -{ - if (S_linebufferpos != S_linebuffer) - { - _dosmemputw(S_linebuffer, (S_linebufferpos - S_linebuffer), - S_ulScreenBase - + S_iBufferRow * (Columns << 1) + (S_iBufferColumn << 1)); - S_linebufferpos = S_linebuffer; - } -} - - static void -mygotoxy(int x, int y) -{ - S_iCurrentRow = y - 1; - S_iCurrentColumn = x - 1; -} - -/* - * Set the system cursor to our cursor position. - */ - static void -set_sys_cursor(void) -{ - if (term_console && full_screen) - { - myflush(); - gotoxy(S_iCurrentColumn + 1, S_iCurrentRow + 1); - } -} - - static void -setblankbuffer(unsigned short uiValue) -{ - int i; - static unsigned short olduiValue = 0; - - if (olduiValue != uiValue) - { - /* Load blank line buffer with spaces */ - for (i = 0; i < Columns; ++i) - S_blankbuffer[i] = uiValue; - olduiValue = uiValue; - } -} - - static void -myclreol(void) -{ - /* Clear to end of line */ - setblankbuffer(S_uiAttribute | ' '); - _dosmemputw(S_blankbuffer, S_iRight - S_iCurrentColumn, S_ulScreenBase - + (S_iCurrentRow) * (Columns << 1) - + (S_iCurrentColumn << 1)); -} - - static void -myclrscr(void) -{ - /* Clear whole screen */ - short iColumn; - int endpoint = (Rows * Columns) << 1; - - setblankbuffer(S_uiAttribute | ' '); - - for (iColumn = 0; iColumn < endpoint; iColumn += (Columns << 1)) - _dosmemputw(S_blankbuffer, Columns, S_ulScreenBase + iColumn); -} - - static void -mydelline(void) -{ - short iRow, iColumn; - - iColumn = (S_iLeft - 1) << 1; - - /* Copy the lines underneath */ - for (iRow = S_iCurrentRow; iRow < S_iBottom - 1; iRow++) - movedata(S_selVideo, (((iRow + 1) * Columns) << 1) + iColumn, - S_selVideo, ((iRow * Columns) << 1) + iColumn, - (S_iRight - S_iLeft + 1) << 1); - - /* Clear the new row */ - setblankbuffer(S_uiAttribute | ' '); - - _dosmemputw(S_blankbuffer, (S_iRight - S_iLeft) + 1, S_ulScreenBase - + (S_iBottom - 1) * (Columns << 1) + iColumn); -} - - static void -myinsline(void) -{ - short iRow, iColumn; - - iColumn = (S_iLeft - 1) << 1; - - /* Copy the lines underneath */ - for (iRow = S_iBottom - 1; iRow >= S_iTop; iRow--) - movedata(S_selVideo, (((iRow - 1) * Columns) << 1) + iColumn, - S_selVideo, ((iRow * Columns) << 1) + iColumn, - (S_iRight - S_iLeft + 1) << 1); - - /* Clear the new row */ - setblankbuffer(S_uiAttribute | ' '); - - _dosmemputw(S_blankbuffer, (S_iRight - S_iLeft) + 1, S_ulScreenBase - + (S_iTop - 1) * (Columns << 1) + iColumn); -} - -/* - * Scroll the screen one line up, clear the last line. - */ - static void -myscroll(void) -{ - short iRow, iColumn; - - iColumn = (S_iLeft - 1) << 1; - - /* Copy the screen */ - for (iRow = S_iTop; iRow < S_iBottom; iRow++) - movedata(S_selVideo, ((iRow * Columns) << 1) + iColumn, - S_selVideo, (((iRow - 1) * Columns) << 1) + iColumn, - (S_iRight - S_iLeft + 1) << 1); - - /* Clear the bottom row */ - setblankbuffer(S_uiAttribute | ' '); - - _dosmemputw(S_blankbuffer, (S_iRight - S_iLeft) + 1, S_ulScreenBase - + (S_iBottom - 1) * (Columns << 1) + iColumn); -} - - static int -myputch(int iChar) -{ - unsigned short uiValue; - - if (iChar == '\n') - { - myflush(); - if (S_iCurrentRow >= S_iBottom - S_iTop) - myscroll(); - else - { - S_iCurrentColumn = S_iLeft - 1; - S_iCurrentRow++; - } - } - else if (iChar == '\r') - { - myflush(); - S_iCurrentColumn = S_iLeft - 1; - } - else if (iChar == '\b') - { - myflush(); - if (S_iCurrentColumn >= S_iLeft) - S_iCurrentColumn--; - } - else if (iChar == 7) - { - sound(440); /* short beep */ - delay(200); - nosound(); - } - else - { - uiValue = S_uiAttribute | (unsigned char)iChar; - - /* - * Normal char - are we starting to buffer? - */ - if (S_linebufferpos == S_linebuffer) - { - S_iBufferColumn = S_iCurrentColumn; - S_iBufferRow = S_iCurrentRow; - } - - *S_linebufferpos++ = uiValue; - - S_iCurrentColumn++; - if (S_iCurrentColumn >= S_iRight && S_iCurrentRow >= S_iBottom - S_iTop) - { - myflush(); - myscroll(); - S_iCurrentColumn = S_iLeft - 1; - S_iCurrentRow++; - } - } - - return 0; -} - - static void -mytextinit(struct text_info *pTextinfo) -{ - S_selVideo = __dpmi_segment_to_descriptor(S_ulScreenBase >> 4); - S_uiAttribute = pTextinfo->normattr << 8; -} - - 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, ®s, ®s); /* int 10 0f */ - if (regs.h.al == 0x07) /* video mode 7 -- hercules mono */ - S_ulScreenBase = 0xb0000; - else - S_ulScreenBase = 0xb8000; -} - - static void -mytextattr(int iAttribute) -{ - S_uiAttribute = (unsigned short)iAttribute << 8; -} - - static void -mynormvideo(void) -{ - mytextattr(orig_attr); -} - - static void -mytextcolor(int iTextColor) -{ - S_uiAttribute = (unsigned short)((S_uiAttribute & 0xf000) - | (unsigned short)iTextColor << 8); -} - - static void -mytextbackground(int iBkgColor) -{ - S_uiAttribute = (unsigned short)((S_uiAttribute & 0x0f00) - | (unsigned short)(iBkgColor << 12)); -} -/* - * Getdigits: Get a number from a string and skip over it. - * Note: the argument is a pointer to a char_u pointer! - */ - - static long -mygetdigits(char_u **pp) -{ - char_u *p; - long retval = 0; - - p = *pp; - if (*p == '-') /* skip negative sign */ - ++p; - while (VIM_ISDIGIT(*p)) - { - retval = (retval * 10) + (*p - '0'); - ++p; - } - if (**pp == '-') /* process negative sign */ - retval = -retval; - - *pp = p; - return retval; -} -#else -# define mygotoxy gotoxy -# define myputch putch -# define myscroll scroll -# define mynormvideo normvideo -# define mytextattr textattr -# define mytextcolor textcolor -# define mytextbackground textbackground -# define mygetdigits getdigits -# define myclreol clreol -# define myclrscr clrscr -# define myinsline insline -# define mydelline delline -#endif - -static const struct -{ - char_u scancode; - char_u metakey; -} altkey_table[] = -{ - {0x1e, 0xe1}, /* a */ - {0x30, 0xe2}, /* b */ - {0x2e, 0xe3}, /* c */ - {0x20, 0xe4}, /* d */ - {0x12, 0xe5}, /* e */ - {0x21, 0xe6}, /* f */ - {0x22, 0xe7}, /* g */ - {0x23, 0xe8}, /* h */ - {0x17, 0xe9}, /* i */ - {0x24, 0xea}, /* j */ - {0x25, 0xeb}, /* k */ - {0x26, 0xec}, /* l */ - {0x32, 0xed}, /* m */ - {0x31, 0xee}, /* n */ - {0x18, 0xef}, /* o */ - {0x19, 0xf0}, /* p */ - {0x10, 0xf1}, /* q */ - {0x13, 0xf2}, /* r */ - {0x1f, 0xf3}, /* s */ - {0x14, 0xf4}, /* t */ - {0x16, 0xf5}, /* u */ - {0x2f, 0xf6}, /* v */ - {0x11, 0xf7}, /* w */ - {0x2d, 0xf8}, /* x */ - {0x15, 0xf9}, /* y */ - {0x2c, 0xfa}, /* z */ - {0x78, 0xb1}, /* 1 */ - {0x79, 0xb2}, /* 2 */ - {0x7a, 0xb3}, /* 3 */ - {0x7b, 0xb4}, /* 4 */ - {0x7c, 0xb5}, /* 5 */ - {0x7d, 0xb6}, /* 6 */ - {0x7e, 0xb7}, /* 7 */ - {0x7f, 0xb8}, /* 8 */ - {0x80, 0xb9}, /* 9 */ - {0x81, 0xb0}, /* 0 */ -}; - -/* - * Translate extended keycodes into meta-chars where applicable - */ - static int -translate_altkeys(int rawkey) -{ - int i, c; - - if ((rawkey & 0xff) == 0) - { - c = (rawkey >> 8); - for (i = sizeof(altkey_table) / sizeof(altkey_table[0]); --i >= 0; ) - { - if (c == altkey_table[i].scancode) - return (int)altkey_table[i].metakey; - } - } - return rawkey; -} - -/* - * Set normal fg/bg color, based on T_ME. Called when t_me has been set. - */ - void -mch_set_normal_colors(void) -{ - char_u *p; - int n; - - cterm_normal_fg_color = (orig_attr & 0xf) + 1; - cterm_normal_bg_color = ((orig_attr >> 4) & 0xf) + 1; - if (T_ME[0] == ESC && T_ME[1] == '|') - { - p = T_ME + 2; - n = getdigits(&p); - if (*p == 'm' && n > 0) - { - cterm_normal_fg_color = (n & 0xf) + 1; - cterm_normal_bg_color = ((n >> 4) & 0xf) + 1; - } - } -} - -#if defined(MCH_CURSOR_SHAPE) || defined(PROTO) -/* - * 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, ®s, ®s); -} - -/* - * 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, ®s, ®s); -} - - void -mch_update_cursor(void) -{ - int idx; - int thickness; - - /* - * How the cursor is drawn depends on the current mode. - */ - idx = get_shape_idx(FALSE); - - if (shape_table[idx].shape == SHAPE_BLOCK) - thickness = 7; - else - thickness = (7 * shape_table[idx].percentage + 90) / 100; - mch_set_cursor_shape(thickness); -} -#endif - -/* - * Return amount of memory currently available in Kbyte. - */ - long_u -mch_avail_mem(int special) -{ -#ifdef DJGPP - return _go32_dpmi_remaining_virtual_memory() >> 10; -#else - return coreleft() >> 10; -#endif -} - -#ifdef FEAT_MOUSE - -/* - * Set area where mouse can be moved to: The whole screen. - * Rows and Columns must be valid when calling! - */ - static void -mouse_area(void) -{ - union REGS regs; - - if (mouse_avail) - { - regs.x.cx = 0; /* mouse visible between cx and dx */ - regs.x.dx = Columns * mouse_x_div - 1; - regs.x.ax = 7; - (void)int86(0x33, ®s, ®s); - - regs.x.cx = 0; /* mouse visible between cx and dx */ - regs.x.dx = Rows * mouse_y_div - 1; - regs.x.ax = 8; - (void)int86(0x33, ®s, ®s); - } -} - - 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, ®s, ®s); /* show mouse */ - if (on) - mouse_area(); - } - } -} - -#endif - -/* - * Version of kbhit() and getch() that use direct console I/O. - * This avoids trouble with CTRL-P and the like, and should work over a telnet - * connection (it works for Xvi). - */ - -static int cons_key = -1; - -/* - * Try to get one character directly from the console. - * If there is a key, it is stored in cons_key. - * Only call when cons_key is -1! - */ - static void -cons_getkey(void) -{ - union REGS regs; - - /* call DOS function 6: Direct console I/O */ - regs.h.ah = 0x06; - regs.h.dl = 0xff; - (void)intdos(®s, ®s); - if ((regs.x.flags & 0x40) == 0) /* zero flag not set? */ - cons_key = (regs.h.al & 0xff); -} - -/* - * Return TRUE if a character is available. - */ - static int -cons_kbhit(void) -{ - if (cons_key < 0) - cons_getkey(); - return (cons_key >= 0); -} - -/* - * Return a character from the console. - * Should only be called when vim_kbhit() returns TRUE. - */ - static int -cons_getch(void) -{ - int c = -1; - - if (cons_key < 0) - cons_getkey(); - c = cons_key; - cons_key = -1; - return c; -} - - -#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(®s, ®s); - 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 caught by DOS (mool). - * - * return TRUE if a character is available, FALSE otherwise - */ - -#define FOREVER 1999999999L - - static int -WaitForChar(long msec) -{ - long starttime = 0; - - if (msec != 0) - starttime = biostime(0, 0L); - - for (;;) - { -#ifdef FEAT_MOUSE - long clicktime; - static int old_status = 0; - union REGS regs; - int x, y; - - if (mouse_avail && mouse_active && mouse_click < 0) - { - regs.x.ax = 3; - int86(0x33, ®s, ®s); /* 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 ((old_status == 0) != (regs.x.bx == 0)) - { - if (old_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 -#ifdef FEAT_DIFF - && mouse_topfill == curwin->w_topfill -#endif - && 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; -#ifdef FEAT_DIFF - mouse_topfill = curwin->w_topfill; -#endif - SET_NUM_MOUSE_CLICKS(mouse_click, mouse_click_count); - } - } - else if (old_status && (x != mouse_x || y != mouse_y)) - mouse_click = MOUSE_DRAG; - old_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_consk ? cons_kbhit() - : p_biosk ? bioskey(bioskey_ready) : kbhit()) - || cbrk_pressed -#ifdef FEAT_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. - * The DJGPP implementation of usleep() uses a busy-wait loop too. - */ - if (msec == 0 || (msec != FOREVER - && biostime(0, 0L) > starttime + msec / BIOSTICK)) - break; - -#ifdef DJGPP - /* Yield the CPU to the next process. */ - __dpmi_yield(); -#endif - } - 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); -} - -/* - * 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 && full_screen) - while (len--) - { - /* translate ESC | sequences into bios calls */ - if (p_wd) /* testing: wait a bit for each char */ - WaitForChar(p_wd); - - if (s[0] == '\n') -#ifdef DJGPP - { - myflush(); - S_iCurrentColumn = S_iLeft - 1; - } -#else - myputch('\r'); -#endif - else if (s[0] == ESC && len > 1 && s[1] == '|') - { - switch (s[2]) - { -#ifdef DJGPP - case 'B': ScreenVisualBell(); - goto got3; -#endif - case 'J': -#ifdef DJGPP - myflush(); -#endif - myclrscr(); - goto got3; - - case 'K': -#ifdef DJGPP - myflush(); -#endif - myclreol(); - goto got3; - - case 'L': -#ifdef DJGPP - myflush(); -#endif - myinsline(); - goto got3; - - case 'M': -#ifdef DJGPP - myflush(); -#endif - mydelline(); -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 = mygetdigits(&p); /* no check for length! */ - if (p > s + len) - break; - if (*p == ';') - { - ++p; - col = mygetdigits(&p); /* no check for length! */ - if (p > s + len) - break; - if (*p == 'H' || *p == 'r' || *p == 'V') - { -#ifdef DJGPP - myflush(); -#endif - if (*p == 'H') /* set cursor position */ - mygotoxy(col, row); - else if (*p == 'V') - mywindow(row, S_iTop, col, S_iBottom); - else /* set scroll region */ - mywindow(S_iLeft, row, S_iRight, 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 function. - * Get a characters from the keyboard. - * If time == 0 do not wait for characters. - * If time == n wait a short time for characters. - * If time == -1 wait forever for characters. - * - * return the number of characters obtained - */ - int -mch_inchar( - char_u *buf, - int maxlen, - long time, - int tb_change_cnt) -{ - int len = 0; - int c; - int tmp_c; - static int nextchar = 0; /* may keep character when maxlen == 1 */ - - /* - * if we got a ctrl-C when we were busy, there will be a "^C" somewhere - * on the screen, so we need to redisplay it. - */ - if (delayed_redraw) - { - delayed_redraw = FALSE; - update_screen(CLEAR); - setcursor(); - out_flush(); - } - - /* return remaining character from last call */ - if (nextchar) - { - *buf = nextchar; - nextchar = 0; - return 1; - } - -#ifdef FEAT_MOUSE - if (time != 0) - show_mouse(TRUE); -#endif -#ifdef DJGPP - set_sys_cursor(); -#endif - if (time >= 0) - { - if (WaitForChar(time) == 0) /* no character available */ - { -#ifdef FEAT_MOUSE - show_mouse(FALSE); -#endif - return 0; - } - } - else /* time == -1 */ - { - /* - * If there is no character available within 2 seconds (default) - * write the autoscript file to disk. Or cause the CursorHold event - * to be triggered. - */ - if (WaitForChar(p_ut) == 0) - { -#ifdef FEAT_AUTOCMD - if (trigger_cursorhold() && maxlen >= 3) - { - buf[0] = K_SPECIAL; - buf[1] = KS_EXTRA; - buf[2] = (int)KE_CURSORHOLD; - return 3; - } -#endif - before_blocking(); - } - } - WaitForChar(FOREVER); /* wait for key or mouse click */ - -/* - * Try to read as many characters as there are, until the buffer is full. - */ - /* - * we will get at least one key. Get more if they are available - * After a ctrl-break we have to read a 0 (!) from the buffer. - * bioskey(1) will return 0 if no key is available and when a - * ctrl-break was typed. When ctrl-break is hit, this does not always - * implies a key hit. - */ - cbrk_pressed = FALSE; -#ifdef FEAT_MOUSE - if (mouse_click >= 0 && maxlen >= 5) - { - len = 5; - *buf++ = ESC + 128; - *buf++ = 'M'; - *buf++ = mouse_click; - *buf++ = mouse_x + '!'; - *buf++ = mouse_y + '!'; - mouse_click = -1; - } - else -#endif - { -#ifdef FEAT_MOUSE - mouse_hidden = TRUE; -#endif - if (p_biosk && !p_consk) - { - while ((len == 0 || bioskey(bioskey_ready)) && len < maxlen) - { - c = translate_altkeys(bioskey(bioskey_read)); /* get the key */ - /* - * translate a few things for inchar(): - * 0x0000 == CTRL-break -> 3 (CTRL-C) - * 0x0300 == CTRL-@ -> NUL - * 0xnn00 == extended key code -> K_NUL, nn - * 0xnne0 == enhanced keyboard -> K_NUL, nn - * K_NUL -> K_NUL, 3 - */ - if (c == 0) - c = 3; - else if (c == 0x0300) - c = NUL; - else if ((c & 0xff) == 0 - || c == K_NUL - || c == 0x4e2b - || c == 0x4a2d - || c == 0x372a - || ((c & 0xff) == 0xe0 && c != 0xe0)) - { - if (c == K_NUL) - c = 3; - else - c >>= 8; - *buf++ = K_NUL; - ++len; - } - - if (len < maxlen) - { - *buf++ = c; - len++; -#ifdef FEAT_MBYTE - /* Convert from 'termencoding' to 'encoding'. Only - * translate normal characters, not key codes. */ - if (input_conv.vc_type != CONV_NONE - && (len == 1 || buf[-2] != K_NUL)) - len += convert_input(buf - 1, 1, maxlen - len + 1) - 1; -#endif - } - else - nextchar = c; - } - } - else - { - while ((len == 0 || (p_consk ? cons_kbhit() : kbhit())) - && len < maxlen) - { - switch (c = (p_consk ? cons_getch() : getch())) - { - case 0: - /* NUL means that there is another character. - * Get it immediately, because kbhit() doesn't always - * return TRUE for the second character. - */ - if (p_consk) - c = cons_getch(); - else - c = getch(); - tmp_c = translate_altkeys(c << 8); - if (tmp_c == (c << 8)) - { - *buf++ = K_NUL; - ++len; - } - else - c = tmp_c; - break; - case K_NUL: - *buf++ = K_NUL; - ++len; - c = 3; - break; - case 3: - cbrk_pressed = TRUE; - /*FALLTHROUGH*/ - default: - break; - } - if (len < maxlen) - { - *buf++ = c; - ++len; - } - else - nextchar = c; - } - } - } -#ifdef FEAT_MOUSE - show_mouse(FALSE); -#endif - - beep_count = 0; /* may beep again now that we got some chars */ - return len; -} - -/* - * return non-zero if a character is available - */ - int -mch_char_avail(void) -{ - return WaitForChar(0L); -} - -#ifdef DJGPP -# define INT_ARG int -#else -# define INT_ARG -#endif - -/* - * function for ctrl-break interrupt - */ - static void interrupt -#ifdef DJGPP -catch_cbrk(int a) -#else -catch_cbrk(void) -#endif -{ - cbrk_pressed = TRUE; - ctrlc_pressed = TRUE; -} - -#ifndef DJGPP -/* - * ctrl-break handler for DOS. Never called when a ctrl-break is typed, because - * we catch interrupt 1b. If you type ctrl-C while Vim is waiting for a - * character this function is not called. When a ctrl-C is typed while Vim is - * busy this function may be called. By that time a ^C has been displayed on - * the screen, so we have to redisplay the screen. We can't do that here, - * because we may be called by DOS. The redraw is in mch_inchar(). - */ - static int _cdecl -cbrk_handler(void) -{ - delayed_redraw = TRUE; - return 1; /* resume operation after ctrl-break */ -} - -/* - * function for critical error interrupt - * For DOS 1 and 2 return 0 (Ignore). - * For DOS 3 and later return 3 (Fail) - */ - static void interrupt -catch_cint( - unsigned bp, - unsigned di, - unsigned si, - unsigned ds, - unsigned es, - unsigned dx, - unsigned cx, - unsigned bx, - unsigned ax) -{ - ax = (ax & 0xff00); /* set AL to 0 */ - if (_osmajor >= 3) - ax |= 3; /* set AL to 3 */ -} -#endif - -/* - * Set the interrupt vectors for use with Vim on or off. - * on == TRUE means as used within Vim - */ - static void -set_interrupts(int on) -{ - static int saved_cbrk; -#ifndef DJGPP - static void interrupt (*old_cint)(); -#endif - static void interrupt (*old_cbrk)(INT_ARG); - - if (on) - { - saved_cbrk = getcbrk(); /* save old ctrl-break setting */ - setcbrk(0); /* do not check for ctrl-break */ -#ifdef DJGPP - old_cbrk = signal(SIGINT, catch_cbrk); /* critical error interrupt */ -#else - old_cint = getvect(0x24); /* save old critical error interrupt */ - setvect(0x24, catch_cint); /* install our critical error interrupt */ - old_cbrk = getvect(0x1B); /* save old ctrl-break interrupt */ - setvect(0x1B, catch_cbrk); /* install our ctrl-break interrupt */ - ctrlbrk(cbrk_handler); /* vim's ctrl-break handler */ -#endif - if (term_console) - out_str(T_ME); /* set colors */ - } - else - { - setcbrk(saved_cbrk); /* restore ctrl-break setting */ -#ifdef DJGPP - signal(SIGINT,old_cbrk); /* critical error interrupt */ -#else - setvect(0x24, old_cint); /* restore critical error interrupt */ - setvect(0x1B, old_cbrk); /* restore ctrl-break interrupt */ -#endif - /* restore ctrl-break handler, how ??? */ - if (term_console) - mynormvideo(); /* restore screen colors */ - } -} - -/* - * We have no job control, fake it by starting a new shell. - */ - void -mch_suspend(void) -{ - suspend_shell(); -} - -extern int _fmode; - -/* - * Prepare window for use by Vim. - */ - void -mch_init(void) -{ - union REGS regs; - -#if defined(DJGPP) && defined(FEAT_CLIPBOARD) - __dpmi_regs dpmi_regs; -#endif - - /* - * Get the video attributes at the cursor. These will be used as the - * default attributes. - */ - regs.h.ah = 0x08; - regs.h.bh = 0x00; /* video page 0 */ - int86(0x10, ®s, ®s); - orig_attr = regs.h.ah; - mynormvideo(); - if (cterm_normal_fg_color == 0) - cterm_normal_fg_color = (orig_attr & 0xf) + 1; - if (cterm_normal_bg_color == 0) - cterm_normal_bg_color = ((orig_attr >> 4) & 0xf) + 1; - - term_console = TRUE; /* assume using the console for the things here */ - _fmode = O_BINARY; /* we do our own CR-LF translation */ - out_flush(); - set_interrupts(TRUE); /* catch interrupts */ - -#ifdef DJGPP - /* - * Use Long File Names by default, if $LFN not set. - */ - if (getenv("LFN") == NULL) - putenv("LFN=y"); - - get_screenbase(); -#endif - -#ifdef FEAT_MOUSE -/* find out if a MS compatible mouse is available */ - regs.x.ax = 0; - (void)int86(0x33, ®s, ®s); - mouse_avail = regs.x.ax; - /* best guess for mouse coordinate computations */ - mch_get_shellsize(); - if (Columns <= 40) - mouse_x_div = 16; - if (Rows == 30) - mouse_y_div = 16; -#endif - - /* - * Try switching to 16 colors for background, instead of 8 colors and - * blinking. Does this always work? Can the old value be restored? - */ - regs.x.ax = 0x1003; - regs.h.bl = 0x00; - regs.h.bh = 0x00; - int86(0x10, ®s, ®s); - - /* - * Test if we have an enhanced AT keyboard. Write 0xFFFF to the keyboard - * buffer and try to read it back. If we can't in 16 tries, it's an old - * type XT keyboard. - */ - regs.h.ah = 0x05; - regs.x.cx = 0xffff; - int86(0x16, ®s, ®s); - if (regs.h.al != 1) /* skip this when keyboard buffer is full */ - { - int i; - - for (i = 0; i < 16; ++i) - { - regs.h.ah = 0x10; - int86(0x16, ®s, ®s); - if (regs.x.ax == 0xffff) - break; - } - if (i == 16) /* 0xffff not read, must be old keyboard */ - { - bioskey_read = 0; - bioskey_ready = 1; - } - } - -#ifdef MCH_CURSOR_SHAPE - /* Save the old cursor shape */ - mch_restore_cursor_shape(FALSE); - /* Initialise the cursor shape */ - mch_update_cursor(); -#endif - -#if defined(DJGPP) && defined(FEAT_CLIPBOARD) - /* - * Check to see if the Windows clipboard is available, ie. are we - * running from a DOS session within Windows. Obviously, the Windows - * clipboard will not be available if we're running under pure DOS. - * - * int 0x2f, AX = 0x1700 identifies the Windows version we're running - * under. Upon return from the interrupt, if AX is unchanged, we're - * running under pure DOS and no Windows clipboard is available. - * - * Remark: could use int86() here but __dpmi_int() is recommended in - * the DJGPP docs, since int86() doesn't cover all available interrupts. - */ - dpmi_regs.x.ax = 0x1700; - if (__dpmi_int(0x2f, &dpmi_regs) == -1) - /* real-mode interrupt failed? */ - dpmi_regs.x.ax = 0x1700; /* force failure */ - - if (dpmi_regs.x.ax == 0x1700) /* no change in AX? */ - clip_init(FALSE); /* no clipboard available, too bad */ - else /* else, running under Windows, OK */ - clip_init(TRUE); /* clipboard is available */ -#endif -} - - int -mch_check_win( - int argc, - char **argv) -{ - /* store argv[0], may be used for $VIM */ - if (*argv[0] != NUL) - exe_name = FullName_save((char_u *)argv[0], FALSE); - - /* - * Try the DOS search path. The executable may in - * fact be called differently, so try this last. - */ - if (exe_name == NULL || *exe_name == NUL) - exe_name = searchpath("vim.exe"); - - if (isatty(1)) - return OK; - return FAIL; -} - -/* - * Return TRUE if the input comes from a terminal, FALSE otherwise. - */ - int -mch_input_isatty(void) -{ - if (isatty(read_cmd_fd)) - return TRUE; - return FALSE; -} - -#if defined(USE_FNAME_CASE) || defined(PROTO) -/* - * fname_case(): Set the case of the file name, if it already exists. - * TODO: should expand short to long file names. Need to use DOS interrupts, - * see DJGPP sources libc/dos/dir/findfirs.c. - */ - void -fname_case(char_u *name, int len) -{ - char_u *tail; - struct ffblk fb; - - slash_adjust(name); - if (findfirst(name, &fb, 0) == 0) - { - tail = gettail(name); - if (len == 0 ? STRLEN(tail) == STRLEN(fb.ff_name) - : (tail - name) + STRLEN(fb.ff_name) < len) - STRCPY(tail, fb.ff_name); - } -} -#endif - -/* - * return process ID - */ - long -mch_get_pid(void) -{ - return (long)0; -} - -/* - * Change default drive (just like _chdrive of Borland C 3.1) - */ - static int -change_drive(int drive) -{ - union REGS regs; - - regs.h.ah = 0x0e; - regs.h.dl = drive - 1; - intdos(®s, ®s); /* set default drive */ - regs.h.ah = 0x19; - intdos(®s, ®s); /* get default drive */ - if (regs.h.al == drive - 1) - return 0; - return -1; -} - -/* - * Get absolute file name into buffer 'buf' of length 'len' bytes. - * All slashes are replaced with backslashes, to avoid trouble when comparing - * file names. When 'shellslash' set do it the other way around. - * - * return FAIL for failure, OK otherwise - */ - int -mch_FullName( - char_u *fname, - char_u *buf, - int len, - int force) -{ - if (!force && mch_isFullName(fname)) /* already expanded */ - { - vim_strncpy(buf, fname, len - 1); - slash_adjust(buf); - return OK; - } - -#ifdef __BORLANDC__ /* Only Borland C++ has this */ - if (_fullpath((char *)buf, (char *)fname, len - 1) == NULL) - return FAIL; - return OK; -#else /* almost the same as mch_FullName() in os_unix.c */ - { -# if 1 - char_u fullpath[MAXPATHL]; - - if (!_truename(fname, fullpath)) - return FAIL; - slash_adjust(fullpath); /* Only needed when 'shellslash' set */ - vim_strncpy(buf, fullpath, len - 1); - return OK; - -# else /* Old code, to be deleted... */ - int l; - char_u olddir[MAXPATHL]; - char_u *p, *q; - int c; - int retval = OK; - - *buf = 0; - /* - * change to the directory for a moment, - * and then do the getwd() (and get back to where we were). - * This will get the correct path name with "../" things. - */ - p = vim_strrchr(fname, '/'); - q = vim_strrchr(fname, '\\'); - if (q != NULL && (p == NULL || q > p)) - p = q; - q = vim_strrchr(fname, ':'); - if (q != NULL && (p == NULL || q > p)) - p = q; - if (p != NULL) - { - if (getcwd(olddir, MAXPATHL) == NULL) - { - p = NULL; /* can't get current dir: don't chdir */ - retval = FAIL; - } - else - { - if (p == fname) /* /fname */ - q = p + 1; /* -> / */ - else if (q + 1 == p) /* ... c:\foo */ - q = p + 1; /* -> c:\ */ - else /* but c:\foo\bar */ - q = p; /* -> c:\foo */ - - c = *q; /* truncate at start of fname */ - *q = NUL; -# ifdef DJGPP - STRCPY(buf, fname); - slash_adjust(buf); /* needed when fname starts with \ */ - if (mch_chdir(buf)) /* change to the directory */ -# else - if (mch_chdir(fname)) /* change to the directory */ -# endif - retval = FAIL; - else - { - fname = q; - if (c == psepc) /* if we cut the name at a */ - fname++; /* '\', don't add it again */ - } - *q = c; - } - } - if (getcwd(buf, len) == NULL) - { - retval = FAIL; - *buf = NUL; - } -# ifdef USE_FNAME_CASE - else - { - char_u *head; - char_u *tail; - struct ffblk fb; - int c; - int added; - - /* Apparently "longna~1" isn't expanded by getcwd(), at least not - * for DJGPP. Expand it here. Have to do each dirname - * separately. */ - slash_adjust(buf); - head = buf; - if (isalpha(*head) && head[1] == ':') - head += 2; /* skip "c:" */ - while (*head != NUL) - { - /* Advance "head" to the start of a dirname and "tail" to just - * after it. */ - while (*head == '/' || *head == '\\') - ++head; - for (tail = head; *tail != NUL; ++tail) - if (*tail == '/' || *tail == '\\') - break; - c = *tail; - *tail = NUL; - - if (findfirst(buf, &fb, FA_DIREC) == 0) - { - added = STRLEN(fb.ff_name); - if ((head - buf) + added + STRLEN(tail + 1) + 2 < len) - { - added -= (tail - head); - if (added != 0) - STRMOVE(tail + 1 + added, tail + 1); - STRCPY(head, fb.ff_name); - tail += added; - } - } - *tail = c; - head = tail; - } - } -# endif - if (p != NULL) - mch_chdir(olddir); - /* - * Concatenate the file name to the path. - */ - if (*fname != NUL) - { - l = STRLEN(buf); - if (l > 0 && buf[l - 1] != '/' && buf[l - 1] != '\\') - strcat(buf, pseps); - strcat(buf, fname); - } - return retval; -# endif - } -#endif -} - -/* - * Replace all slashes by backslashes. - * This used to be the other way around, but MS-DOS sometimes has problems - * with slashes (e.g. in a command name). We can't have mixed slashes and - * backslashes, because comparing file names will not work correctly. The - * commands that use a file name should try to avoid the need to type a - * backslash twice. - * When 'shellslash' set do it the other way around. - */ - void -slash_adjust(char_u *p) -{ -#ifdef OLD_DJGPP /* this seems to have been fixed in DJGPP 2.01 */ - /* DJGPP can't handle a file name that starts with a backslash, and when it - * starts with a slash there should be no backslashes */ - if (*p == '\\' || *p == '/') - while (*p) - { - if (*p == '\\') - *p = '/'; - mb_ptr_adv(p); - } - else -#endif - while (*p) - { - if (*p == psepcN) - *p = psepc; - mb_ptr_adv(p); - } -} - -/* - * Return TRUE if "fname" does not depend on the current directory. - */ - int -mch_isFullName(char_u *fname) -{ - /* A name like "d:/foo" and "//server/share" is absolute */ - return (fname[0] != NUL && fname[1] == ':' - && (fname[2] == '/' || fname[2] == '\\')) - || (fname[0] == fname[1] && (fname[0] == '/' || fname[0] == '\\')); -} - - - void -mch_early_init(void) -{ -} - -/* - * Careful: mch_exit() may be called before mch_init()! - */ - void -mch_exit(int r) -{ - settmode(TMODE_COOK); - stoptermcap(); - set_interrupts(FALSE); /* restore interrupts */ -#ifdef DJGPP - set_sys_cursor(); -#endif - /* Somehow outputting CR-NL causes the original colors to be restored */ - out_char('\r'); - out_char('\n'); - out_flush(); - ml_close_all(TRUE); /* remove all memfiles */ -#ifdef MCH_CURSOR_SHAPE - mch_restore_cursor_shape(TRUE); -#endif - exit(r); -} - -/* - * set the tty in (raw) ? "raw" : "cooked" mode - * Does not change the tty, as bioskey() and kbhit() work raw all the time. - */ - void -mch_settmode(int tmode) -{ -} - -#ifdef FEAT_MOUSE - void -mch_setmouse(int on) -{ - mouse_active = on; - mouse_hidden = TRUE; /* don't show it until moved */ -} -#endif - -/* - * set screen mode - * return FAIL for failure, OK otherwise - */ - int -mch_screenmode(char_u *arg) -{ - int mode; - int i; - static char *(names[]) = {"BW40", "C40", "BW80", "C80", "MONO", "C4350"}; - static int modes[] = { BW40, C40, BW80, C80, MONO, C4350}; - - mode = -1; - if (VIM_ISDIGIT(*arg)) /* mode number given */ - mode = atoi((char *)arg); - else - { - for (i = 0; i < sizeof(names) / sizeof(char_u *); ++i) - if (stricmp(names[i], (char *)arg) == 0) - { - mode = modes[i]; - break; - } - } - if (mode == -1) - { - EMSG("E362: Unsupported screen mode"); - return FAIL; - } - textmode(mode); /* use Borland function */ -#ifdef DJGPP - /* base address may have changed */ - get_screenbase(); -#endif - - /* Screen colors may have changed. */ - out_str(T_ME); - -#ifdef FEAT_MOUSE - if (mode <= 1 || mode == 4 || mode == 5 || mode == 13 || mode == 0x13) - mouse_x_div = 16; - else - mouse_x_div = 8; - if (mode == 0x11 || mode == 0x12) - mouse_y_div = 16; - else if (mode == 0x10) - mouse_y_div = 14; - else - mouse_y_div = 8; - shell_resized(); -#endif - return OK; -} - -/* - * Structure used by Turbo-C/Borland-C to store video parameters. - */ -#ifndef DJGPP -extern struct text_info _video; -#endif - -/* - * try to get the real window size - * return FAIL for failure, OK otherwise - */ - int -mch_get_shellsize(void) -{ - struct text_info textinfo; - - /* - * The screenwidth is returned by the BIOS OK. - * The screenheight is in a location in the bios RAM, if the display is - * EGA or VGA. - */ - if (!term_console) - return FAIL; - gettextinfo(&textinfo); - Columns = textinfo.screenwidth; - Rows = textinfo.screenheight; -#ifndef DJGPP - if (textinfo.currmode > 10) - Rows = *(char far *)MK_FP(0x40, 0x84) + 1; -#endif - - if (Columns < MIN_COLUMNS || Rows < MIN_LINES) - { - /* these values are overwritten by termcap size or default */ - Columns = 80; - Rows = 25; - return FAIL; - } -#ifdef DJGPP - mytextinit(&textinfo); /* Added by JML, 1/15/98 */ -#endif - - return OK; -} - -/* - * Set the active window for delline/insline. - */ - static void -set_window(void) -{ - if (term_console) - { -#ifndef DJGPP - _video.screenheight = Rows; -#endif - mywindow(1, 1, Columns, Rows); - } - screen_start(); -} - - void -mch_set_shellsize(void) -{ - /* Should try to set the window size to Rows and Columns. - * May involve switching display mode.... - * We assume the user knows the size and just use it. */ -} - -/* - * Rows and/or Columns has changed. - */ - void -mch_new_shellsize(void) -{ -#ifdef FEAT_MOUSE - /* best guess for mouse coordinate computations */ - if (Columns <= 40) - mouse_x_div = 16; - if (Rows == 30) - mouse_y_div = 16; -#endif - set_window(); -#ifdef FEAT_MOUSE - mouse_area(); /* set area where mouse can go */ -#endif -} - -#if defined(DJGPP) || defined(PROTO) -/* - * Check the number of Columns with a BIOS call. This avoids a crash of the - * DOS console when 'columns' is set to a too large value. - */ - void -mch_check_columns(void) -{ - static union REGS regs; - - regs.h.ah = 0x0f; - (void)int86(0x10, ®s, ®s); - if ((unsigned)Columns > (unsigned)regs.h.ah) - Columns = (unsigned)regs.h.ah; -} -#endif - -/* - * call shell, return FAIL for failure, OK otherwise - * options: SHELL_*, see vim.h. - */ - int -mch_call_shell( - char_u *cmd, - int options) -{ - int x; - int tmode = cur_tmode; -#ifndef DJGPP - char_u *newcmd; -#endif - - out_flush(); -#ifdef DJGPP - set_sys_cursor(); -#endif - - if (options & SHELL_COOKED) - settmode(TMODE_COOK); /* set to normal mode */ - set_interrupts(FALSE); /* restore interrupts */ - -#ifdef DJGPP - /* ignore signals while external command is running */ - signal(SIGINT, SIG_IGN); - signal(SIGHUP, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTERM, SIG_IGN); -#endif - if (cmd == NULL) - x = system((char *)p_sh); - else - { -#ifdef DJGPP - /* - * Use 'shell' for system(). - */ - setenv("SHELL", (char *)p_sh, 1); - x = system(cmd); -#else - /* we use "command" to start the shell, slow but easy */ - newcmd = alloc(STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 3); - if (newcmd == NULL) - x = -1; - else - { - sprintf((char *)newcmd, "%s %s %s", p_sh, p_shcf, cmd); - x = system((char *)newcmd); - vim_free(newcmd); - } -#endif - } -#ifdef DJGPP - signal(SIGINT, SIG_DFL); - signal(SIGHUP, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTERM, SIG_DFL); -#endif - if (tmode == TMODE_RAW) - settmode(TMODE_RAW); /* set to raw mode */ - set_interrupts(TRUE); /* catch interrupts */ - - if (x && !(options & SHELL_SILENT) && !emsg_silent) - { - MSG_PUTS("\nshell returned "); - msg_outnum((long)x); - msg_putchar('\n'); - } - - return x; -} - -/* - * check for an "interrupt signal": CTRL-break or CTRL-C - */ - void -mch_breakcheck(void) -{ - if (ctrlc_pressed) - { - ctrlc_pressed = FALSE; - got_int = TRUE; - } -} - -/* - * Return TRUE if "p" contain a wildcard that can be expanded by - * dos_expandpath(). - */ - int -mch_has_exp_wildcard(char_u *p) -{ - for ( ; *p; mb_ptr_adv(p)) - { - if (vim_strchr((char_u *)"?*[", *p) != NULL - || (*p == '~' && p[1] != NUL)) - return TRUE; - } - return FALSE; -} - -/* - * Return TRUE if "p" contain a wildcard or a "~1" kind of thing (could be a - * shortened file name). - */ - int -mch_has_wildcard(char_u *p) -{ - for ( ; *p; mb_ptr_adv(p)) - { - if (vim_strchr((char_u *) -# ifdef VIM_BACKTICK - "?*$[`" -# else - "?*$[" -# endif - , *p) != NULL - || (*p == '~' && p[1] != NUL)) - return TRUE; - } - return FALSE; -} - -/* - * Change directory to "path". - * The normal chdir() does not change the default drive. This one does. - * Return 0 for success, -1 for failure. - */ - int -mch_chdir(char *path) -{ - if (path[0] == NUL) /* just checking... */ - return 0; - if (p_verbose >= 5) - { - verbose_enter(); - smsg((char_u *)"chdir(%s)", path); - verbose_leave(); - } - if (path[1] == ':') /* has a drive name */ - { - if (change_drive(TOLOWER_ASC(path[0]) - 'a' + 1)) - return -1; /* invalid drive name */ - path += 2; - } - if (*path == NUL) /* drive name only */ - return 0; - return chdir(path); /* let the normal chdir() do the rest */ -} - -#ifdef DJGPP -/* - * mch_rename() works around a bug in rename (aka MoveFile) in - * Windows 95: rename("foo.bar", "foo.bar~") will generate a - * file whose short file name is "FOO.BAR" (its long file name will - * be correct: "foo.bar~"). Because a file can be accessed by - * either its SFN or its LFN, "foo.bar" has effectively been - * renamed to "foo.bar", which is not at all what was wanted. This - * seems to happen only when renaming files with three-character - * extensions by appending a suffix that does not include ".". - * Windows NT gets it right, however, with an SFN of "FOO~1.BAR". - * This works like mch_rename in os_win32.c, but is a bit simpler. - * - * Like rename(), returns 0 upon success, non-zero upon failure. - * Should probably set errno appropriately when errors occur. - */ - - int -mch_rename(const char *OldFile, const char *NewFile) -{ - char_u *TempFile; - int retval; - int fd; - - /* rename() works correctly without long file names, so use that */ - if (!_USE_LFN) - return rename(OldFile, NewFile); - - if ((TempFile = alloc((unsigned)(STRLEN(OldFile) + 13))) == NULL) - return -1; - - STRCPY(TempFile, OldFile); - STRCPY(gettail(TempFile), "axlqwqhy.ba~"); - if (rename(OldFile, TempFile)) - retval = -1; - else - { - /* now create an empty file called OldFile; this prevents - * the operating system using OldFile as an alias (SFN) - * if we're renaming within the same directory. For example, - * we're editing a file called filename.asc.txt by its SFN, - * filena~1.txt. If we rename filena~1.txt to filena~1.txt~ - * (i.e., we're making a backup while writing it), the SFN - * for filena~1.txt~ will be filena~1.txt, by default, which - * will cause all sorts of problems later in buf_write(). So, we - * create an empty file called filena~1.txt and the system will have - * to find some other SFN for filena~1.txt~, such as filena~2.txt - */ - if ((fd = open(OldFile, O_RDWR|O_CREAT|O_EXCL, 0444)) < 0) - return -1; - retval = rename(TempFile, NewFile); - close(fd); - mch_remove((char_u *)OldFile); - - /* If renaming to NewFile failed, rename TempFile back to OldFile, so - * that it looks like nothing happened. */ - if (retval) - rename(TempFile, OldFile); - } - vim_free(TempFile); - - return retval; /* success */ -} -#endif - -#if defined(DJGPP) || defined(PROTO) -/* - * setlocale() for DJGPP with MS-DOS codepage support - * Author: Cyril Slobin <slobin@fe.msk.ru> - * - * Scaled down a lot for use by Vim: Only support setlocale(LC_ALL, ""). - */ - -#undef setlocale - -#ifndef PROTO -# include <go32.h> -# include <inlines/ctype.ha> -#endif -#include <locale.h> - -#define UPCASE (__dj_ISALNUM | __dj_ISALPHA | __dj_ISGRAPH | __dj_ISPRINT | __dj_ISUPPER) -#define LOCASE (__dj_ISALNUM | __dj_ISALPHA | __dj_ISGRAPH | __dj_ISPRINT | __dj_ISLOWER) - - char * -djgpp_setlocale(void) -{ - __dpmi_regs regs; - struct { char id; unsigned short off, seg; } __attribute__ ((packed)) info; - unsigned char buffer[0x82], lower, upper; - int i; - - regs.x.ax = 0x6502; - regs.x.bx = 0xffff; - regs.x.dx = 0xffff; - regs.x.cx = 5; - regs.x.es = __tb >> 4; - regs.x.di = __tb & 0xf; - - __dpmi_int(0x21, ®s); - - if (regs.x.flags & 1) - return NULL; - - dosmemget(__tb, 5, &info); - dosmemget((info.seg << 4) + info.off, 0x82, buffer); - - if (*(short *)buffer != 0x80) - return NULL; - - /* Fix problem of underscores being replaced with y-umlaut. (Levin) */ - if (buffer[26] == 0x5f) - buffer[26] = 0x98; - - for (i = 0; i < 0x80; i++) - { - lower = i + 0x80; - upper = (buffer+2)[i]; - if (lower != upper) - { - __dj_ctype_flags[lower+1] = LOCASE; - __dj_ctype_toupper[lower+1] = upper; - if (__dj_ctype_flags[upper+1] == 0) - __dj_ctype_flags[upper+1] = UPCASE; - if (__dj_ctype_tolower[upper+1] == upper) - __dj_ctype_tolower[upper+1] = lower; - } - } - - return "C"; -} - -#if defined(FEAT_CLIPBOARD) || defined(PROTO) - -/* - * Clipboard stuff, for cutting and pasting text to other windows. - * - * Implementation of DOS/Windows clipboard data transfer - * by David Kotchan (dkotchan@sympatico.ca) - */ - -#define CF_TEXT 0x01 /* Windows clipboard format: Windows (ANSI) text */ -#define CF_OEMTEXT 0x07 /* Windows clipboard format: OEM (DOS) text */ -#define CF_VIMCLIP 0x04 /* trick: SYLK clipboard format for VimClipboard */ - -static int Win16OpenClipboard(void); -static int Win16CloseClipboard(void); -static int Win16EmptyClipboard(void); -static char_u *Win16GetClipboardData(int clip_data_format); -static int Win16SetClipboardData(int clip_data_format, char_u *clip_data, int clip_data_size, int clip_data_type); - -/* - * Make vim the owner of the current selection. Return OK upon success. - */ - int -clip_mch_own_selection(VimClipboard *cbd) -{ - /* - * Never actually own the clipboard. If another application sets the - * clipboard, we don't want to think that we still own it. - */ - return FAIL; -} - -/* - * Make vim NOT the owner of the current selection. - */ - void -clip_mch_lose_selection(VimClipboard *cbd) -{ - /* Nothing needs to be done here */ -} - -/* - * Read the Windows clipboard text and put it in Vim's clipboard register. - */ - void -clip_mch_request_selection(VimClipboard *cbd) -{ - int type = MAUTO; - char_u *pAllocated = NULL; - char_u *pClipText = NULL; - int clip_data_format = 0; - - if (Win16OpenClipboard()) - { - /* Check for Vim's own clipboard format first. The CF_VIMCLIP format - * is just ordinary text (like CF_TEXT) except prepended by the - * selection type (as a single character). Note that under DOS we - * actually cannot define a custom CF_VIMCLIP clipboard format; we - * use instead one of the existing Windows-defined formats, usually - * "DIF" or "SYLK". See Win16GetClipboardData() for details. - * - * Note that Win16GetClipboardData() returns the address of the memory - * block it allocated. This is not necessary the start of the - * clipboard text data: there may be other bytes ahead of the - * text (particularly for CF_VIMCLIP) which are used for data - * management. So pClipText is not necessarily == pAllocated. - */ - - if ((pAllocated = Win16GetClipboardData(CF_VIMCLIP)) != NULL) - { - clip_data_format = CF_VIMCLIP; - pClipText = pAllocated; - - switch (*pClipText++) /* after ++, pClipText points to text */ - { - default: - case 'L': type = MLINE; break; - case 'C': type = MCHAR; break; - case 'B': type = MBLOCK; break; - } - } - - /* Otherwise, check for the normal Windows text formats. There are - * two of these: CF_TEXT (common) and CF_OEMTEXT (used for DOS - * compatibility). Experiments show that, under the DOS/Windows - * clipboard interface, writing CF_TEXT data to the clipboard - * automatically creates a CF_OEMTEXT format as well. - */ - - else if ((pAllocated = Win16GetClipboardData(CF_TEXT)) != NULL) - { - clip_data_format = CF_TEXT; - pClipText = pAllocated; - } - - else if ((pAllocated = Win16GetClipboardData(CF_OEMTEXT)) != NULL) - { - clip_data_format = CF_OEMTEXT; - pClipText = pAllocated; - } - - /* Did we get anything? */ - - if (pClipText != NULL) - { - char_u *pDest; - char_u *pStart; - char_u *pEnd; - - long_u clip_data_size = 0; - - /* The Windows clipboard normally stores its text lines terminated - * by <CR><NL>. But Vim uses only <NL>, so translate the <CR><NL> - * into <NL>. Also, watch for possible null bytes at the end of - * pClipText. These are padding added by "get_clipboard_data" - * (int 0x2f, AX= 0x1705) in order to round the data size up to the - * next multiple of 32 bytes. See Win16GetClipboardData() for - * details. - */ - - pDest = strstr( pClipText, "\r\n" ); /* find first <CR><NL> */ - - if (pDest != NULL) /* found one? */ - { - pStart = pDest + 1; /* points to <NL> after <CR> */ - pEnd = strstr( pStart, "\r\n" );/* find next <CR><NL> */ - - while (pEnd != NULL) /* found one? */ - { - memmove(pDest, pStart, (long)(pEnd - pStart)); - /* exclude <CR> */ - pDest += (long)(pEnd - pStart); /* new destination */ - pStart = pEnd + 1; /* new starting point */ - pEnd = strstr(pStart, "\r\n"); /* find next <CR><NL> */ - } - - /* Fell out of while() loop: no more <CR><NL> pairs. Just copy - * the rest of the data, up to the first null byte. */ - pEnd = strchr(pStart, '\0'); /* find first null */ - - memmove(pDest, pStart, (long)(pEnd - pStart)); /* exclude nul */ - pDest += (long)(pEnd - pStart); - *pDest = '\0'; /* terminate */ - - /* Now that all <CR><NL> pairs have been "compressed" into just - * <NL>'s, determine the true text length. */ - clip_data_size = (long_u)(pDest - pClipText); - } - else - { - /* no <CR><NL> pairs at all */ - /* Since the data may have been padded with trailing nulls, - * determine the true string length. */ - clip_data_size = STRLEN(pClipText); /* true data length */ - } - - /* Copy the cleaned-up data over to Vim's clipboard "*" register. */ - clip_yank_selection(type, pClipText, clip_data_size, cbd); - - /* Free the memory that Win16GetClipboardData() allocated. */ - vim_free(pAllocated); - } - - Win16CloseClipboard(); - - } // end if (Win16OpenClipboard()) -} - -/* - * Send the currently selected Vim text to the Windows clipboard. - */ - void -clip_mch_set_selection( VimClipboard *cbd ) -{ - char_u *pClipData = NULL; - long_u clip_data_size; - int clip_data_type; - - /* If the '*' register isn't already filled in, fill it in now. */ - cbd->owned = TRUE; - clip_get_selection(cbd); - cbd->owned = FALSE; - - /* - * clip_convert_selection() returns a pointer to a buffer containing - * the text to send to the Windows clipboard, together with a count - * of the number of characters (bytes) in the buffer. The function's - * return value is the 'type' of selection: MLINE, MCHAR, or MBLOCK; - * or -1 for failure. - */ - clip_data_type = clip_convert_selection(&pClipData, &clip_data_size, cbd); - - if (clip_data_type < 0) /* could not convert? */ - return; /* early exit */ - - if (Win16OpenClipboard()) - { - if (Win16EmptyClipboard()) - { - int sentOK; - - sentOK = Win16SetClipboardData(CF_TEXT, pClipData, - clip_data_size, clip_data_type); - sentOK = Win16SetClipboardData(CF_VIMCLIP, - pClipData, clip_data_size, clip_data_type) && sentOK; - - if (!sentOK) - { - /* one or both of Win16SetClipboardData() failed. */ - /* Technically we don't know why Win16SetClipboardData() - * failed, but almost always it will be because there wasn't - * enough DOS memory to buffer the data, so report that as the - * problem. - * - * We report the error here (instead of in - * Win16SetClipboardData()) because we don't want the error - * reported twice. - */ - EMSG("E450: Selection too large, cannot allocate DOS buffer"); - } - } - - Win16CloseClipboard(); - } - - /* release memory allocated by clip_convert_selection() */ - vim_free(pClipData); - - return; -} - -/* - * Win16OpenClipboard: open the Windows clipboard. The clipboard must be open - * before it can be communicated with at all. Return TRUE on success, - * FALSE on failure. - */ - static int -Win16OpenClipboard(void) -{ - __dpmi_regs dpmi_regs; - - long start_time; - int tick_count; - - /* int 0x2f, AX = 0x1701 attempts to open the Windows clipboard. Upon - * return from the interrupt, if AX is non-zero, the clipboard was - * successfully opened. If AX is zero, the clipboard could not be opened - * because it is currently in use by another process. - * - * Remark: other DOS programs I (dk) have written that use the Windows - * clipboard sometimes encounter the problem that the clipboard cannot - * be opened even though it is demonstrably not in use by any other - * process. In all cases, repeated attempts to open the clipboard - * eventually succeed, but the initial attempt occasionally fails. - * - * The problem is intermittent and appears to be related to DOS being - * "busy" at certain unpredictable times. DOS maintains two internal - * flags that indicate whether it's busy: InDOS and CritErr. The - * location of InDOS can be found by calling int 0x21, AH = 0x34. The - * location of CritErr can be found by calling int 0x21, AX = 0x5d06. - * If either of these flags is set, DOS is "busy" and cannot be - * interrupted. See "Undocumented DOS" by Schulman et al for details. - * - * However here I take the easier approach that if the first call to open - * the clipboard does not succeed, just try again. In fact, try once per - * biostime() clock tick, up to 18 times (about one second). - */ - - tick_count = 0; - - dpmi_regs.x.ax = 0x1701; /* open Windows clipboard */ - if (__dpmi_int(0x2f, &dpmi_regs) == -1) - { - /* real-mode interrupt failed? */ - return FALSE; /* FALSE --> clipboard not open */ - } - - /* wait up to one second */ - while (dpmi_regs.x.ax == 0 && tick_count++ < 18) - { - /* Wait one clock tick (18.2 ticks/sec = 55 msec per tick). - * - * 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. - */ - start_time = biostime(0, 0L); - while (biostime(0, 0L) == start_time) - ; - - dpmi_regs.x.ax = 0x1701; /* open Windows clipboard */ - if (__dpmi_int(0x2f, &dpmi_regs) == -1) - { - /* real-mode interrupt failed? */ - return FALSE; /* FALSE --> clipboard not open */ - } - } - - /* Couldn't open the clipboard, even after 18 attempts? */ - - if (tick_count >= 18 && dpmi_regs.x.ax == 0) - return FALSE; /* FALSE --> clipboard not open */ - - return TRUE; /* TRUE --> clipboard opened successfully, OK */ -} - -/* - * Win16CloseClipboard: close the Windows clipboard. Return TRUE on - * success, FALSE on failure. This function can always be called, - * whether the clipboard is open or not. - */ - static int -Win16CloseClipboard(void) -{ - __dpmi_regs dpmi_regs; - - /* Close the clipboard. This interrupt can always be called, even - * if the clipboard is already closed. - */ - - dpmi_regs.x.ax = 0x1708; /* close the clipboard */ - if (__dpmi_int(0x2f, &dpmi_regs) == -1) - { - /* real-mode interrupt failed? */ - return FALSE; /* FALSE --> clipboard could not be closed */ - } - - return TRUE; /* TRUE --> clipboard closed successfully, OK */ -} - -/* - * Win16EmptyClipboard: empty the (previously opened) Windows clipboard. - * Return TRUE on success, FALSE on failure. - */ - static int -Win16EmptyClipboard(void) -{ - __dpmi_regs dpmi_regs; - - /* int 0x2f, AX = 0x1702 attempts to empty the Windows clipboard. Upon - * return from the interrupt, if AX == 0, the clipboard could not be - * emptied (for some reason). - */ - dpmi_regs.x.ax = 0x1702; /* empty the Windows clipboard */ - if (__dpmi_int(0x2f, &dpmi_regs) == -1) - { - /* real-mode interrupt failed? */ - return FALSE; /* FALSE --> clipboard could not be emptied */ - } - - /* Did we succeed in clearing the clipboard? */ - if (dpmi_regs.x.ax == 0) - return FALSE; /* FALSE --> clipboard could not be emptied */ - - return TRUE; /* TRUE --> clipboard was emptied, OK */ -} - -/* - * FreeDOSMemory: a helper function to free memory previously - * allocated by a call to __dpmi_allocate_dos_memory(). - */ - static void -FreeDOSMemory(int protected_mode_selector) -{ - /* Free the DOS buffer and release the DPMI prot-mode selector. - * - * It's important that DOS memory be properly released because - * there's only a limited amount of it. Therefore, if the call - * to __dpmi_free_dos_memory() fails, emit an error message - * unconditionally. - */ - if (__dpmi_free_dos_memory(protected_mode_selector) == -1) - EMSG("E451: could not free DOS memory buffer (DJGPP)"); -} - -/* - * Win16GetClipboardData: query the Windows clipboard as to whether data - * is available in a particular clipboard format. If data is - * available, allocate a buffer for it and read the data from the - * clipboard into the buffer. Return a pointer to the buffer. If - * no data is available in the requested format, return NULL. - * - * This routine allocates memory to hold the retrieved clipboard - * data. It's the caller's responsibility to free this memory - * once it's finished using it. The memory should be freed by - * calling vim_free(). - */ - static char_u * -Win16GetClipboardData(int clip_data_format) -{ - __dpmi_regs dpmi_regs; - - int real_mode_segment_address; - int protected_mode_selector; - - char_u *clip_data_buffer; - long_u clip_data_size; - - /* We only handle clipboard formats we recognize, others are ignored. - * - * It's not possible to create a custom clipboard format for VimClipboard - * data under DOS, so one of the predefined Windows formats had to be - * used for CF_VIMCLIP. Two obscure formats, popular when Windows 3.0 - * came out but no longer in much use today, are the DIF and SYLK formats. - * DIF is the Data Interchange Format, SYLK is the Symbolic Link format. - * They are both text formats and either one can be hijacked for use as - * "the VimClipboard format". Of course, this conflicts with anyone who - * still *is* using DIF or SYLK data formats, but that will be very few - * people. - * - * I (dk) chose SYLK as the more obscure format because it was used - * mostly for Microsoft Multiplan (the pre-cursor to Excel) and it's not - * likely Multiplan is used anywhere much anymore. Mind you, Excel can - * still export to both DIF and SYLK formats. - */ - - switch (clip_data_format) - { - case CF_VIMCLIP: /* Vim's own special clipboard format */ - case CF_TEXT: /* Windows text */ - case CF_OEMTEXT: /* DOS (OEM) text */ - - /* int 0x2f, AX = 0x1704 returns the number of bytes of data currently - * on the Windows clipboard, for the specified format. Upon return - * from the interrupt, DX:AX = the number of bytes, rounded up to the - * nearest multiple of 32. - */ - - dpmi_regs.x.ax = 0x1704; /* get size of clipbd data */ - dpmi_regs.x.dx = clip_data_format; - if (__dpmi_int(0x2f, &dpmi_regs) == -1) - { - /* real-mode interrupt failed? */ - return NULL; /* early exit */ - } - - /* Did we get anything? If not, this is not an error. */ - if (dpmi_regs.x.dx == 0 && dpmi_regs.x.ax == 0) - { - /* no CF_VIMCLIP data? */ - return NULL; /* early exit */ - } - - /* There is data available in the requested clipboard format. - * - * Calculate data size. Remember this is rounded up to the nearest - * multiple of 32, so clip_data_size is actually an upper limit. - * The extra bytes, if any, are set to null (0x00) when the data is - * read from the clipboard. (Later:) actually I'm no longer sure - * this is strictly true: the end-of-data is marked by a null, but - * the extra bytes appear to sometimes be null, sometimes not. - * They may just be garbage. - */ - clip_data_size = dpmi_regs.x.ax + (dpmi_regs.x.dx << 16); - - /* Allocate memory to retrieve the data. The buffer has to lie in the - * DOS memory region (in the first 1 MByte of address space) because - * the Windows clipboard interface expects a 16-bit segment:offset - * pointer to a buffer address within the DOS region. Must therefore - * use __dpmi_allocate_dos_memory() instead of lalloc() or alloc(). - */ - real_mode_segment_address = __dpmi_allocate_dos_memory( - (clip_data_size + 15) >> 4, /* buffer size, in 16-byte paragraphs */ - &protected_mode_selector); /* prot-mode selector for the address */ - - if (real_mode_segment_address == -1) - { - /* memory allocation failed. */ - - /* Technically we don't know why the allocation failed, but - * almost always it will be because there wasn't enough DOS - * memory to satisfy the request, so report that as the problem. - * On my system, DJGPP is able to satisfy a DOS allocation request - * up to about 600K in size. This depends on your HIMEM.SYS and - * EMM386.EXE settings however. - */ - EMSG("E452: Clipboard data too large, cannot allocate DOS buffer"); - return NULL; /* early exit */ - } - - /* Copy data from the clipboard into the buffer. Experiments show that - * the Windows clipboard is smart enough to handle data transfers - * larger than 64K properly, even though the buffer address is a 16-bit - * segment:offset (which would normally limit the block size to 64K - * unless ES gets incremented). - */ - dpmi_regs.x.ax = 0x1705; /* get clipboard data */ - dpmi_regs.x.dx = clip_data_format; /* CF_VIMCLIP */ - dpmi_regs.x.es = real_mode_segment_address; /* buffer ad: segment */ - dpmi_regs.x.bx = 0; /* buffer ad: offset */ - if (__dpmi_int( 0x2f, &dpmi_regs) == -1) - { - /* real-mode interrupt failed? */ - EMSG("E453: could not copy clipboard data to DOS buffer"); - FreeDOSMemory(protected_mode_selector); /* clean up DOS mem */ - return NULL; /* early exit */ - } - - /* Clipboard data is now in DOS memory in the buffer pointed to by - * ES:BX. Copy this into ordinary memory that Vim can access (ie. - * prot-mode memory). Allocate one extra byte to ensure the text - * is terminated properly (in case it was somehow corrupted). - */ - clip_data_buffer = (char_u *)lalloc(clip_data_size + 1, TRUE); - - if (clip_data_buffer == NULL) - { - /* allocation failed? */ - EMSG("E454: could not allocate clipboard memory buffer"); - FreeDOSMemory(protected_mode_selector); /* clean up DOS mem */ - return NULL; /* early exit */ - } - - *(clip_data_buffer + clip_data_size) = '\0'; /* ensure terminated */ - - /* Copy the data from DOS memory to Vim-accessible memory. */ - movedata( /* DJGPP version of memcpy() */ - protected_mode_selector, 0, /* source: DOS ad (via selector) */ - _my_ds(), (unsigned)clip_data_buffer, - /* target: normal mem address */ - clip_data_size); /* how many bytes */ - - /* Free the DOS buffer and release the DPMI prot-mode selector. */ - FreeDOSMemory(protected_mode_selector); /* clean up DOS memory */ - - return clip_data_buffer; /* return pointer to allocated buffer */ - - default: /* unknown clipboard format */ - return NULL; - } -} - -/* - * Win16SetClipboardData: send 'clip_data_size' bytes of data from the buffer - * pointed to by 'clip_data', to the Windows clipboard. The data is - * registered with the clipboard as being in the 'clip_data_format' - * format. - */ - static int -Win16SetClipboardData( - int clip_data_format, - char_u *clip_data, - int clip_data_size, - int clip_data_type) -{ - __dpmi_regs dpmi_regs; - - int real_mode_segment_address; - int protected_mode_selector; - long_u protected_mode_offset = 0L; - int total_size = clip_data_size; - - char_u *clip_sel_type; - - /* If we're using the CF_VIMCLIP custom format, allocate an extra - * byte for clip_sel_type, which is a character indicating the type - * of text selection: MLINE, MCHAR, or MBLOCK. - */ - if (clip_data_format == CF_VIMCLIP) - total_size++; /* extra byte for marker */ - - /* Data cannot be sent directly from a Vim string (pClipData) to - * the Windows clipboard, because the Windows clipboard interface - * expects a 16-bit (DOS) segment:offset address for the source - * buffer. Therefore we must create a "transfer buffer" in the DOS - * memory region (in the first 1 MByte of address space) and copy - * the Vim string into that. From there, the data can then be sent - * to the Windows clipboard. - * - * To allocate DOS memory, we must use __dpmi_allocate_dos_memory() - * instead of lalloc() or alloc(). If the allocation fails, it will - * almost invariably be because there is not enough DOS memory - * available to accommodate the size of clip_data. There is nothing - * we can do about this, we simply have to fail. - */ - real_mode_segment_address = __dpmi_allocate_dos_memory( - (total_size + 15) >> 4, /* buffer size, in 16-byte paragraphs */ - &protected_mode_selector); /* prot-mode selector for the address */ - - if (real_mode_segment_address == -1) - { - /* memory allocation failed. */ - /* Technically we don't know why the allocation failed, but - * almost always it will be because there wasn't enough DOS - * memory to satisfy the request. On my system, DJGPP is able - * to satisfy a DOS allocation request up to about 600K in size. - * This depends however on HIMEM.SYS and EMM386.EXE settings. - */ - return FALSE; /* early exit */ - } - - /* Copy data from Vim's buffer (clip_data) into the DOS transfer buffer. - * This can be larger than 64K; movedata() takes care of crossing any - * 16-bit segment boundaries. - * - * If we're using Vim's custom clipboard format, we must copy one extra - * byte to indicate the type of selection: line, character, or block. - */ - if (clip_data_format == CF_VIMCLIP) - { - switch (clip_data_type) - { - default: - case MLINE: clip_sel_type = "L"; break; - case MCHAR: clip_sel_type = "C"; break; - case MBLOCK: clip_sel_type = "B"; break; - } - - movedata( - _my_ds(), (unsigned)clip_sel_type, - /* source: normal memory address */ - protected_mode_selector, 0, /* target: DOS ad (via selector) */ - 1); /* how many bytes to copy */ - - protected_mode_offset += STRLEN(clip_sel_type); /* allow for marker */ - } - - movedata( - _my_ds(), (unsigned)clip_data, /* source: normal memory address */ - protected_mode_selector, /* target: DOS address (via selector) */ - protected_mode_offset, /* non-zero, if using clip_sel_type */ - clip_data_size); /* how many bytes to copy */ - - /* Send data from the DOS transfer buffer to the Windows clipboard. - * int 0x2f, AX = 0x1703 sends SI:CX bytes of data from the buffer - * at ES:BX, to the clipboard. - */ - dpmi_regs.x.ax = 0x1703; /* send clipboard data */ - dpmi_regs.x.dx = clip_data_format; /* flag: format of the data */ - dpmi_regs.x.si = ((total_size >> 16) - & 0x0000ffffL); /* hi word of data size */ - dpmi_regs.x.cx = (total_size & 0x0000ffffL); - /* lo word of data size */ - dpmi_regs.x.es = real_mode_segment_address; /* buffer address: segment */ - dpmi_regs.x.bx = 0; /* buffer address: offset */ - if (__dpmi_int(0x2f, &dpmi_regs) == -1) - { - /* real-mode interrupt failed. */ - FreeDOSMemory(protected_mode_selector); /* clean up DOS memory */ - return FALSE; /* early exit */ - } - - /* Free the DOS buffer and release the DPMI prot-mode selector. */ - FreeDOSMemory(protected_mode_selector); /* clean up DOS memory */ - - return TRUE; /* TRUE --> data successfully sent to clipboard */ -} - -#endif /* FEAT_CLIPBOARD */ -#endif /* DJGPP */ - -/* common MS-DOS and Win16 code follows */ - - static int -vim_chmod(char_u *name) -{ - char_u *p; - int f; - int c = 0; - - /* chmod() can't handle a file name with a trailing slash, remove it. - * But don't remove it for "/" or "c:/". */ - p = name + STRLEN(name); - if (p > name) - --p; - if (p > name && (*p == '\\' || *p == '/') && p[-1] != ':') - { - c = *p; /* remove trailing (back)slash */ - *p = NUL; - } - else - p = NULL; -#if defined(__BORLANDC__) && (__BORLANDC__ > 0x410) - /* this also sets the archive bit, supported by Borland C 4.0 and later, - * where __BORLANDC__ is 0x450 (3.1 is 0x410) */ - f = _rtl_chmod((char *)name, 0, 0); -#else - f = _chmod((char *)name, 0, 0); -#endif - if (p != NULL) - *p = c; /* put back (back)slash */ - return f; -} - -/* - * get file permissions for 'name' - * Returns -1 for error. - * Returns FA_attributes defined in dos.h - */ - long -mch_getperm(char_u *name) -{ - return (long)vim_chmod(name); /* get file mode */ -} - -/* - * set file permission for 'name' to 'perm' - * - * return FAIL for failure, OK otherwise - */ - int -mch_setperm( - char_u *name, - long perm) -{ - perm |= FA_ARCH; /* file has changed, set archive bit */ -#if defined(__BORLANDC__) && (__BORLANDC__ > 0x410) - return (_rtl_chmod((char *)name, 1, (int)perm) == -1 ? FAIL : OK); -#else - return (_chmod((char *)name, 1, (int)perm) == -1 ? FAIL : OK); -#endif -} - -/* - * Set hidden flag for "name". - */ - void -mch_hide(char_u *name) -{ - /* DOS 6.2 share.exe causes "seek error on file write" errors when making - * the swap file hidden. Thus don't do it. */ -} - -/* - * return TRUE if "name" is a directory - * return FALSE if "name" is not a directory - * return FALSE for error - * - * beware of a trailing (back)slash - */ - int -mch_isdir(char_u *name) -{ - int f; - - f = vim_chmod(name); - if (f == -1) - return FALSE; /* file does not exist at all */ - if ((f & FA_DIREC) == 0) - return FALSE; /* not a directory */ - return TRUE; -} - -/* - * Return 1 if "name" can be executed, 0 if not. - * If "use_path" is FALSE only check if "name" is executable. - * Return -1 if unknown. - */ - int -mch_can_exe( - char_u *name, - char_u **path, - int use_path) -{ - char *p; - int mode; - - if (!use_path) - { - /* TODO: proper check if file is executable. */ - mode = vim_chmod(name); - return mode != -1 && (mode & FA_DIREC) == 0; - } - p = searchpath(name); - if (p == NULL || mch_isdir(p)) - return FALSE; - if (path != NULL) - *path = vim_strsave(p); - return TRUE; -} - -/* - * Check what "name" is: - * NODE_NORMAL: file or directory (or doesn't exist) - * NODE_WRITABLE: writable device, socket, fifo, etc. - * NODE_OTHER: non-writable things - */ - int -mch_nodetype(char_u *name) -{ - if (STRICMP(name, "AUX") == 0 - || STRICMP(name, "CON") == 0 - || STRICMP(name, "CLOCK$") == 0 - || STRICMP(name, "NUL") == 0 - || STRICMP(name, "PRN") == 0 - || ((STRNICMP(name, "COM", 3) == 0 - || STRNICMP(name, "LPT", 3) == 0) - && VIM_ISDIGIT(name[3]) - && name[4] == NUL)) - return NODE_WRITABLE; - /* TODO: NODE_OTHER? */ - return NODE_NORMAL; -} - -/* - * Get name of current directory into buffer 'buf' of length 'len' bytes. - * Return OK for success, FAIL for failure. - */ - int -mch_dirname( - char_u *buf, - int len) -{ -#ifdef DJGPP - if (getcwd((char *)buf, len) == NULL) - return FAIL; - /* turn the '/'s returned by DJGPP into '\'s */ - slash_adjust(buf); - return OK; -#else - return (getcwd((char *)buf, len) != NULL ? OK : FAIL); -#endif -} - -/* - * 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); -} - -/* - * Special version of getenv(): Use uppercase name. - */ - char_u * -mch_getenv(char_u *name) -{ - int i; -#define MAXENVLEN 50 - char_u var_copy[MAXENVLEN + 1]; - char_u *p; - char_u *res; - - /* - * Take a copy of the argument, and force it to upper case before passing - * to getenv(). On DOS systems, getenv() doesn't like lower-case argument - * (unlike Win32 et al.) If the name is too long to fit in var_copy[] - * allocate memory. - */ - if ((i = STRLEN(name)) > MAXENVLEN) - p = alloc(i + 1); - else - p = var_copy; - if (p == NULL) - p = name; /* out of memory, fall back to unmodified name */ - else - { - for (i = 0; name[i] != NUL; ++i) - p[i] = toupper(name[i]); - p[i] = NUL; - } - - res = (char_u *)getenv((char *)p); - - if (p != var_copy && p != name) - vim_free(p); - - return res; -} - -/* - * Insert user name in s[len]. - */ - int -mch_get_user_name( - char_u *s, - int len) -{ - *s = NUL; - return FAIL; -} - -/* - * Insert host name is s[len]. - */ - void -mch_get_host_name( - char_u *s, - int len) -{ -#ifdef DJGPP - vim_strncpy(s, "PC (32 bits Vim)", len - 1); -#else - vim_strncpy(s, "PC (16 bits Vim)", len - 1); -#endif -} |