os_win32.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:88k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8. /*
  9.  * os_win32.c
  10.  *
  11.  * Used for both the console version and the Win32 GUI.  A lot of code is for
  12.  * the console version only, so there is a lot of "#ifndef USE_GUI_WIN32".
  13.  *
  14.  * Win32 (Windows NT and Windows 95) system-dependent routines.
  15.  * Portions lifted from the Win32 SDK samples, the MSDOS-dependent code,
  16.  * NetHack 3.1.3, GNU Emacs 19.30, and Vile 5.5.
  17.  *
  18.  * George V. Reilly <georgere@microsoft.com> wrote most of this.
  19.  * Roger Knobbe <rogerk@wonderware.com> did the initial port of Vim 3.0.
  20.  */
  21. #include <io.h>
  22. #include "vim.h"
  23. #ifdef HAVE_FCNTL_H
  24. # include <fcntl.h>
  25. #endif
  26. #include <sys/types.h>
  27. #include <errno.h>
  28. #include <signal.h>
  29. #include <limits.h>
  30. #include <process.h>
  31. #define STRICT
  32. #define WIN32_LEAN_AND_MEAN
  33. #include <windows.h>
  34. #undef chdir
  35. #ifdef __GNUC__
  36. #include <dirent.h>
  37. #else
  38. #include <direct.h>
  39. #endif
  40. /* Record all output and all keyboard & mouse input */
  41. /* #define MCH_WRITE_DUMP */
  42. #ifdef MCH_WRITE_DUMP
  43. FILE* fdDump = NULL;
  44. #endif
  45. /*
  46.  * When generating prototypes for Win32 on Unix, these lines make the syntax
  47.  * errors disappear.  They do not need to be correct.
  48.  */
  49. #ifdef PROTO
  50. # define HANDLE int
  51. # define SMALL_RECT int
  52. # define COORD int
  53. # define SHORT int
  54. # define WORD int
  55. # define DWORD int
  56. # define BOOL int
  57. # define LPSTR int
  58. # define KEY_EVENT_RECORD int
  59. # define MOUSE_EVENT_RECORD int
  60. # define WINAPI
  61. # define CONSOLE_CURSOR_INFO int
  62. # define LPCSTR char_u *
  63. # define WINBASEAPI
  64. #endif
  65. #ifndef USE_GUI_WIN32
  66. /* Undocumented API in kernel32.dll needed to work around dead key bug in
  67.  * console-mode applications in NT 4.0.  If you switch keyboard layouts
  68.  * in a console app to a layout that includes dead keys and then hit a
  69.  * dead key, a call to ToAscii will trash the stack.  My thanks to Ian James
  70.  * and Michael Dietrich for helping me figure out this workaround.
  71.  */
  72. /* WINBASEAPI BOOL WINAPI GetConsoleKeyboardLayoutNameA(LPSTR); */
  73. #if defined(__BORLANDC__) || defined(__GNUC__)
  74. typedef BOOL (*PFNGCKLN)(LPSTR);
  75. #else
  76. typedef WINBASEAPI BOOL (WINAPI *PFNGCKLN)(LPSTR);
  77. #endif
  78. PFNGCKLN    s_pfnGetConsoleKeyboardLayoutName = NULL;
  79. #endif
  80. #if defined(__GNUC__) && !defined(PROTO)
  81. int _stricoll(char *a, char *b)
  82. {
  83.     // the ANSI-ish correct way is to use strxfrm():
  84.     char a_buff[512], b_buff[512];  // file names, so this is enough on Win32
  85.     strxfrm(a_buff, a, 512);
  86.     strxfrm(b_buff, b, 512);
  87.     return strcoll(a_buff, b_buff);
  88. }
  89. char * _fullpath(char *buf, char *fname, int len)
  90. {
  91.     LPTSTR toss;
  92.    return (char *) GetFullPathName(fname, len, buf, &toss);
  93. }
  94. int _chdrive(int drive)
  95. {
  96.     char temp [3] = "-:";
  97.     temp[0] = drive + 'A' - 1;
  98.     return !SetCurrentDirectory(temp);
  99. }
  100. #else
  101. #ifdef __BORLANDC__
  102. // being a more ANSI compliant compiler, BorlandC doesn't define _stricoll:
  103. // but it does in BC 5.02!
  104. #if __BORLANDC__ < 0x502
  105. int _stricoll(char *a, char *b)
  106. {
  107. #if 1
  108.     // this is fast but not correct:
  109.     return stricmp(a,b);
  110. #else
  111.     // the ANSI-ish correct way is to use strxfrm():
  112.     char a_buff[512], b_buff[512];  // file names, so this is enough on Win32
  113.     strxfrm(a_buff, a, 512);
  114.     strxfrm(b_buff, b, 512);
  115.     return strcoll(a_buff, b_buff);
  116. #endif
  117. }
  118. #endif
  119. #endif
  120. #endif
  121. #ifndef USE_GUI_WIN32
  122. /* Win32 Console handles for input and output */
  123. static HANDLE g_hConIn = INVALID_HANDLE_VALUE;
  124. static HANDLE g_hSavOut = INVALID_HANDLE_VALUE;
  125. static HANDLE g_hCurOut = INVALID_HANDLE_VALUE;
  126. static HANDLE g_hConOut = INVALID_HANDLE_VALUE;
  127. /* Win32 Screen buffer,coordinate,console I/O information */
  128. static SMALL_RECT g_srScrollRegion;
  129. static COORD   g_coord;  /* 0-based, but external coords are 1-based */
  130. /* The attribute of the screen when the editor was started */
  131. static WORD  g_attrDefault = 7;  /* lightgray text on black background */
  132. static WORD  g_attrCurrent;
  133. static int g_fCBrkPressed = FALSE;  /* set by ctrl-break interrupt */
  134. static int g_fCtrlCPressed = FALSE; /* set when ctrl-C or ctrl-break detected */
  135. static char_u g_chPending = NUL;
  136. static void termcap_mode_start(void);
  137. static void termcap_mode_end(void);
  138. static void clear_chars(COORD coord, DWORD n);
  139. static void clear_screen(void);
  140. static void clear_to_end_of_display(void);
  141. static void clear_to_end_of_line(void);
  142. static void scroll(unsigned cLines);
  143. static void set_scroll_region(unsigned left, unsigned top,
  144.       unsigned right, unsigned bottom);
  145. static void insert_lines(unsigned cLines);
  146. static void delete_lines(unsigned cLines);
  147. static void gotoxy(unsigned x, unsigned y);
  148. static void normvideo(void);
  149. static void textattr(WORD wAttr);
  150. static void textcolor(WORD wAttr);
  151. static void textbackground(WORD wAttr);
  152. static void standout(void);
  153. static void standend(void);
  154. static void visual_bell(void);
  155. static void cursor_visible(BOOL fVisible);
  156. static BOOL write_chars(LPCSTR pchBuf, DWORD cchToWrite, DWORD* pcchWritten);
  157. static char_u tgetch(void);
  158. static void create_conin(void);
  159. static void mch_set_cursor_shape(int thickness);
  160. static int s_cursor_visible = TRUE;
  161. static int did_create_conin = FALSE;
  162. #else
  163. static int s_dont_use_vimrun = TRUE;
  164. static char *vimrun_path = "vimrun ";
  165. #endif
  166. /*
  167.  * The old solution for opening a console is still there.
  168.  */
  169. //#define OLD_CONSOLE_STUFF
  170. #ifdef OLD_CONSOLE_STUFF
  171. static void mch_open_console(void);
  172. static void mch_close_console(int wait_key, DWORD ret);
  173. #endif
  174. struct growarray error_ga = {0, 0, 0, 0, NULL};
  175. #ifndef USE_GUI_WIN32
  176. static int suppress_winsize = 1; /* don't fiddle with console */
  177. #endif
  178. /* This symbol is not defined in older versions of the SDK or Visual C++ */
  179. #ifndef VER_PLATFORM_WIN32_WINDOWS
  180. # define VER_PLATFORM_WIN32_WINDOWS 1
  181. #endif
  182. static void PlatformId(void);
  183. static DWORD g_PlatformId;
  184. /*
  185.  * Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
  186.  * VER_PLATFORM_WIN32_WINDOWS (Win95).
  187.  */
  188.     static void
  189. PlatformId(void)
  190. {
  191.     static int done = FALSE;
  192.     if (!done)
  193.     {
  194. OSVERSIONINFO ovi;
  195. ovi.dwOSVersionInfoSize = sizeof(ovi);
  196. GetVersionEx(&ovi);
  197. g_PlatformId = ovi.dwPlatformId;
  198. done = TRUE;
  199.     }
  200. }
  201. /*
  202.  * Return TRUE when running on Windows 95.  Only to be used after
  203.  * mch_windinit().
  204.  */
  205.     int
  206. mch_windows95(void)
  207. {
  208.     return g_PlatformId == VER_PLATFORM_WIN32_WINDOWS;
  209. }
  210. #ifdef USE_GUI_WIN32
  211. /*
  212.  * Used to work around the "can't do synchronous spawn"
  213.  * problem on Win32s, without resorting to Universal Thunk.
  214.  */
  215. static int old_num_windows;
  216. static int num_windows;
  217.     static BOOL CALLBACK
  218. win32ssynch_cb(HWND hwnd, LPARAM lparam)
  219. {
  220.     num_windows++;
  221.     return TRUE;
  222. }
  223. #endif
  224. #ifndef USE_GUI_WIN32
  225. #define SHIFT  (SHIFT_PRESSED)
  226. #define CTRL   (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)
  227. #define ALT    (RIGHT_ALT_PRESSED  | LEFT_ALT_PRESSED)
  228. #define ALT_GR (RIGHT_ALT_PRESSED  | LEFT_CTRL_PRESSED)
  229. /* When uChar.AsciiChar is 0, then we need to look at wVirtualKeyCode.
  230.  * We map function keys to their ANSI terminal equivalents, as produced
  231.  * by ANSI.SYS, for compatibility with the MS-DOS version of Vim.  Any
  232.  * ANSI key with a value >= '300' is nonstandard, but provided anyway
  233.  * so that the user can have access to all SHIFT-, CTRL-, and ALT-
  234.  * combinations of function/arrow/etc keys.
  235.  */
  236. const static struct
  237. {
  238.     WORD    wVirtKey;
  239.     BOOL    fAnsiKey;
  240.     int     chAlone;
  241.     int     chShift;
  242.     int     chCtrl;
  243.     int     chAlt;
  244. } VirtKeyMap[] =
  245. {
  246. /*    Key ANSI alone shift ctrl     alt */
  247.     { VK_ESCAPE,FALSE, ESC, ESC, ESC,     ESC,    },
  248.     { VK_F1, TRUE, ';', 'T', '^',     'h', },
  249.     { VK_F2, TRUE, '<', 'U', '_',     'i', },
  250.     { VK_F3, TRUE, '=', 'V', '`',     'j', },
  251.     { VK_F4, TRUE, '>', 'W', 'a',     'k', },
  252.     { VK_F5, TRUE, '?', 'X', 'b',     'l', },
  253.     { VK_F6, TRUE, '@', 'Y', 'c',     'm', },
  254.     { VK_F7, TRUE, 'A', 'Z', 'd',     'n', },
  255.     { VK_F8, TRUE, 'B', '[', 'e',     'o', },
  256.     { VK_F9, TRUE, 'C', '\', 'f',     'p', },
  257.     { VK_F10, TRUE, 'D', ']', 'g',     'q', },
  258.     { VK_F11, TRUE, '205', '207', '211',     '213', },
  259.     { VK_F12, TRUE, '206', '210', '212',     '214', },
  260.     { VK_HOME, TRUE, 'G', '302', 'w',     '303', },
  261.     { VK_UP, TRUE, 'H', '304', '305',     '306', },
  262.     { VK_PRIOR, TRUE, 'I', '307', '204',     '310', }, /*PgUp*/
  263.     { VK_LEFT, TRUE, 'K', '311', 's',     '312', },
  264.     { VK_RIGHT, TRUE, 'M', '313', 't',     '314', },
  265.     { VK_END, TRUE, 'O', '315', 'u',     '316', },
  266.     { VK_DOWN, TRUE, 'P', '317', '320',     '321', },
  267.     { VK_NEXT, TRUE, 'Q', '322', 'v',     '323', }, /*PgDn*/
  268.     { VK_INSERT,TRUE, 'R', '324', '325',     '326', },
  269.     { VK_DELETE,TRUE, 'S', '327', '330',     '331', },
  270.     { VK_SNAPSHOT,TRUE, 0, 0, 0,     'r', }, /*PrtScrn*/
  271.     /* Most people don't have F13-F20, but what the hell... */
  272.     { VK_F13, TRUE, '332', '333', '334',     '335', },
  273.     { VK_F14, TRUE, '336', '337', '340',     '341', },
  274.     { VK_F15, TRUE, '342', '343', '344',     '345', },
  275.     { VK_F16, TRUE, '346', '347', '350',     '351', },
  276.     { VK_F17, TRUE, '352', '353', '354',     '355', },
  277.     { VK_F18, TRUE, '356', '357', '360',     '361', },
  278.     { VK_F19, TRUE, '362', '363', '364',     '365', },
  279.     { VK_F20, TRUE, '366', '367', '370',     '371', },
  280. };
  281. // The ToAscii bug destroys several registers. Need to turn off optimization
  282. // or the GetConsoleKeyboardLayoutName hack will fail in non-debug versions
  283. #pragma optimize("", off)
  284. /* The return code indicates key code size. */
  285.     static int
  286. win32_kbd_patch_key(
  287.     KEY_EVENT_RECORD* pker)
  288. {
  289.     static int s_iIsDead = 0;
  290.     static WORD awAnsiCode[2];
  291.     UINT uMods = pker->dwControlKeyState;
  292.     BYTE abKeystate[256];
  293.     if (s_iIsDead == 2)
  294.     {
  295. #ifdef __GNUC__
  296. pker->AsciiChar = (CHAR) awAnsiCode[1];
  297. #else
  298. pker->uChar.AsciiChar = (CHAR) awAnsiCode[1];
  299. #endif
  300. s_iIsDead = 0;
  301. return 1;
  302.     }
  303. #ifdef __GNUC__
  304.     if (pker->AsciiChar != 0)
  305. #else
  306.     if (pker->uChar.AsciiChar != 0)
  307. #endif
  308. return 1;
  309.     memset(abKeystate, 0, sizeof (abKeystate));
  310.     // Should only be non-NULL on NT 4.0
  311.     if (s_pfnGetConsoleKeyboardLayoutName != NULL)
  312.     {
  313. CHAR szKLID[KL_NAMELENGTH];
  314. if (s_pfnGetConsoleKeyboardLayoutName(szKLID))
  315.     (void)LoadKeyboardLayout(szKLID, KLF_ACTIVATE);
  316.     }
  317.     /* Clear any pending dead keys */
  318.     ToAscii(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 0);
  319.     if (uMods & SHIFT_PRESSED)
  320. abKeystate[VK_SHIFT] = 0x80;
  321.     if (uMods & CAPSLOCK_ON)
  322. abKeystate[VK_CAPITAL] = 1;
  323.     if ((uMods & ALT_GR) == ALT_GR)
  324.     {
  325. abKeystate[VK_CONTROL] = abKeystate[VK_LCONTROL] =
  326.     abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80;
  327.     }
  328.     s_iIsDead = ToAscii(pker->wVirtualKeyCode, pker->wVirtualScanCode,
  329. abKeystate, awAnsiCode, 0);
  330.     if (s_iIsDead > 0)
  331. #ifdef __GNUC__
  332. pker->AsciiChar = (CHAR) awAnsiCode[0];
  333. #else
  334. pker->uChar.AsciiChar = (CHAR) awAnsiCode[0];
  335. #endif
  336.     return s_iIsDead;
  337. }
  338. /* MUST switch optimization on again here, otherwise a call to
  339.  * decode_key_event() may crash (e.g. when hitting caps-lock) */
  340. #pragma optimize("", on)
  341. #if (_MSC_VER < 1100)
  342. /* MUST turn off global optimisation for this next function, or
  343.  * pressing ctrl-minus in insert mode crashes Vim when built with
  344.  * VC4.1. -- negri. */
  345. #pragma optimize("g", off)
  346. #endif
  347. static BOOL g_fJustGotFocus = FALSE;
  348. /*
  349.  * Decode a KEY_EVENT into one or two keystrokes
  350.  */
  351.     static BOOL
  352. decode_key_event(
  353.     KEY_EVENT_RECORD *pker,
  354.     char_u *pch,
  355.     char_u *pchPending,
  356.     BOOL fDoPost)
  357. {
  358.     int i;
  359.     const int nModifs = pker->dwControlKeyState & (SHIFT | ALT | CTRL);
  360.     *pch = *pchPending = NUL;
  361.     g_fJustGotFocus = FALSE;
  362.     /* ignore key up events */
  363.     if (!pker->bKeyDown)
  364. return FALSE;
  365.     /* ignore some keystrokes */
  366.     switch (pker->wVirtualKeyCode)
  367.     {
  368.     /* modifiers */
  369.     case VK_SHIFT:
  370.     case VK_CONTROL:
  371.     case VK_MENU:   /* Alt key */
  372. return FALSE;
  373.     default:
  374. break;
  375.     }
  376.     /* special cases */
  377.     if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0
  378. #ifdef __GNUC__
  379.     && pker->AsciiChar == NUL)
  380. #else
  381.     && pker->uChar.AsciiChar == NUL)
  382. #endif
  383.     {
  384. /* Ctrl-6 is Ctrl-^ */
  385. if (pker->wVirtualKeyCode == '6')
  386. {
  387.     *pch = Ctrl('^');
  388.     return TRUE;
  389. }
  390. /* Ctrl-2 is Ctrl-@ */
  391. else if (pker->wVirtualKeyCode == '2')
  392. {
  393.     *pch = NUL;
  394.     return TRUE;
  395. }
  396.     }
  397.     /* Shift-TAB */
  398.     if (pker->wVirtualKeyCode == VK_TAB && (nModifs & SHIFT_PRESSED))
  399.     {
  400. *pch = K_NUL;
  401. *pchPending = '17';
  402. return TRUE;
  403.     }
  404.     for (i = sizeof(VirtKeyMap) / sizeof(VirtKeyMap[0]);  --i >= 0;  )
  405.     {
  406. if (VirtKeyMap[i].wVirtKey == pker->wVirtualKeyCode)
  407. {
  408.     if (nModifs == 0)
  409. *pch = VirtKeyMap[i].chAlone;
  410.     else if ((nModifs & SHIFT) != 0 && (nModifs & ~SHIFT) == 0)
  411. *pch = VirtKeyMap[i].chShift;
  412.     else if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0)
  413. *pch = VirtKeyMap[i].chCtrl;
  414.     else if ((nModifs & ALT) != 0 && (nModifs & ~ALT) == 0)
  415. *pch = VirtKeyMap[i].chAlt;
  416.     if (*pch != 0)
  417.     {
  418. if (VirtKeyMap[i].fAnsiKey)
  419. {
  420.     *pchPending = *pch;
  421.     *pch = K_NUL;
  422. }
  423. return TRUE;
  424.     }
  425. }
  426.     }
  427.     i = win32_kbd_patch_key(pker);
  428.     if (i < 0)
  429. *pch = NUL;
  430.     else
  431. #ifdef __GNUC__
  432. *pch = (i > 0) ?  pker->AsciiChar  :  NUL;
  433. #else
  434. *pch = (i > 0) ?  pker->uChar.AsciiChar  :  NUL;
  435. #endif
  436.     return (*pch != NUL);
  437. }
  438. #pragma optimize("", on)
  439. #endif /* USE_GUI_WIN32 */
  440. #ifdef USE_MOUSE
  441. /*
  442.  * For the GUI the mouse handling is in gui_w32.c.
  443.  */
  444. # ifdef USE_GUI_WIN32
  445.     void
  446. mch_setmouse(
  447.     int on)
  448. {
  449. }
  450. # else
  451. static int g_fMouseAvail = FALSE;   /* mouse present */
  452. static int g_fMouseActive = FALSE;  /* mouse enabled */
  453. static int g_nMouseClick = -1;     /* mouse status */
  454. static int g_xMouse;     /* mouse x coordinate */
  455. static int g_yMouse;     /* mouse y coordinate */
  456. /*
  457.  * Enable or disable mouse input
  458.  */
  459.     void
  460. mch_setmouse(
  461.     int on)
  462. {
  463.     DWORD cmodein;
  464.     if (! g_fMouseAvail)
  465. return;
  466.     g_fMouseActive = on;
  467.     GetConsoleMode(g_hConIn, &cmodein);
  468.     if (g_fMouseActive)
  469. cmodein |= ENABLE_MOUSE_INPUT;
  470.     else
  471. cmodein &= ~ENABLE_MOUSE_INPUT;
  472.     SetConsoleMode(g_hConIn, cmodein);
  473. }
  474. /*
  475.  * Decode a MOUSE_EVENT.  If it's a valid event, return MOUSE_LEFT,
  476.  * MOUSE_MIDDLE, or MOUSE_RIGHT for a click; MOUSE_DRAG for a mouse
  477.  * move with a button held down; and MOUSE_RELEASE after a MOUSE_DRAG
  478.  * or a MOUSE_LEFT, _MIDDLE, or _RIGHT.  We encode the button type,
  479.  * the number of clicks, and the Shift/Ctrl/Alt modifiers in g_nMouseClick,
  480.  * and we return the mouse position in g_xMouse and g_yMouse.
  481.  *
  482.  * Every MOUSE_LEFT, _MIDDLE, or _RIGHT will be followed by zero or more
  483.  * MOUSE_DRAGs and one MOUSE_RELEASE.  MOUSE_RELEASE will be followed only
  484.  * by MOUSE_LEFT, _MIDDLE, or _RIGHT.
  485.  *
  486.  * For multiple clicks, we send, say, MOUSE_LEFT/1 click, MOUSE_RELEASE,
  487.  * MOUSE_LEFT/2 clicks, MOUSE_RELEASE, MOUSE_LEFT/3 clicks, MOUSE_RELEASE, ....
  488.  *
  489.  * Windows will send us MOUSE_MOVED notifications whenever the mouse
  490.  * moves, even if it stays within the same character cell.  We ignore
  491.  * all MOUSE_MOVED messages if the position hasn't really changed, and
  492.  * we ignore all MOUSE_MOVED messages where no button is held down (i.e.,
  493.  * we're only interested in MOUSE_DRAG).
  494.  *
  495.  * All of this is complicated by the code that fakes MOUSE_MIDDLE on
  496.  * 2-button mouses by pressing the left & right buttons simultaneously.
  497.  * In practice, it's almost impossible to click both at the same time,
  498.  * so we need to delay a little.  Also, we tend not to get MOUSE_RELEASE
  499.  * in such cases, if the user is clicking quickly.
  500.  */
  501.     static BOOL
  502. decode_mouse_event(
  503.     MOUSE_EVENT_RECORD* pmer)
  504. {
  505.     static int s_nOldButton = -1;
  506.     static int s_nOldMouseClick = -1;
  507.     static int s_xOldMouse = -1;
  508.     static int s_yOldMouse = -1;
  509.     static linenr_t s_old_topline = 0;
  510.     static int s_cClicks = 1;
  511.     static BOOL s_fReleased = TRUE;
  512.     static s_dwLastClickTime = 0;
  513.     static BOOL s_fNextIsMiddle = FALSE;
  514.     const DWORD LEFT = FROM_LEFT_1ST_BUTTON_PRESSED;
  515.     const DWORD MIDDLE = FROM_LEFT_2ND_BUTTON_PRESSED;
  516.     const DWORD RIGHT = RIGHTMOST_BUTTON_PRESSED;
  517.     const DWORD LEFT_RIGHT = LEFT | RIGHT;
  518.     int nButton;
  519.     if (! g_fMouseAvail || !g_fMouseActive)
  520.     {
  521. g_nMouseClick = -1;
  522. return FALSE;
  523.     }
  524.     /* get a spurious MOUSE_EVENT immediately after receiving focus; ignore */
  525.     if (g_fJustGotFocus)
  526.     {
  527. g_fJustGotFocus = FALSE;
  528. return FALSE;
  529.     }
  530.     /* unprocessed mouse click? */
  531.     if (g_nMouseClick != -1)
  532. return TRUE;
  533.     nButton = -1;
  534.     g_xMouse = pmer->dwMousePosition.X;
  535.     g_yMouse = pmer->dwMousePosition.Y;
  536.     if (pmer->dwEventFlags == MOUSE_MOVED)
  537.     {
  538. /* ignore MOUSE_MOVED events if (x, y) hasn't changed. (We get these
  539.  * events even when the mouse moves only within a char cell.) */
  540. if (s_xOldMouse == g_xMouse && s_yOldMouse == g_yMouse)
  541.     return FALSE;
  542.     }
  543.     /* If no buttons are pressed... */
  544.     if (pmer->dwButtonState == 0)
  545.     {
  546. /* If the last thing returned was MOUSE_RELEASE, ignore this */
  547. if (s_fReleased)
  548.     return FALSE;
  549. nButton = MOUSE_RELEASE;
  550. s_fReleased = TRUE;
  551.     }
  552.     else    /* one or more buttons pressed */
  553.     {
  554. const int cButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
  555. /* on a 2-button mouse, hold down left and right buttons
  556.  * simultaneously to get MIDDLE. */
  557. if (cButtons == 2 && s_nOldButton != MOUSE_DRAG)
  558. {
  559.     DWORD dwLR = (pmer->dwButtonState & LEFT_RIGHT);
  560.     /* if either left or right button only is pressed, see if the
  561.      * the next mouse event has both of them pressed */
  562.     if (dwLR == LEFT || dwLR == RIGHT)
  563.     {
  564. for (;;)
  565. {
  566.     /* wait a short time for next input event */
  567.     if (WaitForSingleObject(g_hConIn, p_mouset / 3)
  568. != WAIT_OBJECT_0)
  569. break;
  570.     else
  571.     {
  572. DWORD cRecords = 0;
  573. INPUT_RECORD ir;
  574. MOUSE_EVENT_RECORD* pmer2 = &ir.Event.MouseEvent;
  575. PeekConsoleInput(g_hConIn, &ir, 1, &cRecords);
  576. if (cRecords == 0 || ir.EventType != MOUSE_EVENT
  577. || !(pmer2->dwButtonState & LEFT_RIGHT))
  578.     break;
  579. else
  580. {
  581.     if (pmer2->dwEventFlags != MOUSE_MOVED)
  582.     {
  583. ReadConsoleInput(g_hConIn, &ir, 1, &cRecords);
  584. return decode_mouse_event(pmer2);
  585.     }
  586.     else if (s_xOldMouse == pmer2->dwMousePosition.X &&
  587.      s_yOldMouse == pmer2->dwMousePosition.Y)
  588.     {
  589. /* throw away spurious mouse move */
  590. ReadConsoleInput(g_hConIn, &ir, 1, &cRecords);
  591. /* are there any more mouse events in queue? */
  592. PeekConsoleInput(g_hConIn, &ir, 1, &cRecords);
  593. if (cRecords==0 || ir.EventType != MOUSE_EVENT)
  594.     break;
  595.     }
  596.     else
  597. break;
  598. }
  599.     }
  600. }
  601.     }
  602. }
  603. if (s_fNextIsMiddle)
  604. {
  605.     nButton = (pmer->dwEventFlags == MOUSE_MOVED)
  606. ? MOUSE_DRAG : MOUSE_MIDDLE;
  607.     s_fNextIsMiddle = FALSE;
  608. }
  609. else if (cButtons == 2 &&
  610.     ((pmer->dwButtonState & LEFT_RIGHT) == LEFT_RIGHT))
  611. {
  612.     nButton = MOUSE_MIDDLE;
  613.     if (! s_fReleased && pmer->dwEventFlags != MOUSE_MOVED)
  614.     {
  615. s_fNextIsMiddle = TRUE;
  616. nButton = MOUSE_RELEASE;
  617.     }
  618. }
  619. else if ((pmer->dwButtonState & LEFT) == LEFT)
  620.     nButton = MOUSE_LEFT;
  621. else if ((pmer->dwButtonState & MIDDLE) == MIDDLE)
  622.     nButton = MOUSE_MIDDLE;
  623. else if ((pmer->dwButtonState & RIGHT) == RIGHT)
  624.     nButton = MOUSE_RIGHT;
  625. if (! s_fReleased && ! s_fNextIsMiddle
  626. && nButton != s_nOldButton && s_nOldButton != MOUSE_DRAG)
  627.     return FALSE;
  628. s_fReleased = s_fNextIsMiddle;
  629.     }
  630.     if (pmer->dwEventFlags == 0 || pmer->dwEventFlags == DOUBLE_CLICK)
  631.     {
  632. /* button pressed or released, without mouse moving */
  633. if (nButton != -1 && nButton != MOUSE_RELEASE)
  634. {
  635.     DWORD dwCurrentTime = GetTickCount();
  636.     if (s_xOldMouse != g_xMouse
  637.     || s_yOldMouse != g_yMouse
  638.     || s_nOldButton != nButton
  639.     || s_old_topline != curwin->w_topline
  640.     || (int)(dwCurrentTime - s_dwLastClickTime) > p_mouset)
  641.     {
  642. s_cClicks = 1;
  643.     }
  644.     else if (++s_cClicks > 4)
  645.     {
  646. s_cClicks = 1;
  647.     }
  648.     s_dwLastClickTime = dwCurrentTime;
  649. }
  650.     }
  651.     else if (pmer->dwEventFlags == MOUSE_MOVED)
  652.     {
  653. if (nButton != -1 && nButton != MOUSE_RELEASE)
  654.     nButton = MOUSE_DRAG;
  655. s_cClicks = 1;
  656.     }
  657.     if (nButton == -1)
  658. return FALSE;
  659.     if (nButton != MOUSE_RELEASE)
  660. s_nOldButton = nButton;
  661.     g_nMouseClick = nButton;
  662.     if (pmer->dwControlKeyState & SHIFT_PRESSED)
  663. g_nMouseClick |= MOUSE_SHIFT;
  664.     if (pmer->dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
  665. g_nMouseClick |= MOUSE_CTRL;
  666.     if (pmer->dwControlKeyState & (RIGHT_ALT_PRESSED  | LEFT_ALT_PRESSED))
  667. g_nMouseClick |= MOUSE_ALT;
  668.     /* only pass on interesting (i.e., different) mouse events */
  669.     if (s_xOldMouse == g_xMouse
  670.     && s_yOldMouse == g_yMouse
  671.     && s_nOldMouseClick == g_nMouseClick)
  672.     {
  673. g_nMouseClick = -1;
  674. return FALSE;
  675.     }
  676.     g_nMouseClick |= 0x20;
  677.     s_xOldMouse = g_xMouse;
  678.     s_yOldMouse = g_yMouse;
  679.     s_old_topline = curwin->w_topline;
  680.     s_nOldMouseClick = g_nMouseClick;
  681.     if (nButton != MOUSE_DRAG && nButton != MOUSE_RELEASE)
  682. SET_NUM_MOUSE_CLICKS(g_nMouseClick, s_cClicks);
  683.     return TRUE;
  684. }
  685. # endif /* USE_GUI_WIN32 */
  686. #endif /* USE_MOUSE */
  687. #ifndef USE_GUI_WIN32     /* this isn't used for the GUI */
  688. /*
  689.  * Set the shape of the cursor.
  690.  * 'thickness' can be from 1 (thin) to 99 (block)
  691.  */
  692.     static void
  693. mch_set_cursor_shape(int thickness)
  694. {
  695.     CONSOLE_CURSOR_INFO ConsoleCursorInfo;
  696.     ConsoleCursorInfo.dwSize = thickness;
  697.     ConsoleCursorInfo.bVisible = s_cursor_visible;
  698.     SetConsoleCursorInfo(g_hCurOut, &ConsoleCursorInfo);
  699. }
  700.     void
  701. mch_update_cursor(void)
  702. {
  703.     int idx;
  704.     int thickness;
  705.     /*
  706.      * How the cursor is drawn depends on the current mode.
  707.      */
  708.     idx = get_cursor_idx();
  709.     if (cursor_table[idx].shape == SHAPE_BLOCK)
  710. thickness = 99; /* 100 doesn't work on W95 */
  711.     else
  712. thickness = cursor_table[idx].percentage;
  713.     mch_set_cursor_shape(thickness);
  714. }
  715. /*
  716.  * Wait until console input from keyboard or mouse is available,
  717.  * or the time is up.
  718.  * Return TRUE if something is available FALSE if not.
  719.  */
  720.     static int
  721. WaitForChar(long msec)
  722. {
  723.     DWORD     dwNow, dwEndTime;
  724.     INPUT_RECORD    ir;
  725.     DWORD     cRecords;
  726.     char_u     ch, ch2;
  727.     if (msec > 0)
  728. dwEndTime = GetTickCount() + msec;
  729.     /* We need to loop until the end of the time period, because
  730.      * we might get multiple unusable mouse events in that time.
  731.      */
  732.     for (;;)
  733.     {
  734. if (g_chPending != NUL
  735. #ifdef USE_MOUSE
  736. || g_nMouseClick != -1
  737. #endif
  738.     )
  739.     return TRUE;
  740. if (msec > 0)
  741. {
  742.     dwNow = GetTickCount();
  743.     if (dwNow >= dwEndTime)
  744. break;
  745.     if (WaitForSingleObject(g_hConIn, dwEndTime - dwNow)
  746.      != WAIT_OBJECT_0)
  747. continue;
  748. }
  749. cRecords = 0;
  750. PeekConsoleInput(g_hConIn, &ir, 1, &cRecords);
  751. if (cRecords > 0)
  752. {
  753. #ifdef MULTI_BYTE_IME
  754.     /* Windows IME sends two 'n's with only one 'ENTER'.
  755.        first, wVirtualKeyCode == 13. second, wVirtualKeyCode == 0 */
  756.     if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
  757.     {
  758. if (ir.Event.KeyEvent.uChar.UnicodeChar == 0
  759. && ir.Event.KeyEvent.wVirtualKeyCode == 13)
  760. {
  761.     ReadConsoleInput(g_hConIn, &ir, 1, &cRecords);
  762.     continue;
  763. }
  764. return decode_key_event(&ir.Event.KeyEvent, &ch, &ch2, FALSE);
  765.     }
  766. #else
  767.     if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown
  768.     && decode_key_event(&ir.Event.KeyEvent, &ch, &ch2, FALSE))
  769. return TRUE;
  770. #endif
  771.     ReadConsoleInput(g_hConIn, &ir, 1, &cRecords);
  772. #ifdef USE_CLIPBOARD
  773.     if (ir.EventType == FOCUS_EVENT)
  774. g_fJustGotFocus = ir.Event.FocusEvent.bSetFocus;
  775. #endif
  776.     else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
  777. set_winsize(Rows, Columns, FALSE);
  778. #ifdef USE_MOUSE
  779.     else if (ir.EventType == MOUSE_EVENT
  780.     && decode_mouse_event(&ir.Event.MouseEvent))
  781. return TRUE;
  782. #endif
  783. }
  784. else if (msec == 0)
  785.     break;
  786.     }
  787.     return FALSE;
  788. }
  789. /*
  790.  * Create the console input.  Used when reading stdin doesn't work.
  791.  */
  792.     static void
  793. create_conin(void)
  794. {
  795.     g_hConIn = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE,
  796. FILE_SHARE_READ|FILE_SHARE_WRITE,
  797. (LPSECURITY_ATTRIBUTES) NULL,
  798. OPEN_EXISTING, (DWORD)NULL, (HANDLE)NULL);
  799.     did_create_conin = TRUE;
  800. }
  801. /*
  802.  * Get a keystroke or a mouse event
  803.  */
  804.     static char_u
  805. tgetch(void)
  806. {
  807.     char_u ch;
  808.     if (g_chPending != NUL)
  809.     {
  810. ch = g_chPending;
  811. g_chPending = NUL;
  812. return ch;
  813.     }
  814.     for ( ; ; )
  815.     {
  816. INPUT_RECORD ir;
  817. DWORD cRecords = 0;
  818. if (ReadConsoleInput(g_hConIn, &ir, 1, &cRecords) == 0)
  819. {
  820.     if (did_create_conin)
  821. read_error_exit();
  822.     create_conin();
  823.     continue;
  824. }
  825. if (ir.EventType == KEY_EVENT)
  826. {
  827.     if (decode_key_event(&ir.Event.KeyEvent, &ch, &g_chPending, TRUE))
  828. return ch;
  829. }
  830. #ifdef USE_CLIPBOARD
  831. else if (ir.EventType == FOCUS_EVENT)
  832. {
  833.     g_fJustGotFocus = ir.Event.FocusEvent.bSetFocus;
  834.     /* TRACE("tgetch: Focus %dn", g_fJustGotFocus); */
  835. }
  836. #endif
  837. else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
  838. {
  839.     set_winsize(Rows, Columns, FALSE);
  840. }
  841. #ifdef USE_MOUSE
  842. else if (ir.EventType == MOUSE_EVENT)
  843. {
  844.     if (decode_mouse_event(&ir.Event.MouseEvent))
  845. return 0;
  846. }
  847. #endif
  848.     }
  849. }
  850. #endif /* !USE_GUI_WIN32 */
  851. /*
  852.  * mch_inchar(): low-level input funcion.
  853.  * Get one or more characters from the keyboard or the mouse.
  854.  * If time == 0, do not wait for characters.
  855.  * If time == n, wait a short time for characters.
  856.  * If time == -1, wait forever for characters.
  857.  * Returns the number of characters read into buf.
  858.  */
  859.     int
  860. mch_inchar(
  861.     char_u *buf,
  862.     int maxlen,
  863.     long time)
  864. {
  865. #ifndef USE_GUI_WIN32     /* this isn't used for the GUI */
  866.     int len = 0;
  867.     int c;
  868.     if (time >= 0)
  869.     {
  870. if (!WaitForChar(time))     /* no character available */
  871.     return 0;
  872.     }
  873.     else    /* time == -1, wait forever */
  874.     {
  875. /* If there is no character available within 2 seconds (default),
  876.  * write the autoscript file to disk */
  877. if (!WaitForChar(p_ut))
  878.     updatescript(0);
  879.     }
  880.     /*
  881.      * Try to read as many characters as there are, until the buffer is full.
  882.      */
  883.     /* we will get at least one key. Get more if they are available. */
  884.     g_fCBrkPressed = FALSE;
  885. #ifdef MCH_WRITE_DUMP
  886.     if (fdDump)
  887. fputc('[', fdDump);
  888. #endif
  889.     while ((len == 0 || WaitForChar(0)) && len < maxlen)
  890.     {
  891. #ifdef USE_MOUSE
  892. if (g_nMouseClick != -1 && maxlen - len >= 5)
  893. {
  894. # ifdef MCH_WRITE_DUMP
  895.     if (fdDump)
  896. fprintf(fdDump, "{%02x @ %d, %d}",
  897. g_nMouseClick, g_xMouse, g_yMouse);
  898. # endif
  899.     len += 5;
  900.     *buf++ = ESC + 128;
  901.     *buf++ = 'M';
  902.     *buf++ = g_nMouseClick;
  903.     *buf++ = g_xMouse + '!';
  904.     *buf++ = g_yMouse + '!';
  905.     g_nMouseClick = -1;
  906. }
  907. else
  908. #endif /* USE_MOUSE */
  909. {
  910.     if ((c = tgetch()) == Ctrl('C'))
  911. g_fCBrkPressed = TRUE;
  912. #ifdef USE_MOUSE
  913.     if (g_nMouseClick == -1)
  914. #endif
  915.     {
  916. *buf++ = c;
  917. len++;
  918. #ifdef MCH_WRITE_DUMP
  919. if (fdDump)
  920.     fputc(c, fdDump);
  921. #endif
  922.     }
  923. }
  924.     }
  925. #ifdef MCH_WRITE_DUMP
  926.     if (fdDump)
  927.     {
  928. fputs("]n", fdDump);
  929. fflush(fdDump);
  930.     }
  931. #endif
  932.     return len;
  933. #else /* USE_GUI_WIN32 */
  934.     return 0;
  935. #endif /* USE_GUI_WIN32 */
  936. }
  937. #ifdef USE_GUI_WIN32
  938. #include <shellapi.h> /* required for FindExecutable() */
  939. /*
  940.  * GUI version of mch_windinit().
  941.  */
  942.     void
  943. mch_windinit()
  944. {
  945.     extern int _fmode;
  946.     PlatformId();
  947.     /* Specify window size.  Is there a place to get the default from? */
  948.     Rows = 25;
  949.     Columns = 80;
  950.     _fmode = O_BINARY; /* we do our own CR-LF translation */
  951.     /* Look for 'vimrun' */
  952.     if (!gui_is_win32s())
  953.     {
  954. char_u vimrun_location[2 * _MAX_PATH + 2];
  955. char_u widename[40];
  956. /* First try in same directory as gvim.exe */
  957. STRCPY(vimrun_location, exe_name);
  958. STRCPY(gettail(vimrun_location), "vimrun.exe");
  959. if (mch_getperm(vimrun_location) >= 0)
  960. {
  961.     STRCPY(gettail(vimrun_location), "vimrun ");
  962.     vimrun_path = (char *)vim_strsave(vimrun_location);
  963.     s_dont_use_vimrun = FALSE;
  964. }
  965. else
  966. {
  967.     /* There appears to be a bug in FindExecutableA() on Windows NT.
  968.      * Use FindExecutableW() instead... */
  969.     if (g_PlatformId == VER_PLATFORM_WIN32_NT)
  970.     {
  971. MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)"vimrun.exe", -1,
  972. (LPWSTR)widename, 20);
  973. if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"",
  974.     (LPWSTR)vimrun_location) > (HINSTANCE)32)
  975.     s_dont_use_vimrun = FALSE;
  976.     }
  977.     else
  978.     {
  979. if (FindExecutableA((LPCTSTR)"vimrun.exe", (LPCTSTR)"",
  980.     (LPTSTR)vimrun_location) > (HINSTANCE)32)
  981.     s_dont_use_vimrun = FALSE;
  982.     }
  983. }
  984. if (s_dont_use_vimrun)
  985.     MessageBox(NULL,
  986. "VIMRUN.EXE not found in your $PATH.n"
  987. "External commands will not pause after completion.n"
  988. "See  :help win32-vimrun  for more information.",
  989. "Vim Warning",
  990. MB_ICONWARNING);
  991.     }
  992. #ifdef USE_CLIPBOARD
  993.     clip_init(TRUE);
  994.     /*
  995.      * Vim's own clipboard format recognises whether the text is char, line, or
  996.      * rectangular block.  Only useful for copying between two Vims.
  997.      */
  998.     clipboard.format = RegisterClipboardFormat("VimClipboard");
  999. #endif
  1000. }
  1001. /*
  1002.  * GUI version of mch_windexit().
  1003.  * Shut down and exit with status `r'
  1004.  * Careful: mch_windexit() may be called before mch_windinit()!
  1005.  */
  1006.     void
  1007. mch_windexit(
  1008.     int r)
  1009. {
  1010.     mch_display_error();
  1011.     ml_close_all(TRUE); /* remove all memfiles */
  1012. # ifdef HAVE_OLE
  1013.     UninitOLE();
  1014. # endif
  1015.     if (gui.in_use)
  1016. gui_exit(r);
  1017.     exit(r);
  1018. }
  1019. #else /* USE_GUI_WIN32 */
  1020. static char g_szOrigTitle[256];
  1021. static int  g_fWindInitCalled = FALSE;
  1022. static CONSOLE_CURSOR_INFO g_cci;
  1023. static DWORD g_cmodein = 0;
  1024. static DWORD g_cmodeout = 0;
  1025. /*
  1026.  * Because of a bug in the Windows 95 Console, we need to set the screen size
  1027.  * back when switching screens.
  1028.  */
  1029. static int g_nOldRows = 0;
  1030. static int g_nOldColumns = 0;
  1031. /*
  1032.  * non-GUI version of mch_windinit().
  1033.  */
  1034.     void
  1035. mch_windinit()
  1036. {
  1037.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  1038.     extern int _fmode;
  1039.     PlatformId();
  1040.     _fmode = O_BINARY; /* we do our own CR-LF translation */
  1041.     out_flush();
  1042.     /* Obtain handles for the standard Console I/O devices */
  1043.     if (read_cmd_fd == 0)
  1044. g_hConIn =  GetStdHandle(STD_INPUT_HANDLE);
  1045.     else
  1046. create_conin();
  1047.     g_hSavOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1048.     g_hCurOut = g_hSavOut;
  1049.     /* Get current text attributes */
  1050.     GetConsoleScreenBufferInfo(g_hSavOut, &csbi);
  1051.     g_attrCurrent = g_attrDefault = csbi.wAttributes;
  1052.     GetConsoleCursorInfo(g_hSavOut, &g_cci);
  1053.     /* set termcap codes to current text attributes */
  1054.     update_tcap(csbi.wAttributes);
  1055.     GetConsoleMode(g_hConIn,  &g_cmodein);
  1056.     GetConsoleMode(g_hSavOut, &g_cmodeout);
  1057.     GetConsoleTitle(g_szOrigTitle, sizeof(g_szOrigTitle));
  1058.     ui_get_winsize();
  1059.     g_nOldRows = Rows;
  1060.     g_nOldColumns = Columns;
  1061. #ifdef MCH_WRITE_DUMP
  1062.     fdDump = fopen("dump", "wt");
  1063.     if (fdDump)
  1064.     {
  1065. time_t t;
  1066. time(&t);
  1067. fputs(ctime(&t), fdDump);
  1068. fflush(fdDump);
  1069.     }
  1070. #endif
  1071.     g_fWindInitCalled = TRUE;
  1072. #ifdef USE_MOUSE
  1073.     g_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT);
  1074. #endif
  1075. #ifdef USE_CLIPBOARD
  1076.     clip_init(TRUE);
  1077.     /*
  1078.      * Vim's own clipboard format recognises whether the text is char, line, or
  1079.      * rectangular block.  Only useful for copying between two Vims.
  1080.      */
  1081.     clipboard.format = RegisterClipboardFormat("VimClipboard");
  1082. #endif
  1083.     /* This will be NULL on anything but NT 4.0 */
  1084.     s_pfnGetConsoleKeyboardLayoutName =
  1085. (PFNGCKLN) GetProcAddress(GetModuleHandle("kernel32.dll"),
  1086.   "GetConsoleKeyboardLayoutNameA");
  1087.     /*
  1088.      * We don't really want to jump to our own screen yet; do that after
  1089.      * starttermcap(). This flashes the window, sorry about that, but
  1090.      * otherwise "vim -r" doesn't work.
  1091.      */
  1092.     g_hCurOut = g_hSavOut;
  1093.     SetConsoleActiveScreenBuffer(g_hCurOut);
  1094. }
  1095. /*
  1096.  * non-GUI version of mch_windexit().
  1097.  * Shut down and exit with status `r'
  1098.  * Careful: mch_windexit() may be called before mch_windinit()!
  1099.  */
  1100.     void
  1101. mch_windexit(
  1102.     int r)
  1103. {
  1104.     stoptermcap();
  1105.     out_char('r');
  1106.     out_char('n');
  1107.     out_flush();
  1108.     if (g_fWindInitCalled)
  1109. settmode(TMODE_COOK);
  1110.     if (g_hConOut != INVALID_HANDLE_VALUE)
  1111.     {
  1112. (void)CloseHandle(g_hConOut);
  1113. if (g_hSavOut != INVALID_HANDLE_VALUE)
  1114. {
  1115.     SetConsoleTextAttribute(g_hSavOut, g_attrDefault);
  1116.     SetConsoleCursorInfo(g_hSavOut, &g_cci);
  1117. }
  1118.     }
  1119.     ml_close_all(TRUE); /* remove all memfiles */
  1120.     if (g_fWindInitCalled)
  1121.     {
  1122. mch_restore_title(3);
  1123. #ifdef MCH_WRITE_DUMP
  1124. if (fdDump)
  1125. {
  1126.     time_t t;
  1127.     time(&t);
  1128.     fputs(ctime(&t), fdDump);
  1129.     fclose(fdDump);
  1130. }
  1131. fdDump = NULL;
  1132. #endif
  1133.     }
  1134.     exit(r);
  1135. }
  1136. #endif /* USE_GUI_WIN32 */
  1137. /*
  1138.  * Do we have an interactive window?
  1139.  */
  1140.     int
  1141. mch_check_win(
  1142.     int argc,
  1143.     char **argv)
  1144. {
  1145.     char temp[256];
  1146.     int i;
  1147.     /* store the name of the executable, may be used for $VIM */
  1148.     GetModuleFileName(NULL, temp, 255);
  1149.     if (*temp != NUL)
  1150. exe_name = FullName_save((char_u *)temp, FALSE);
  1151.     /* Init the tables for toupper() and tolower() */
  1152.     for (i = 0; i < 256; ++i)
  1153. toupper_tab[i] = tolower_tab[i] = i;
  1154.     CharUpperBuff(toupper_tab, 256);
  1155.     CharLowerBuff(tolower_tab, 256);
  1156. #ifdef USE_GUI_WIN32
  1157.     return OK;     /* GUI always has a tty */
  1158. #else
  1159.     if (isatty(1))
  1160. return OK;
  1161.     return FAIL;
  1162. #endif
  1163. }
  1164. /*
  1165.  * Return TRUE if the input comes from a terminal, FALSE otherwise.
  1166.  */
  1167.     int
  1168. mch_input_isatty()
  1169. {
  1170. #ifdef USE_GUI_WIN32
  1171.     return OK;     /* GUI always has a tty */
  1172. #else
  1173.     if (isatty(read_cmd_fd))
  1174. return TRUE;
  1175.     return FALSE;
  1176. #endif
  1177. }
  1178. /*
  1179.  * Turn a file name into its canonical form.  Replace slashes with backslashes.
  1180.  * This used to replace backslashes with slashes, but that caused problems
  1181.  * when using the file name as a command.  We can't have a mix of slashes and
  1182.  * backslashes, because comparing file names will not work correctly.  The
  1183.  * commands that use file names should be prepared to handle the backslashes.
  1184.  */
  1185.     static void
  1186. canonicalize_filename(
  1187.     char *pszName)
  1188. {
  1189.     if (pszName == NULL)
  1190. return;
  1191.     for ( ; *pszName;  pszName++)
  1192.     {
  1193. if (*pszName == '/')
  1194.     *pszName = '\';
  1195.     }
  1196. }
  1197. /*
  1198.  * fname_case(): Set the case of the file name, if it already exists.
  1199.  */
  1200.     void
  1201. fname_case(
  1202.     char_u *name)
  1203. {
  1204.     char szTrueName[_MAX_PATH + 2];
  1205.     char *psz, *pszPrev;
  1206.     const int len = (name != NULL)  ?  STRLEN(name)  : 0;
  1207.     if (len == 0)
  1208. return;
  1209.     STRNCPY(szTrueName, name, _MAX_PATH);
  1210.     szTrueName[_MAX_PATH] = '';   /* ensure it's sealed off! */
  1211.     STRCAT(szTrueName, "\"); /* sentinel */
  1212.     for (psz = szTrueName;  *psz != NUL;  psz++)
  1213. if (*psz == '/')
  1214.     *psz = '\';
  1215.     psz = pszPrev = szTrueName;
  1216.     /* Skip leading \ in UNC name or drive letter */
  1217.     if (len > 2 && ((psz[0] == '\' && psz[1] == '\')
  1218.        || (isalpha(psz[0]) && psz[1] == ':')))
  1219.     {
  1220. psz = pszPrev = szTrueName + 2;
  1221.     }
  1222.     while (*psz != NUL)
  1223.     {
  1224. WIN32_FIND_DATA fb;
  1225. HANDLE hFind;
  1226. while (*psz != '\')
  1227.     psz++;
  1228. *psz = NUL;
  1229. if ((hFind = FindFirstFile(szTrueName, &fb)) != INVALID_HANDLE_VALUE)
  1230. {
  1231.     /* avoid ".." and ".", etc */
  1232.     if (_stricoll(pszPrev, fb.cFileName) == 0)
  1233. STRCPY(pszPrev, fb.cFileName);
  1234.     FindClose(hFind);
  1235. }
  1236. *psz++ = '\';
  1237. pszPrev = psz;
  1238.     }
  1239.     *--psz = NUL;   /* remove sentinel */
  1240.     STRCPY(name, szTrueName);
  1241. }
  1242. /*
  1243.  * mch_settitle(): set titlebar of our window
  1244.  * Can the icon also be set?
  1245.  */
  1246.     void
  1247. mch_settitle(
  1248.     char_u *title,
  1249.     char_u *icon)
  1250. {
  1251. #ifdef USE_GUI_WIN32
  1252.     gui_mch_settitle(title, icon);
  1253. #else
  1254.     if (title != NULL)
  1255. SetConsoleTitle(title);
  1256. #endif
  1257. }
  1258. /*
  1259.  * Restore the window/icon title.
  1260.  * which is one of:
  1261.  *  1: Just restore title
  1262.  *  2: Just restore icon (which we don't have)
  1263.  *  3: Restore title and icon (which we don't have)
  1264.  */
  1265.     void
  1266. mch_restore_title(
  1267.     int which)
  1268. {
  1269. #ifndef USE_GUI_WIN32
  1270.     mch_settitle((which & 1) ? g_szOrigTitle : NULL, NULL);
  1271. #endif
  1272. }
  1273. /*
  1274.  * Return TRUE if we can restore the title (we can)
  1275.  */
  1276.     int
  1277. mch_can_restore_title()
  1278. {
  1279.     return TRUE;
  1280. }
  1281. /*
  1282.  * Return TRUE if we can restore the icon (we can't)
  1283.  */
  1284.     int
  1285. mch_can_restore_icon()
  1286. {
  1287.     return FALSE;
  1288. }
  1289. /*
  1290.  * Insert user name in s[len].
  1291.  */
  1292.     int
  1293. mch_get_user_name(
  1294.     char_u *s,
  1295.     int len)
  1296. {
  1297.     char szUserName[MAX_COMPUTERNAME_LENGTH + 1];
  1298.     DWORD cch = sizeof szUserName;
  1299.     if (GetUserName(szUserName, &cch))
  1300.     {
  1301. STRNCPY(s, szUserName, len);
  1302. return OK;
  1303.     }
  1304.     s[0] = NUL;
  1305.     return FAIL;
  1306. }
  1307. /*
  1308.  * Insert host name in s[len].
  1309.  */
  1310.     void
  1311. mch_get_host_name(
  1312.     char_u *s,
  1313.     int len)
  1314. {
  1315.     char szHostName[MAX_COMPUTERNAME_LENGTH + 1];
  1316.     DWORD cch = sizeof szHostName;
  1317.     if (GetComputerName(szHostName, &cch))
  1318.     {
  1319. STRCPY(s, "PC ");
  1320. STRNCPY(s + 3, szHostName, len - 3);
  1321.     }
  1322.     else
  1323. STRNCPY(s, "PC (Win32 Vim)", len);
  1324. }
  1325. /*
  1326.  * return process ID
  1327.  */
  1328.     long
  1329. mch_get_pid()
  1330. {
  1331.     return (long)GetCurrentProcessId();
  1332. }
  1333. /*
  1334.  * Get name of current directory into buffer 'buf' of length 'len' bytes.
  1335.  * Return OK for success, FAIL for failure.
  1336.  */
  1337.     int
  1338. mch_dirname(
  1339.     char_u *buf,
  1340.     int len)
  1341. {
  1342.     /*
  1343.      * Originally this was:
  1344.      *    return (getcwd(buf, len) != NULL ? OK : FAIL);
  1345.      * But the Win32s known bug list says that getcwd() doesn't work
  1346.      * so use the Win32 system call instead. <Negri>
  1347.      */
  1348.     return (GetCurrentDirectory(len,buf) != 0 ? OK : FAIL);
  1349. }
  1350. /*
  1351.  * Get absolute file name into buffer 'buf' of length 'len' bytes,
  1352.  * turning all '/'s into '\'s and getting the correct case of each
  1353.  * component of the file name. Return OK or FAIL.
  1354.  */
  1355.     int
  1356. mch_FullName(
  1357.     char_u *fname,
  1358.     char_u *buf,
  1359.     int len,
  1360.     int force)
  1361. {
  1362.     int nResult = FAIL;
  1363.     if (fname == NULL) /* always fail */
  1364. return FAIL;
  1365.     if (_fullpath(buf, fname, len - 1) == NULL)
  1366. STRNCPY(buf, fname, len);   /* failed, use the relative path name */
  1367.     else
  1368.     {
  1369. if (mch_isdir(fname))
  1370.     STRCAT(buf, "\");
  1371. nResult = OK;
  1372.     }
  1373.     fname_case(buf);
  1374.     return nResult;
  1375. }
  1376. /*
  1377.  * return TRUE if `fname' is an absolute path name
  1378.  */
  1379.     int
  1380. mch_isFullName(
  1381.     char_u *fname)
  1382. {
  1383.     char szName[_MAX_PATH+1];
  1384.     mch_FullName(fname, szName, _MAX_PATH, FALSE);
  1385.     return strcoll(fname, szName) == 0;
  1386. }
  1387. /*
  1388.  * Replace all slashes by backslashes.
  1389.  * This used to be the other way around, but MS-DOS sometimes has problems
  1390.  * with slashes (e.g. in a command name).  We can't have mixed slashes and
  1391.  * backslashes, because comparing file names will not work correctly.  The
  1392.  * commands that use a file name should try to avoid the need to type a
  1393.  * backslash twice.
  1394.  */
  1395.     void
  1396. slash_adjust(p)
  1397.     char_u  *p;
  1398. {
  1399.     while (*p)
  1400.     {
  1401. if (*p == '/')
  1402.     *p = '\';
  1403. ++p;
  1404.     }
  1405. }
  1406. /*
  1407.  * get file permissions for `name'
  1408.  * -1 : error
  1409.  * else FILE_ATTRIBUTE_* defined in winnt.h
  1410.  */
  1411.     long
  1412. mch_getperm(
  1413.     char_u *name)
  1414. {
  1415.     return (long)GetFileAttributes((char *)name);
  1416. }
  1417. /*
  1418.  * set file permission for `name' to `perm'
  1419.  */
  1420.     int
  1421. mch_setperm(
  1422.     char_u *name,
  1423.     long perm)
  1424. {
  1425.     perm |= FILE_ATTRIBUTE_ARCHIVE; /* file has changed, set archive bit */
  1426.     return SetFileAttributes((char *)name, perm) ? OK : FAIL;
  1427. }
  1428. /*
  1429.  * Set hidden flag for "name".
  1430.  */
  1431.     void
  1432. mch_hide(char_u *name)
  1433. {
  1434.     int perm;
  1435.     perm = GetFileAttributes((char *)name);
  1436.     if (perm >= 0)
  1437.     {
  1438. perm |= FILE_ATTRIBUTE_HIDDEN;
  1439. SetFileAttributes((char *)name, perm);
  1440.     }
  1441. }
  1442. /*
  1443.  * return TRUE if "name" is a directory
  1444.  * return FALSE if "name" is not a directory or upon error
  1445.  */
  1446.     int
  1447. mch_isdir(char_u *name)
  1448. {
  1449.     int f = mch_getperm(name);
  1450.     if (f == -1)
  1451. return FALSE;     /* file does not exist at all */
  1452.     return (f & FILE_ATTRIBUTE_DIRECTORY) != 0;
  1453. }
  1454. #ifdef USE_GUI_WIN32
  1455.     void
  1456. mch_settmode(int tmode)
  1457. {
  1458.     /* nothing to do */
  1459. }
  1460.     int
  1461. mch_get_winsize()
  1462. {
  1463.     /* never used */
  1464.     return OK;
  1465. }
  1466.     void
  1467. mch_set_winsize()
  1468. {
  1469.     /* never used */
  1470. }
  1471. #else
  1472. /*
  1473.  * handler for ctrl-break, ctrl-c interrupts, and fatal events.
  1474.  */
  1475.     static BOOL WINAPI
  1476. handler_routine(
  1477.     DWORD dwCtrlType)
  1478. {
  1479.     switch (dwCtrlType)
  1480.     {
  1481.     case CTRL_C_EVENT:
  1482. g_fCtrlCPressed = TRUE;
  1483. return TRUE;
  1484.     case CTRL_BREAK_EVENT:
  1485. g_fCBrkPressed = TRUE;
  1486. return TRUE;
  1487.     /* fatal events: shut down gracefully */
  1488.     case CTRL_CLOSE_EVENT:
  1489.     case CTRL_LOGOFF_EVENT:
  1490.     case CTRL_SHUTDOWN_EVENT:
  1491. windgoto((int)Rows - 1, 0);
  1492. sprintf((char *)IObuff, "Vim: Caught %s eventn",
  1493. (dwCtrlType == CTRL_CLOSE_EVENT ? "close"
  1494.  : dwCtrlType == CTRL_LOGOFF_EVENT ? "logoff" : "shutdown"));
  1495. #ifdef DEBUG
  1496. OutputDebugString(IObuff);
  1497. #endif
  1498. preserve_exit(); /* output IObuff, preserve files and exit */
  1499. return TRUE; /* not reached */
  1500.     default:
  1501. return FALSE;
  1502.     }
  1503. }
  1504. /*
  1505.  * set the tty in (raw) ? "raw" : "cooked" mode
  1506.  */
  1507.     void
  1508. mch_settmode(
  1509.     int tmode)
  1510. {
  1511.     DWORD cmodein;
  1512.     DWORD cmodeout;
  1513.     GetConsoleMode(g_hConIn,  &cmodein);
  1514.     GetConsoleMode(g_hCurOut, &cmodeout);
  1515.     if (tmode == TMODE_RAW)
  1516.     {
  1517. cmodein &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
  1518.      ENABLE_ECHO_INPUT);
  1519. cmodein |= (
  1520. #ifdef USE_MOUSE
  1521.     (g_fMouseActive ? ENABLE_MOUSE_INPUT : 0) |
  1522. #endif
  1523.     ENABLE_WINDOW_INPUT);
  1524. SetConsoleMode(g_hConIn, cmodein);
  1525. cmodeout &= ~(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
  1526. SetConsoleMode(g_hCurOut, cmodeout);
  1527. SetConsoleCtrlHandler(handler_routine, TRUE);
  1528.     }
  1529.     else /* cooked */
  1530.     {
  1531. cmodein =  g_cmodein;
  1532. cmodeout = g_cmodeout;
  1533. SetConsoleMode(g_hConIn,  g_cmodein);
  1534. SetConsoleMode(g_hCurOut, g_cmodeout);
  1535. SetConsoleCtrlHandler(handler_routine, FALSE);
  1536.     }
  1537. #ifdef MCH_WRITE_DUMP
  1538.     if (fdDump)
  1539.     {
  1540. fprintf(fdDump, "mch_settmode(%s, CurOut = %s, in = %x, out = %x)n",
  1541. tmode == TMODE_RAW ? "raw" :
  1542.     tmode == TMODE_COOK ? "cooked" : "normal",
  1543. (g_hCurOut == g_hSavOut ? "Sav" : "Con"),
  1544. cmodein, cmodeout);
  1545. fflush(fdDump);
  1546.     }
  1547. #endif
  1548. }
  1549. /*
  1550.  * Get the size of the current window in `Rows' and `Columns'
  1551.  * Return OK when size could be determined, FAIL otherwise.
  1552.  */
  1553.     int
  1554. mch_get_winsize()
  1555. {
  1556.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  1557.     if (GetConsoleScreenBufferInfo(g_hCurOut, &csbi))
  1558.     {
  1559. Rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
  1560. Columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
  1561.     }
  1562.     else
  1563.     {
  1564. Rows = 25;
  1565. Columns = 80;
  1566.     }
  1567.     if (Columns < MIN_COLUMNS || Rows < MIN_LINES)
  1568.     {
  1569. /* these values are overwritten by termcap size or default */
  1570. Rows = 25;
  1571. Columns = 80;
  1572.     }
  1573.     check_winsize();
  1574.     set_scroll_region(0, 0, Columns - 1, Rows - 1);
  1575.     return OK;
  1576. }
  1577. /*
  1578.  * Set a console window to `xSize' * `ySize'
  1579.  */
  1580.     static void
  1581. ResizeConBufAndWindow(
  1582.     HANDLE hConsole,
  1583.     int xSize,
  1584.     int ySize)
  1585. {
  1586.     CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */
  1587.     SMALL_RECT     srWindowRect; /* hold the new console size */
  1588.     COORD     coordScreen;
  1589.     int     did_start_termcap = FALSE;
  1590. #ifdef MCH_WRITE_DUMP
  1591.     if (fdDump)
  1592.     {
  1593. fprintf(fdDump, "ResizeConBufAndWindow(%d, %d)n", xSize, ySize);
  1594. fflush(fdDump);
  1595.     }
  1596. #endif
  1597.     /*
  1598.      * The resizing MUST be done while in our own console buffer, otherwise it
  1599.      * will never be possible to restore the old one, and we will crash on
  1600.      * exit in Windows 95.
  1601.      */
  1602.     if (g_hCurOut != g_hConOut)
  1603.     {
  1604. termcap_mode_start();
  1605. did_start_termcap = TRUE;
  1606.     }
  1607.     /* get the largest size we can size the console window to */
  1608.     coordScreen = GetLargestConsoleWindowSize(hConsole);
  1609.     /* define the new console window size and scroll position */
  1610.     srWindowRect.Left = srWindowRect.Top = (SHORT) 0;
  1611.     srWindowRect.Right =  (SHORT) (min(xSize, coordScreen.X) - 1);
  1612.     srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1);
  1613.     if (GetConsoleScreenBufferInfo(g_hCurOut, &csbi))
  1614.     {
  1615. int sx, sy;
  1616. sx = csbi.srWindow.Right - csbi.srWindow.Left + 1;
  1617. sy = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
  1618. if (sy < ySize || sx < xSize)
  1619. {
  1620.     /*
  1621.      * Increasing number of lines/columns, do buffer first.
  1622.      * Use the maximal size in x and y direction.
  1623.      */
  1624.     if (sy < ySize)
  1625. coordScreen.Y = ySize;
  1626.     else
  1627. coordScreen.Y = sy;
  1628.     if (sx < xSize)
  1629. coordScreen.X = xSize;
  1630.     else
  1631. coordScreen.X = sx;
  1632.     SetConsoleScreenBufferSize(hConsole, coordScreen);
  1633. }
  1634.     }
  1635.     if (!SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect))
  1636.     {
  1637. #ifdef MCH_WRITE_DUMP
  1638. if (fdDump)
  1639. {
  1640.     fprintf(fdDump, "SetConsoleWindowInfo failed: %lxn",
  1641.     GetLastError());
  1642.     fflush(fdDump);
  1643. }
  1644. #endif
  1645.     }
  1646.     /* define the new console buffer size */
  1647.     coordScreen.X = xSize;
  1648.     coordScreen.Y = ySize;
  1649.     if (!SetConsoleScreenBufferSize(hConsole, coordScreen))
  1650.     {
  1651. #ifdef MCH_WRITE_DUMP
  1652. if (fdDump)
  1653. {
  1654.     fprintf(fdDump, "SetConsoleScreenBufferSize failed: %lxn",
  1655.     GetLastError());
  1656.     fflush(fdDump);
  1657. }
  1658. #endif
  1659.     }
  1660.     if (did_start_termcap)
  1661. termcap_mode_end();
  1662. }
  1663. /*
  1664.  * Set the console window to `Rows' * `Columns'
  1665.  */
  1666.     void
  1667. mch_set_winsize()
  1668. {
  1669.     COORD coordScreen;
  1670.     /* Don't change window size while still starting up */
  1671.     if (suppress_winsize)
  1672.     {
  1673. suppress_winsize = 2;
  1674. return;
  1675.     }
  1676.     coordScreen = GetLargestConsoleWindowSize(g_hCurOut);
  1677.     /* Clamp Rows and Columns to reasonable values */
  1678.     if (Rows > coordScreen.Y)
  1679. Rows = coordScreen.Y;
  1680.     if (Columns > coordScreen.X)
  1681. Columns = coordScreen.X;
  1682.     ResizeConBufAndWindow(g_hCurOut, Columns, Rows);
  1683.     set_scroll_region(0, 0, Columns - 1, Rows - 1);
  1684. }
  1685. /*
  1686.  * Called when started up, to set the winsize that was delayed.
  1687.  */
  1688.     void
  1689. mch_set_winsize_now()
  1690. {
  1691.     if (suppress_winsize == 2)
  1692.     {
  1693. suppress_winsize = 0;
  1694. mch_set_winsize();
  1695. check_winsize();     /* in case 'columns' changed */
  1696.     }
  1697.     suppress_winsize = 0;
  1698. }
  1699. #endif /* USE_GUI_WIN32 */
  1700. /*
  1701.  * We have no job control, so fake it by starting a new shell.
  1702.  */
  1703.     void
  1704. mch_suspend()
  1705. {
  1706.     suspend_shell();
  1707. }
  1708. #if defined(USE_GUI_WIN32) || defined(PROTO)
  1709. #ifdef OLD_CONSOLE_STUFF
  1710. /*
  1711.  * Functions to open and close a console window.
  1712.  * The open function sets the size of the window to 25x80, to avoid problems
  1713.  * with Windows 95.  In the long term should make sure that the "close" icon
  1714.  * cannot crash vim (it doesn't do so at the moment!).
  1715.  * The close function waits for the user to press a key before closing the
  1716.  * window.
  1717.  */
  1718.     static BOOL
  1719. ConsoleCtrlHandler(DWORD what)
  1720. {
  1721.     return TRUE;
  1722. }
  1723.     static void
  1724. mch_open_console(void)
  1725. {
  1726.     COORD size;
  1727.     SMALL_RECT window_size;
  1728.     HANDLE console_handle;
  1729.     AllocConsole();
  1730.     /* On windows 95, we must use a 25x80 console size, to avoid trouble with
  1731.      * some DOS commands */
  1732.     if (g_PlatformId != VER_PLATFORM_WIN32_NT)
  1733.     {
  1734. console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
  1735. size.X = 80;
  1736. size.Y = 25;
  1737. window_size.Left = 0;
  1738. window_size.Top = 0;
  1739. window_size.Right = 79;
  1740. window_size.Bottom = 24;
  1741. /* First set the window size, then also resize the screen buffer, to
  1742.  * avoid a scrollbar */
  1743. SetConsoleWindowInfo(console_handle, TRUE, &window_size);
  1744. SetConsoleScreenBufferSize(console_handle, size);
  1745.     }
  1746.     SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleCtrlHandler, TRUE);
  1747. }
  1748.     static void
  1749. mch_close_console(int wait_key, DWORD ret)
  1750. {
  1751.     if (wait_key)
  1752.     {
  1753. HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
  1754. HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
  1755. DWORD number;
  1756. static char message[] = "nPress any key to close this window...";
  1757. static char err_buf[80];
  1758. char buffer[1];
  1759. if (ret)
  1760. {
  1761.     sprintf(err_buf, "n%ld returned.", ret);
  1762.     WriteConsole(hStderr, err_buf, strlen(err_buf), &number, NULL);
  1763. }
  1764. /* Write a message to the user */
  1765. WriteConsole(hStderr, message, sizeof(message)-1, &number, NULL);
  1766. /* Clear the console input buffer, and set the input to "raw" mode */
  1767. FlushConsoleInputBuffer(hStdin);
  1768. SetConsoleMode(hStdin, 0);
  1769. /* Wait for a keypress */
  1770. ReadConsole(hStdin, buffer, 1, &number, NULL);
  1771.     }
  1772.     /* Close the console window */
  1773.     FreeConsole();
  1774. }
  1775. #endif
  1776. #ifdef mch_errmsg
  1777. # undef mch_errmsg
  1778. # undef mch_display_error
  1779. #endif
  1780. /*
  1781.  * Record an error message for later display.
  1782.  */
  1783.     void
  1784. mch_errmsg(char *str)
  1785. {
  1786.     int len = STRLEN(str) + 1;
  1787.     if (error_ga.ga_growsize == 0)
  1788.     {
  1789. error_ga.ga_growsize = 80;
  1790. error_ga.ga_itemsize = 1;
  1791.     }
  1792.     if (ga_grow(&error_ga, len) == OK)
  1793.     {
  1794. mch_memmove((char_u *)error_ga.ga_data + error_ga.ga_len,
  1795.   (char_u *)str, len);
  1796. --len; /* don't count the NUL at the end */
  1797. error_ga.ga_len += len;
  1798. error_ga.ga_room -= len;
  1799.     }
  1800. }
  1801. /*
  1802.  * Display the saved error message(s).
  1803.  */
  1804.     void
  1805. mch_display_error()
  1806. {
  1807.     char *p;
  1808.     if (error_ga.ga_data != NULL)
  1809.     {
  1810. /* avoid putting up a message box with blanks only */
  1811. for (p = (char *)error_ga.ga_data; *p; ++p)
  1812.     if (!isspace(*p))
  1813.     {
  1814. MessageBox(0, p, "Vim", MB_TASKMODAL|MB_SETFOREGROUND);
  1815. break;
  1816.     }
  1817. ga_clear(&error_ga);
  1818.     }
  1819. }
  1820. /*
  1821.  * Specialised version of system() for Win32 GUI mode.
  1822.  * This version proceeds as follows:
  1823.  *    1. Create a console window for use by the subprocess
  1824.  *    2. Run the subprocess (it gets the allocated console by default)
  1825.  *    3. Wait for the subprocess to terminate and get its exit code
  1826.  *    4. Prompt the user to press a key to close the console window
  1827.  */
  1828. static BOOL fUseConsole = TRUE;
  1829.     static int
  1830. mch_system(char *cmd, int options)
  1831. {
  1832.     STARTUPINFO si;
  1833.     PROCESS_INFORMATION pi;
  1834.     DWORD ret = 0;
  1835.     si.cb = sizeof(si);
  1836.     si.lpReserved = NULL;
  1837.     si.lpDesktop = NULL;
  1838.     si.lpTitle = NULL;
  1839.     si.dwFlags = STARTF_USESHOWWINDOW;
  1840.     /*
  1841.      * It's nicer to run a filter command in a minimized window, but in
  1842.      * Windows 95 this makes the command MUCH slower.
  1843.      */
  1844.     if ((options & SHELL_DOOUT) && !mch_windows95())
  1845. si.wShowWindow = SW_SHOWMINIMIZED;
  1846.     else
  1847. si.wShowWindow = SW_SHOWNORMAL;
  1848.     si.cbReserved2 = 0;
  1849.     si.lpReserved2 = NULL;
  1850. #ifdef OLD_CONSOLE_STUFF
  1851.     /* Create a console for the process. This lets us write a termination
  1852.      * message at the end, and wait for the user to close the console
  1853.      * window manually...
  1854.      */
  1855.     if (fUseConsole)
  1856.     {
  1857. mch_open_console();
  1858. /*
  1859.  * Write the command to the console, so the user can see what is going
  1860.  * on.
  1861.  */
  1862. {
  1863.     HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
  1864.     DWORD number;
  1865.     WriteConsole(hStderr, cmd, STRLEN(cmd), &number, NULL);
  1866.     WriteConsole(hStderr, "n", 1, &number, NULL);
  1867. }
  1868.     }
  1869. #else
  1870.     /* There is a strange error on Windows 95 when using "c:\command.com".
  1871.      * When the "c:\" is left out it works OK...? */
  1872.     if (mch_windows95()
  1873.     && (STRNICMP(cmd, "c:/command.com", 14) == 0
  1874. || STRNICMP(cmd, "c:\command.com", 14) == 0))
  1875. cmd += 3;
  1876. #endif
  1877.     /* Now, run the command */
  1878.     CreateProcess(NULL, /* Executable name */
  1879.   cmd, /* Command to execute */
  1880.   NULL, /* Process security attributes */
  1881.   NULL, /* Thread security attributes */
  1882.   FALSE, /* Inherit handles */
  1883.   CREATE_DEFAULT_ERROR_MODE | /* Creation flags */
  1884. #ifdef OLD_CONSOLE_STUFF
  1885.   0,
  1886. #else
  1887.   CREATE_NEW_CONSOLE,
  1888. #endif
  1889.   NULL, /* Environment */
  1890.   NULL, /* Current directory */
  1891.   &si, /* Startup information */
  1892.   &pi); /* Process information */
  1893.     /* Wait for the command to terminate before continuing */
  1894.     if (fUseConsole)
  1895.     {
  1896. if (g_PlatformId != VER_PLATFORM_WIN32s)
  1897. {
  1898.     WaitForSingleObject(pi.hProcess, INFINITE);
  1899.     /* Get the command exit code */
  1900.     GetExitCodeProcess(pi.hProcess, &ret);
  1901. }
  1902. else
  1903. {
  1904.     /*
  1905.      * This ugly code is the only quick way of performing
  1906.      * a synchronous spawn under Win32s. Yuk.
  1907.      */
  1908.     num_windows = 0;
  1909.     EnumWindows(win32ssynch_cb, 0);
  1910.     old_num_windows = num_windows;
  1911.     do
  1912.     {
  1913. Sleep(1000);
  1914. num_windows = 0;
  1915. EnumWindows(win32ssynch_cb, 0);
  1916.     } while (num_windows == old_num_windows);
  1917.     ret = 0;
  1918. }
  1919.     }
  1920.     /* Close the handles to the subprocess, so that it goes away */
  1921.     CloseHandle(pi.hThread);
  1922.     CloseHandle(pi.hProcess);
  1923.     /* Close the console window. If we are not redirecting output, wait for
  1924.      * the user to press a key.
  1925.      */
  1926. #ifdef OLD_CONSOLE_STUFF
  1927.     if (fUseConsole)
  1928. mch_close_console(!(options & SHELL_DOOUT), ret);
  1929. #endif
  1930.     return ret;
  1931. }
  1932. #else
  1933. # define mch_system(c, o) system(c)
  1934. #endif
  1935. /*
  1936.  * Either execute a command by calling the shell or start a new shell
  1937.  */
  1938.     int
  1939. mch_call_shell(
  1940.     char_u *cmd,
  1941.     int options)     /* SHELL_FILTER if called by do_filter() */
  1942.     /* SHELL_COOKED if term needs cooked mode */
  1943. {
  1944.     int     x;
  1945. #ifndef USE_GUI_WIN32
  1946.     int     stopped_termcap_mode = FALSE;
  1947. #endif
  1948.     out_flush();
  1949. #ifndef USE_GUI_WIN32
  1950.     /*
  1951.      * ALWAYS switch to non-termcap mode, otherwise ":r !ls" may crash.
  1952.      */
  1953.     if (g_hCurOut == g_hConOut &&
  1954.     ((cmd == NULL) || STRNICMP(cmd, "start ", 6) != 0))
  1955.     {
  1956. termcap_mode_end();
  1957. stopped_termcap_mode = TRUE;
  1958.     }
  1959. #endif
  1960. #ifdef MCH_WRITE_DUMP
  1961.     if (fdDump)
  1962.     {
  1963. fprintf(fdDump, "mch_call_shell("%s", %d)n", cmd, options);
  1964. fflush(fdDump);
  1965.     }
  1966. #endif
  1967.     /*
  1968.      * Catch all deadly signals while running the external command, because a
  1969.      * CTRL-C, Ctrl-Break or illegal instruction  might otherwise kill us.
  1970.      */
  1971.     signal(SIGINT, SIG_IGN);
  1972. #ifdef __GNUC__
  1973.     signal(SIGKILL, SIG_IGN);
  1974. #else
  1975.     signal(SIGBREAK, SIG_IGN);
  1976. #endif
  1977.     signal(SIGILL, SIG_IGN);
  1978.     signal(SIGFPE, SIG_IGN);
  1979.     signal(SIGSEGV, SIG_IGN);
  1980.     signal(SIGTERM, SIG_IGN);
  1981.     signal(SIGABRT, SIG_IGN);
  1982.     if (options & SHELL_COOKED)
  1983. settmode(TMODE_COOK); /* set to normal mode */
  1984.     if (cmd == NULL)
  1985.     {
  1986. x = mch_system(p_sh, options);
  1987.     }
  1988.     else
  1989.     {
  1990. /* we use "command" or "cmd" to start the shell; slow but easy */
  1991. char_u *newcmd;
  1992. newcmd = lalloc(
  1993. #ifdef USE_GUI_WIN32
  1994. STRLEN(vimrun_path) +
  1995. #endif
  1996. STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10, TRUE);
  1997. if (newcmd != NULL)
  1998. {
  1999.     if (STRNICMP(cmd, "start ", 6) == 0)
  2000.     {
  2001. STARTUPINFO si;
  2002. PROCESS_INFORMATION pi;
  2003. si.cb = sizeof(si);
  2004. si.lpReserved = NULL;
  2005. si.lpDesktop = NULL;
  2006. si.lpTitle = NULL;
  2007. si.dwFlags = 0;
  2008. si.cbReserved2 = 0;
  2009. si.lpReserved2 = NULL;
  2010. sprintf((char *)newcmd, "%s", cmd+6);
  2011. /*
  2012.  * Now, start the command as a process, so that it doesn't
  2013.  * inherit our handles which causes unpleasant dangling swap
  2014.  * files if we exit before the spawned process
  2015.  */
  2016. if (CreateProcess (NULL, // Executable name
  2017. newcmd, // Command to execute
  2018. NULL, // Process security attributes
  2019. NULL, // Thread security attributes
  2020. FALSE, // Inherit handles
  2021. CREATE_NEW_CONSOLE, // Creation flags
  2022. NULL, // Environment
  2023. NULL, // Current directory
  2024. &si, // Startup information
  2025. &pi)) // Process information
  2026.     x = 0;
  2027. else
  2028.     x = -1;
  2029. /* Close the handles to the subprocess, so that it goes away */
  2030. CloseHandle(pi.hThread);
  2031. CloseHandle(pi.hProcess);
  2032.     }
  2033.     else
  2034.     {
  2035. sprintf((char *)newcmd, "%s%s %s %s",
  2036. #if defined(OLD_CONSOLE_STUFF) || !defined(USE_GUI_WIN32)
  2037. "",
  2038. #else
  2039. /*
  2040.  * Do we need to use "vimrun"?
  2041.  */
  2042. ((options & SHELL_DOOUT) || s_dont_use_vimrun) ?
  2043.     "" : vimrun_path,
  2044. #endif
  2045. p_sh,
  2046. p_shcf,
  2047. cmd);
  2048. x = mch_system((char *)newcmd, options);
  2049.     }
  2050.     vim_free(newcmd);
  2051. }
  2052.     }
  2053.     settmode(TMODE_RAW);     /* set to raw mode */
  2054. #ifdef USE_GUI_WIN32
  2055.     if (x && !expand_interactively && !fUseConsole)
  2056. #else
  2057.     if (x && !expand_interactively)
  2058. #endif
  2059.     {
  2060. smsg("%d returned", x);
  2061. msg_putchar('n');
  2062.     }
  2063.     resettitle();
  2064.     signal(SIGINT, SIG_DFL);
  2065. #ifdef __GNUC__
  2066.     signal(SIGKILL, SIG_DFL);
  2067. #else
  2068.     signal(SIGBREAK, SIG_DFL);
  2069. #endif
  2070.     signal(SIGILL, SIG_DFL);
  2071.     signal(SIGFPE, SIG_DFL);
  2072.     signal(SIGSEGV, SIG_DFL);
  2073.     signal(SIGTERM, SIG_DFL);
  2074.     signal(SIGABRT, SIG_DFL);
  2075. #ifndef USE_GUI_WIN32
  2076.     if (stopped_termcap_mode)
  2077. termcap_mode_start();
  2078. #endif
  2079.     return x;
  2080. }
  2081. /*
  2082.  * Does `s' contain a wildcard?
  2083.  */
  2084.     int
  2085. mch_has_wildcard(
  2086.     char_u *s)
  2087. {
  2088.     return (vim_strpbrk(s, (char_u *)"?*$~") != NULL);
  2089. }
  2090. /*
  2091.  * comparison function for qsort in expandpath
  2092.  */
  2093.     static int
  2094. #ifdef __BORLANDC__
  2095. _RTLENTRYF
  2096. #endif
  2097. pstrcmp(
  2098.     const void *a,
  2099.     const void *b)
  2100. {
  2101.     return (_stricoll(* (char **)a, * (char **)b));
  2102. }
  2103. /*
  2104.  * Recursively build up a list of files in "gap" matching the first wildcard
  2105.  * in `path'.  Called by expand_wildcards().
  2106.  */
  2107.     int
  2108. mch_expandpath(
  2109.     struct growarray *gap,
  2110.     char_u *path,
  2111.     int flags)
  2112. {
  2113.     char buf[_MAX_PATH+1];
  2114.     char *p, *s, *e;
  2115.     int start_len, c = 1;
  2116.     WIN32_FIND_DATA fb;
  2117.     HANDLE hFind;
  2118.     int matches;
  2119.     int start_dot_ok;
  2120.     start_len = gap->ga_len;
  2121.     /*
  2122.      * Find the first part in the path name that contains a wildcard.
  2123.      * Copy it into `buf', including the preceding characters.
  2124.      */
  2125.     p = buf;
  2126.     s = NULL;
  2127.     e = NULL;
  2128.     while (*path)
  2129.     {
  2130. if (*path == '\' || *path == ':' || *path == '/')
  2131. {
  2132.     if (e)
  2133. break;
  2134.     else
  2135. s = p;
  2136. }
  2137. if (*path == '*' || *path == '?')
  2138.     e = p;
  2139. *p++ = *path++;
  2140.     }
  2141.     e = p;
  2142.     if (s)
  2143. s++;
  2144.     else
  2145. s = buf;
  2146. #ifdef USE_GUI_WIN32
  2147.     if (gui_is_win32s())
  2148.     {
  2149. /* It appears the Win32s FindFirstFile() call doesn't like a pattern
  2150.  * such as swrel1.0cod* because of the dot in the directory name.
  2151.  * It doesn't match files with extensions.
  2152.  * if the file name ends in "*" and does not contain a "." after the
  2153.  * last  , add ".*"
  2154.  */
  2155. if (e[-1] == '*' && vim_strchr(s, '.') == NULL)
  2156. {
  2157.     *e++ = '.';
  2158.     *e++ = '*';
  2159. }
  2160.     }
  2161. #endif
  2162.     /* now we have one wildcard component between `s' and `e' */
  2163.     *e = NUL;
  2164.     start_dot_ok = (buf[0] == '.' || buf[0] == '*');
  2165.     /* If we are expanding wildcards, we try both files and directories */
  2166.     if ((hFind = FindFirstFile(buf, &fb)) != INVALID_HANDLE_VALUE)
  2167. while (c)
  2168. {
  2169.     STRCPY(s, fb.cFileName);
  2170.     /*
  2171.      * Ignore "." and "..".  When more follows, this must be a
  2172.      * directory.
  2173.      * Find*File() returns matches that start with a '.', even though
  2174.      * the pattern doesn't start with '.'.  Filter them out manually.
  2175.      */
  2176.     if ((s[0] != '.'
  2177. || (start_dot_ok
  2178.     && s[1] != NUL
  2179.     && (s[1] != '.' || s[2] != NUL)))
  2180.     && (*path == NUL || mch_isdir(buf)))
  2181.     {
  2182. STRCAT(buf, path);
  2183. if (mch_has_wildcard(path))     /* handle more wildcards */
  2184.     (void)mch_expandpath(gap, buf, flags);
  2185. else if (mch_getperm(buf) >= 0)     /* add existing file */
  2186.     addfile(gap, buf, flags);
  2187.     }
  2188.     c = FindNextFile(hFind, &fb);
  2189. }
  2190.     FindClose(hFind);
  2191.     matches = gap->ga_len - start_len;
  2192.     if (matches)
  2193. qsort(((char_u **)gap->ga_data) + start_len, matches,
  2194.      sizeof(char *), pstrcmp);
  2195.     return matches;
  2196. }
  2197. /*
  2198.  * The normal _chdir() does not change the default drive.  This one does.
  2199.  * Returning 0 implies success; -1 implies failure.
  2200.  */
  2201.     int
  2202. mch_chdir(char *path)
  2203. {
  2204.     if (path[0] == NUL) /* just checking... */
  2205. return -1;
  2206.     if (isalpha(path[0]) && path[1] == ':') /* has a drive name */
  2207.     {
  2208. if (_chdrive(TO_LOWER(path[0]) - 'a' + 1) != 0)
  2209.     return -1; /* invalid drive name */
  2210. path += 2;
  2211.     }
  2212.     if (*path == NUL) /* drive name only */
  2213. return 0;
  2214.     return chdir(path);        /* let the normal chdir() do the rest */
  2215. }
  2216. #ifndef USE_GUI_WIN32
  2217. /*
  2218.  * Copy the contents of screen buffer hSrc to the bottom-left corner
  2219.  * of screen buffer hDst.
  2220.  */
  2221.     static void
  2222. copy_screen_buffer_text(
  2223.     HANDLE hSrc,
  2224.     HANDLE hDst)
  2225. {
  2226.     int     i, j, nSrcWidth, nSrcHeight, nDstWidth, nDstHeight;
  2227.     COORD   coordOrigin;
  2228.     DWORD   dwDummy;
  2229.     LPSTR   pszOldText;
  2230.     CONSOLE_SCREEN_BUFFER_INFO csbiSrc, csbiDst;
  2231. #ifdef MCH_WRITE_DUMP
  2232.     if (fdDump)
  2233.     {
  2234. fprintf(fdDump, "copy_screen_buffer_text(%s, %s)n",
  2235. (hSrc == g_hSavOut ? "Sav" : "Con"),
  2236. (hDst == g_hSavOut ? "Sav" : "Con"));
  2237. fflush(fdDump);
  2238.     }
  2239. #endif
  2240.     GetConsoleScreenBufferInfo(hSrc, &csbiSrc);
  2241.     nSrcWidth =  csbiSrc.srWindow.Right  - csbiSrc.srWindow.Left + 1;
  2242.     nSrcHeight = csbiSrc.srWindow.Bottom - csbiSrc.srWindow.Top  + 1;
  2243.     GetConsoleScreenBufferInfo(hDst, &csbiDst);
  2244.     nDstWidth =  csbiDst.srWindow.Right  - csbiDst.srWindow.Left + 1;
  2245.     nDstHeight = csbiDst.srWindow.Bottom - csbiDst.srWindow.Top  + 1;
  2246.     pszOldText = (LPSTR) alloc(nDstHeight * nDstWidth);
  2247.     /* clear the top few lines if Src shorter than Dst */
  2248.     for (i = 0;  i < nDstHeight - nSrcHeight;  i++)
  2249.     {
  2250. for (j = 0;  j < nDstWidth;  j++)
  2251.     pszOldText[i * nDstWidth + j] = ' ';
  2252.     }
  2253.     /* Grab text off source screen. */
  2254.     coordOrigin.X = 0;
  2255.     coordOrigin.Y = (SHORT) max(0, csbiSrc.srWindow.Bottom + 1 - nDstHeight);
  2256.     for (i = 0;  i < min(nSrcHeight, nDstHeight);  i++)
  2257.     {
  2258. LPSTR psz = pszOldText
  2259.      + (i + max(0, nDstHeight - nSrcHeight)) * nDstWidth;
  2260. ReadConsoleOutputCharacter(hSrc, psz, min(nDstWidth, nSrcWidth),
  2261.    coordOrigin, &dwDummy);
  2262. coordOrigin.Y++;
  2263. /* clear the last few columns if Src narrower than Dst */
  2264. for (j = nSrcWidth;  j < nDstWidth;  j++)
  2265.     psz[j] = ' ';
  2266.     }
  2267.     /* paste Src's text onto Dst */
  2268.     coordOrigin.Y = csbiDst.srWindow.Top;
  2269.     WriteConsoleOutputCharacter(hDst, pszOldText, nDstHeight * nDstWidth,
  2270. coordOrigin, &dwDummy);
  2271.     vim_free(pszOldText);
  2272. }
  2273. /* keep track of state of original console window */
  2274. static SMALL_RECT   g_srOrigWindowRect;
  2275. static COORD     g_coordOrig;
  2276. static WORD     g_attrSave = 0;
  2277. /*
  2278.  * Start termcap mode by switching to our allocated screen buffer
  2279.  */
  2280.     static void
  2281. termcap_mode_start(void)
  2282. {
  2283.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  2284.     DWORD dwDummy;
  2285.     COORD coord;
  2286.     WORD wAttr = (WORD) (g_attrSave ? g_attrSave : g_attrCurrent);
  2287.     GetConsoleScreenBufferInfo(g_hSavOut, &csbi);
  2288.     g_srOrigWindowRect = csbi.srWindow;
  2289.     g_coordOrig.X = 0;
  2290.     g_coordOrig.Y = csbi.dwCursorPosition.Y;
  2291.     if (g_hConOut == INVALID_HANDLE_VALUE)
  2292. /* Create a new screen buffer in which we do all of our editing.
  2293.  * This means we can restore the original screen when we finish. */
  2294. g_hConOut = CreateConsoleScreenBuffer(GENERIC_WRITE | GENERIC_READ,
  2295.       0, (LPSECURITY_ATTRIBUTES) NULL,
  2296.       CONSOLE_TEXTMODE_BUFFER,
  2297.       (LPVOID) NULL);
  2298.     coord.X = coord.Y = 0;
  2299.     FillConsoleOutputCharacter(g_hConOut, ' ', Rows * Columns, coord, &dwDummy);
  2300.     FillConsoleOutputAttribute(g_hConOut, wAttr, Rows*Columns, coord, &dwDummy);
  2301.     copy_screen_buffer_text(g_hSavOut, g_hConOut);
  2302.     g_hCurOut = g_hConOut;
  2303.     SetConsoleActiveScreenBuffer(g_hCurOut);
  2304.     ResizeConBufAndWindow(g_hCurOut, Columns, Rows);
  2305.     set_scroll_region(0, 0, Columns - 1, Rows - 1);
  2306.     check_winsize();
  2307.     resettitle();
  2308.     textattr(wAttr);
  2309. }
  2310. /*
  2311.  * Turn off termcap mode by restoring the screen buffer we had upon startup
  2312.  */
  2313.     static void
  2314. termcap_mode_end()
  2315. {
  2316.     g_attrSave = g_attrCurrent;
  2317.     ResizeConBufAndWindow(g_hCurOut, g_nOldColumns, g_nOldRows);
  2318.     /* This weird Sleep(0) is required to allow Windows to really resize the
  2319.      * console window.  Apparently it's done asynchronously, which may cause
  2320.      * the following screenbuffer switch to go wrong */
  2321.     Sleep(0);
  2322.     check_winsize();
  2323.     g_hCurOut = g_hSavOut;
  2324.     SetConsoleActiveScreenBuffer(g_hCurOut);
  2325.     SetConsoleCursorInfo(g_hCurOut, &g_cci);
  2326.     normvideo();
  2327.     if (!p_rs)
  2328. g_coordOrig.Y = g_srOrigWindowRect.Bottom;
  2329.     SetConsoleCursorPosition(g_hCurOut, g_coordOrig);
  2330.     if (!p_rs)
  2331. copy_screen_buffer_text(g_hConOut, g_hSavOut);
  2332.     clear_chars(g_coordOrig,
  2333. g_srOrigWindowRect.Right - g_srOrigWindowRect.Left + 1);
  2334.     mch_restore_title(3);
  2335.     SetConsoleMode(g_hConIn,  g_cmodein);
  2336.     SetConsoleMode(g_hSavOut, g_cmodeout);
  2337. }
  2338. #endif /* USE_GUI_WIN32 */
  2339. /*
  2340.  * Switching off termcap mode is only allowed when Columns is 80, otherwise a
  2341.  * crash may result.  It's always allowed on NT or when running the GUI.
  2342.  */
  2343.     int
  2344. can_end_termcap_mode(
  2345.     int give_msg)
  2346. {
  2347. #ifdef USE_GUI_WIN32
  2348.     return TRUE; /* GUI starts a new console anyway */
  2349. #else
  2350.     if (g_PlatformId == VER_PLATFORM_WIN32_NT || Columns == 80)
  2351. return TRUE;
  2352.     if (give_msg)
  2353. msg("'columns' is not 80, cannot execute external commands");
  2354.     return FALSE;
  2355. #endif
  2356. }
  2357. #ifdef USE_GUI_WIN32
  2358.     void
  2359. mch_write(
  2360.     char_u  *s,
  2361.     int     len)
  2362. {
  2363.     /* never used */
  2364. }
  2365. #else
  2366. /*
  2367.  * clear `n' chars, starting from `coord'
  2368.  */
  2369.     static void
  2370. clear_chars(
  2371.     COORD coord,
  2372.     DWORD n)
  2373. {
  2374.     DWORD dwDummy;
  2375.     FillConsoleOutputCharacter(g_hCurOut, ' ', n, coord, &dwDummy);
  2376.     FillConsoleOutputAttribute(g_hCurOut, g_attrCurrent, n, coord, &dwDummy);
  2377. }
  2378. /*
  2379.  * Clear the screen
  2380.  */
  2381.     static void
  2382. clear_screen(void)
  2383. {
  2384.     g_coord.X = g_coord.Y = 0;
  2385.     clear_chars(g_coord, Rows * Columns);
  2386. }
  2387. /*
  2388.  * Clear to end of display
  2389.  */
  2390.     static void
  2391. clear_to_end_of_display(void)
  2392. {
  2393.     clear_chars(g_coord, (Rows-g_coord.Y-1) * Columns + (Columns-g_coord.X));
  2394. }
  2395. /*
  2396.  * Clear to end of line
  2397.  */
  2398.     static void
  2399. clear_to_end_of_line(void)
  2400. {
  2401.     clear_chars(g_coord, Columns - g_coord.X);
  2402. }
  2403. /*
  2404.  * Scroll the scroll region up by `cLines' lines
  2405.  */
  2406.     static void
  2407. scroll(
  2408.     unsigned cLines)
  2409. {
  2410.     COORD oldcoord = g_coord;
  2411.     gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Top + 1);
  2412.     delete_lines(cLines);
  2413.     g_coord = oldcoord;
  2414. }
  2415. /*
  2416.  * Set the scroll region
  2417.  */
  2418.     static void
  2419. set_scroll_region(
  2420.     unsigned left,
  2421.     unsigned top,
  2422.     unsigned right,
  2423.     unsigned bottom)
  2424. {
  2425.     if (left >= right
  2426.     || top >= bottom
  2427.     || right > (unsigned) Columns - 1
  2428.     || bottom > (unsigned) Rows - 1)
  2429. return;
  2430.     g_srScrollRegion.Left =   left;
  2431.     g_srScrollRegion.Top =    top;
  2432.     g_srScrollRegion.Right =  right;
  2433.     g_srScrollRegion.Bottom = bottom;
  2434. }
  2435. /*
  2436.  * Insert `cLines' lines at the current cursor position
  2437.  */
  2438.     static void
  2439. insert_lines(
  2440.     unsigned cLines)
  2441. {
  2442.     SMALL_RECT     source;
  2443.     COORD     dest;
  2444.     CHAR_INFO     fill;
  2445.     dest.X = 0;
  2446.     dest.Y = g_coord.Y + cLines;
  2447.     source.Left   = 0;
  2448.     source.Top   = g_coord.Y;
  2449.     source.Right  = g_srScrollRegion.Right;
  2450.     source.Bottom = g_srScrollRegion.Bottom - cLines;
  2451.     fill.Char.AsciiChar = ' ';
  2452.     fill.Attributes = g_attrCurrent;
  2453.     ScrollConsoleScreenBuffer(g_hCurOut, &source, NULL, dest, &fill);
  2454.     /* Here we have to deal with a win32 console flake: If the scroll
  2455.      * region looks like abc and we scroll c to a and fill with d we get
  2456.      * cbd... if we scroll block c one line at a time to a, we get cdd...
  2457.      * vim expects cdd consistently... So we have to deal with that
  2458.      * here... (this also occurs scrolling the same way in the other
  2459.      * direction).  */
  2460.     if (source.Bottom < dest.Y)
  2461.     {
  2462. COORD coord;
  2463. coord.X = 0;
  2464. coord.Y = source.Bottom;
  2465. clear_chars(coord, Columns * (dest.Y - source.Bottom));
  2466.     }
  2467. }
  2468. /*
  2469.  * Delete `cLines' lines at the current cursor position
  2470.  */
  2471.     static void
  2472. delete_lines(
  2473.     unsigned cLines)
  2474. {
  2475.     SMALL_RECT     source;
  2476.     COORD     dest;
  2477.     CHAR_INFO     fill;
  2478.     int     nb;
  2479.     dest.X = 0;
  2480.     dest.Y = g_coord.Y;
  2481.     source.Left   = 0;
  2482.     source.Top   = g_coord.Y + cLines;
  2483.     source.Right  = g_srScrollRegion.Right;
  2484.     source.Bottom = g_srScrollRegion.Bottom;
  2485.     fill.Char.AsciiChar = ' ';
  2486.     fill.Attributes = g_attrCurrent;
  2487.     ScrollConsoleScreenBuffer(g_hCurOut, &source, NULL, dest, &fill);
  2488.     /* Here we have to deal with a win32 console flake: If the scroll
  2489.      * region looks like abc and we scroll c to a and fill with d we get
  2490.      * cbd... if we scroll block c one line at a time to a, we get cdd...
  2491.      * vim expects cdd consistently... So we have to deal with that
  2492.      * here... (this also occurs scrolling the same way in the other
  2493.      * direction).  */
  2494.     nb = dest.Y + (source.Bottom - source.Top) + 1;
  2495.     if (nb < source.Top)
  2496.     {
  2497. COORD coord;
  2498. coord.X = 0;
  2499. coord.Y = nb;
  2500. clear_chars(coord, Columns * (source.Top - nb));
  2501.     }
  2502. }
  2503. /*
  2504.  * Set the cursor position
  2505.  */
  2506.     static void
  2507. gotoxy(
  2508.     unsigned x,
  2509.     unsigned y)
  2510. {
  2511.     COORD coord2;
  2512.     if (x < 1 || x > (unsigned) Columns || y < 1 || y > (unsigned) Rows)
  2513. return;
  2514.     /* Should we check against g_srScrollRegion? */
  2515.     /* external cursor coords are 1-based; internal are 0-based */
  2516.     g_coord.X = coord2.X = x - 1;
  2517.     g_coord.Y = coord2.Y = y - 1;
  2518.     /* If we are using the window buffer that we had upon startup, make
  2519.      * sure to position cursor relative to the window upon that buffer */
  2520.     if (g_hCurOut == g_hSavOut)
  2521.     {
  2522. CONSOLE_SCREEN_BUFFER_INFO csbi;
  2523. GetConsoleScreenBufferInfo(g_hCurOut, &csbi);
  2524. g_srOrigWindowRect = csbi.srWindow;
  2525. coord2.X += (SHORT) (g_srOrigWindowRect.Left);
  2526. coord2.Y += (SHORT) (g_srOrigWindowRect.Bottom + 1 - Rows);
  2527.     }
  2528.     SetConsoleCursorPosition(g_hCurOut, coord2);
  2529. }
  2530. /*
  2531.  * Set the current text attribute = (foreground | background)
  2532.  * See ../doc/os_win32.txt for the numbers.
  2533.  */
  2534.     static void
  2535. textattr(
  2536.     WORD wAttr)
  2537. {
  2538.     g_attrCurrent = wAttr;
  2539.     SetConsoleTextAttribute(g_hCurOut, wAttr);
  2540. }
  2541.     static void
  2542. textcolor(
  2543.     WORD wAttr)
  2544. {
  2545.     g_attrCurrent = (g_attrCurrent & 0xf0) + wAttr;
  2546.     SetConsoleTextAttribute(g_hCurOut, g_attrCurrent);
  2547. }
  2548.     static void
  2549. textbackground(
  2550.     WORD wAttr)
  2551. {
  2552.     g_attrCurrent = (g_attrCurrent & 0x0f) + (wAttr << 4);
  2553.     SetConsoleTextAttribute(g_hCurOut, g_attrCurrent);
  2554. }
  2555. /*
  2556.  * restore the default text attribute (whatever we started with)
  2557.  */
  2558.     static void
  2559. normvideo()
  2560. {
  2561.     textattr(g_attrDefault);
  2562. }
  2563. static WORD g_attrPreStandout = 0;
  2564. /*
  2565.  * Make the text standout, by brightening it
  2566.  */
  2567.     static void
  2568. standout(void)
  2569. {
  2570.     g_attrPreStandout = g_attrCurrent;
  2571.     textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY));
  2572. }
  2573. /*
  2574.  * Turn off standout mode
  2575.  */
  2576.     static void
  2577. standend()
  2578. {
  2579.     if (g_attrPreStandout)
  2580.     {
  2581. textattr(g_attrPreStandout);
  2582. g_attrPreStandout = 0;
  2583.     }
  2584. }
  2585. /*
  2586.  * visual bell: flash the screen
  2587.  */
  2588.     static void
  2589. visual_bell()
  2590. {
  2591.     COORD   coordOrigin = {0, 0};
  2592.     WORD    attrFlash = ~g_attrCurrent & 0xff;
  2593.     DWORD   dwDummy;
  2594.     LPWORD  oldattrs = (LPWORD) alloc(Rows * Columns * sizeof(WORD));
  2595.     ReadConsoleOutputAttribute(g_hCurOut, oldattrs, Rows * Columns,
  2596.        coordOrigin, &dwDummy);
  2597.     FillConsoleOutputAttribute(g_hCurOut, attrFlash, Rows * Columns,
  2598.        coordOrigin, &dwDummy);
  2599.     Sleep(15);     /* wait for 15 msec */
  2600.     WriteConsoleOutputAttribute(g_hCurOut, oldattrs, Rows * Columns,
  2601. coordOrigin, &dwDummy);
  2602.     vim_free(oldattrs);
  2603. }
  2604. /*
  2605.  * Make the cursor visible or invisible
  2606.  */
  2607.     static void
  2608. cursor_visible(
  2609.     BOOL fVisible)
  2610. {
  2611.     s_cursor_visible = fVisible;
  2612.     mch_update_cursor();
  2613. }
  2614. /*
  2615.  * write `cchToWrite' characters in `pchBuf' to the screen
  2616.  */
  2617.     static BOOL
  2618. write_chars(
  2619.     LPCSTR pchBuf,
  2620.     DWORD  cchToWrite,
  2621.     DWORD* pcchWritten)
  2622. {
  2623.     BOOL f;
  2624.     COORD coord2 = g_coord;
  2625.     if (g_hCurOut == g_hSavOut)
  2626.     {
  2627. CONSOLE_SCREEN_BUFFER_INFO csbi;
  2628. GetConsoleScreenBufferInfo(g_hCurOut, &csbi);
  2629. coord2.X += (SHORT) (csbi.srWindow.Left);
  2630. coord2.Y += (SHORT) (csbi.srWindow.Bottom + 1 - Rows);
  2631.     }
  2632.     FillConsoleOutputAttribute(g_hCurOut, g_attrCurrent, cchToWrite,
  2633.        coord2, pcchWritten);
  2634.     f = WriteConsoleOutputCharacter(g_hCurOut, pchBuf, cchToWrite,
  2635.     coord2, pcchWritten);
  2636.     g_coord.X += (SHORT) *pcchWritten;
  2637.     while (g_coord.X > g_srScrollRegion.Right)
  2638.     {
  2639. g_coord.X -= (SHORT) Columns;
  2640. if (g_coord.Y < g_srScrollRegion.Bottom)
  2641.     g_coord.Y++;
  2642.     }
  2643.     gotoxy(g_coord.X + 1, g_coord.Y + 1);
  2644.     return f;
  2645. }
  2646. /*
  2647.  * mch_write(): write the output buffer to the screen, translating ESC
  2648.  * sequences into calls to console output routines.
  2649.  */
  2650.     void
  2651. mch_write(
  2652.     char_u  *s,
  2653.     int     len)
  2654. {
  2655.     s[len] = NUL;
  2656.     if (!term_console)
  2657.     {
  2658. write(1, s, (unsigned) len);
  2659. return;
  2660.     }
  2661.     /* translate ESC | sequences into faked bios calls */
  2662.     while (len--)
  2663.     {
  2664. /* optimization: use one single write_chars for runs of text,
  2665.  * rather than once per character  It ain't curses, but it helps. */
  2666. DWORD  prefix = strcspn(s, "nrba33");
  2667. if (p_wd)
  2668. {
  2669.     WaitForChar(p_wd);
  2670.     if (prefix)
  2671. prefix = 1;
  2672. }
  2673. if (prefix)
  2674. {
  2675.     DWORD nWritten;
  2676.     if (write_chars(s, prefix, &nWritten))
  2677.     {
  2678. #ifdef MCH_WRITE_DUMP
  2679. if (fdDump)
  2680. {
  2681.     fputc('>', fdDump);
  2682.     fwrite(s, sizeof(char_u), nWritten, fdDump);
  2683.     fputs("<n", fdDump);
  2684. }
  2685. #endif
  2686. len -= (nWritten - 1);
  2687. s += nWritten;
  2688.     }
  2689. }
  2690. else if (s[0] == 'n')
  2691. {
  2692.     /* n, newline: go to the beginning of the next line or scroll */
  2693.     if (g_coord.Y == g_srScrollRegion.Bottom)
  2694.     {
  2695. scroll(1);
  2696. gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Bottom + 1);
  2697.     }
  2698.     else
  2699.     {
  2700. gotoxy(g_srScrollRegion.Left + 1, g_coord.Y + 2);
  2701.     }
  2702. #ifdef MCH_WRITE_DUMP
  2703.     if (fdDump)
  2704. fputs("\nn", fdDump);
  2705. #endif
  2706.     s++;
  2707. }
  2708. else if (s[0] == 'r')
  2709. {
  2710.     /* r, carriage return: go to beginning of line */
  2711.     gotoxy(g_srScrollRegion.Left+1, g_coord.Y + 1);
  2712. #ifdef MCH_WRITE_DUMP
  2713.     if (fdDump)
  2714. fputs("\rn", fdDump);
  2715. #endif
  2716.     s++;
  2717. }
  2718. else if (s[0] == 'b')
  2719. {
  2720.     /* b, backspace: move cursor one position left */
  2721.     if (g_coord.X > g_srScrollRegion.Left)
  2722. g_coord.X--;
  2723.     else if (g_coord.Y > g_srScrollRegion.Top)
  2724.     {
  2725. g_coord.X = g_srScrollRegion.Right;
  2726. g_coord.Y--;
  2727.     }
  2728.     gotoxy(g_coord.X + 1, g_coord.Y + 1);
  2729. #ifdef MCH_WRITE_DUMP
  2730.     if (fdDump)
  2731. fputs("\bn", fdDump);
  2732. #endif
  2733.     s++;
  2734. }
  2735. else if (s[0] == 'a')
  2736. {
  2737.     /* a, bell */
  2738.     MessageBeep(0xFFFFFFFF);
  2739. #ifdef MCH_WRITE_DUMP
  2740.     if (fdDump)
  2741. fputs("\an", fdDump);
  2742. #endif
  2743.     s++;
  2744. }
  2745. else if (s[0] == ESC && len >= 3-1 && s[1] == '|')
  2746. {
  2747. #ifdef MCH_WRITE_DUMP
  2748.     char_u* old_s = s;
  2749. #endif
  2750.     char_u* p;
  2751.     int arg1 = 0, arg2 = 0;
  2752.     switch (s[2])
  2753.     {
  2754.     /* one or two numeric arguments, separated by ';' */
  2755.     case '0': case '1': case '2': case '3': case '4':
  2756.     case '5': case '6': case '7': case '8': case '9':
  2757. p = s + 2;
  2758. arg1 = getdigits(&p);     /* no check for length! */
  2759. if (p > s + len)
  2760.     break;
  2761. if (*p == ';')
  2762. {
  2763.     ++p;
  2764.     arg2 = getdigits(&p);   /* no check for length! */
  2765.     if (p > s + len)
  2766. break;
  2767.     if (*p == 'H')
  2768. gotoxy(arg2, arg1);
  2769.     else if (*p == 'r')
  2770. set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1);
  2771. }
  2772. else if (*p == 'A')
  2773. {
  2774.     /* move cursor up arg1 lines in same column */
  2775.     gotoxy(g_coord.X + 1,
  2776.    max(g_srScrollRegion.Top, g_coord.Y - arg1) + 1);
  2777. }
  2778. else if (*p == 'C')
  2779. {
  2780.     /* move cursor right arg1 columns in same line */
  2781.     gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1,
  2782.    g_coord.Y + 1);
  2783. }
  2784. else if (*p == 'H')
  2785. {
  2786.     gotoxy(1, arg1);
  2787. }
  2788. else if (*p == 'L')
  2789. {
  2790.     insert_lines(arg1);
  2791. }
  2792. else if (*p == 'm')
  2793. {
  2794.     if (arg1 == 0)
  2795. normvideo();
  2796.     else
  2797. textattr((WORD) arg1);
  2798. }
  2799. else if (*p == 'f')
  2800. {
  2801.     textcolor((WORD) arg1);
  2802. }
  2803. else if (*p == 'b')
  2804. {
  2805.     textbackground((WORD) arg1);
  2806. }
  2807. else if (*p == 'M')
  2808. {
  2809.     delete_lines(arg1);
  2810. }
  2811. len -= p - s;
  2812. s = p + 1;
  2813. break;
  2814.     /* Three-character escape sequences */
  2815.     case 'A':
  2816. /* move cursor up one line in same column */
  2817. gotoxy(g_coord.X + 1,
  2818.        max(g_srScrollRegion.Top, g_coord.Y - 1) + 1);
  2819. goto got3;
  2820.     case 'B':
  2821. visual_bell();
  2822. goto got3;
  2823.     case 'C':
  2824. /* move cursor right one column in same line */
  2825. gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1,
  2826.        g_coord.Y + 1);
  2827. goto got3;
  2828.     case 'E':
  2829. termcap_mode_end();
  2830. goto got3;
  2831.     case 'F':
  2832. standout();
  2833. goto got3;
  2834.     case 'f':
  2835. standend();
  2836. goto got3;
  2837.     case 'H':
  2838. gotoxy(1, 1);
  2839. goto got3;
  2840.     case 'j':
  2841. clear_to_end_of_display();
  2842. goto got3;
  2843.     case 'J':
  2844. clear_screen();
  2845. goto got3;
  2846.     case 'K':
  2847. clear_to_end_of_line();
  2848. goto got3;
  2849.     case 'L':
  2850. insert_lines(1);
  2851. goto got3;
  2852.     case 'M':
  2853. delete_lines(1);
  2854. goto got3;
  2855.     case 'S':
  2856. termcap_mode_start();
  2857. goto got3;
  2858.     case 'V':
  2859. cursor_visible(TRUE);
  2860. goto got3;
  2861.     case 'v':
  2862. cursor_visible(FALSE);
  2863. goto got3;
  2864.     got3:
  2865. s += 3;
  2866. len -= 2;
  2867.     }
  2868. #ifdef MCH_WRITE_DUMP
  2869.     if (fdDump)
  2870.     {
  2871. fputs("ESC | ", fdDump);
  2872. fwrite(old_s + 2, sizeof(char_u), s - old_s - 2, fdDump);
  2873. fputc('n', fdDump);
  2874.     }
  2875. #endif
  2876. }
  2877. else
  2878. {
  2879.     /* Write a single character */
  2880.     DWORD nWritten;
  2881.     if (write_chars(s, 1, &nWritten))
  2882.     {
  2883. #ifdef MCH_WRITE_DUMP
  2884. if (fdDump)
  2885. {
  2886.     fputc('>', fdDump);
  2887.     fwrite(s, sizeof(char_u), nWritten, fdDump);
  2888.     fputs("<n", fdDump);
  2889. }
  2890. #endif
  2891. len -= (nWritten - 1);
  2892. s += nWritten;
  2893.     }
  2894. }
  2895.     }
  2896. #ifdef MCH_WRITE_DUMP
  2897.     if (fdDump)
  2898. fflush(fdDump);
  2899. #endif
  2900. }
  2901. #endif /* USE_GUI_WIN32 */
  2902. /*
  2903.  * Delay for half a second.
  2904.  */
  2905.     void
  2906. mch_delay(
  2907.     long    msec,
  2908.     int     ignoreinput)
  2909. {
  2910. #ifdef USE_GUI_WIN32
  2911.     Sleep((int)msec);     /* never wait for input */
  2912. #else
  2913.     if (ignoreinput)
  2914. Sleep((int)msec);
  2915.     else
  2916. WaitForChar(msec);
  2917. #endif
  2918. }
  2919. /*
  2920.  * this version of remove is not scared by a readonly (backup) file
  2921.  */
  2922.     int
  2923. mch_remove(char_u *name)
  2924. {
  2925.     SetFileAttributes(name, FILE_ATTRIBUTE_NORMAL);
  2926.     return DeleteFile(name) ? 0 : -1;
  2927. }
  2928. /*
  2929.  * check for an "interrupt signal": CTRL-break or CTRL-C
  2930.  */
  2931.     void
  2932. mch_breakcheck()
  2933. {
  2934. #ifndef USE_GUI_WIN32     /* never used */
  2935.     if (g_fCtrlCPressed || g_fCBrkPressed)
  2936.     {
  2937. g_fCtrlCPressed = g_fCBrkPressed = FALSE;
  2938. got_int = TRUE;
  2939.     }
  2940. #endif
  2941. }
  2942. /*
  2943.  * How much memory is available?
  2944.  */
  2945.     long_u
  2946. mch_avail_mem(
  2947.     int special)
  2948. {
  2949.     return LONG_MAX;     /* virtual memory, eh? */
  2950. }
  2951. /*
  2952.  * return non-zero if a character is available
  2953.  */
  2954.     int
  2955. mch_char_avail()
  2956. {
  2957. #ifdef USE_GUI_WIN32
  2958.     /* never used */
  2959.     return TRUE;
  2960. #else
  2961.     return WaitForChar(0L);
  2962. #endif
  2963. }
  2964. /*
  2965.  * set screen mode, always fails.
  2966.  */
  2967.     int
  2968. mch_screenmode(
  2969.     char_u *arg)
  2970. {
  2971.     EMSG("Screen mode setting not supported");
  2972.     return FAIL;
  2973. }
  2974. /*
  2975.  * mch_rename() works around a bug in rename (aka MoveFile) in
  2976.  * Windows 95: rename("foo.bar", "foo.bar~") will generate a
  2977.  * file whose short file name is "FOO.BAR" (its long file name will
  2978.  * be correct: "foo.bar~").  Because a file can be accessed by
  2979.  * either its SFN or its LFN, "foo.bar" has effectively been
  2980.  * renamed to "foo.bar", which is not at all what was wanted.  This
  2981.  * seems to happen only when renaming files with three-character
  2982.  * extensions by appending a suffix that does not include ".".
  2983.  * Windows NT gets it right, however, with an SFN of "FOO~1.BAR".
  2984.  *
  2985.  * Like rename(), returns 0 upon success, non-zero upon failure.
  2986.  * Should probably set errno appropriately when errors occur.
  2987.  */
  2988.     int
  2989. mch_rename(
  2990.     const char *pszOldFile,
  2991.     const char *pszNewFile)
  2992. {
  2993.     char szTempFile[_MAX_PATH+1];
  2994.     char szNewPath[_MAX_PATH+1];
  2995.     char *pszFilePart;
  2996.     HANDLE hf;
  2997.     /*
  2998.      * No need to play tricks if not running Windows 95
  2999.      */
  3000.     if (!mch_windows95())
  3001. return rename(pszOldFile, pszNewFile);
  3002.     /* get base path of new file name */
  3003.     if (GetFullPathName(pszNewFile, _MAX_PATH, szNewPath, &pszFilePart) == 0)
  3004. return -1;
  3005.     else
  3006. *pszFilePart = NUL;
  3007.     /* Get (and create) a unique temporary file name in directory of new file */
  3008.     if (GetTempFileName(szNewPath, "VIM", 0, szTempFile) == 0)
  3009. return -2;
  3010.     /* blow the temp file away */
  3011.     if (!DeleteFile(szTempFile))
  3012. return -3;
  3013.     /* rename old file to the temp file */
  3014.     if (!MoveFile(pszOldFile, szTempFile))
  3015. return -4;
  3016.     /* now create an empty file called pszOldFile; this prevents the operating
  3017.      * system using pszOldFile as an alias (SFN) if we're renaming within the
  3018.      * same directory.  For example, we're editing a file called
  3019.      * filename.asc.txt by its SFN, filena~1.txt.  If we rename filena~1.txt
  3020.      * to filena~1.txt~ (i.e., we're making a backup while writing it), the
  3021.      * SFN for filena~1.txt~ will be filena~1.txt, by default, which will
  3022.      * cause all sorts of problems later in buf_write.  So, we create an empty
  3023.      * file called filena~1.txt and the system will have to find some other
  3024.      * SFN for filena~1.txt~, such as filena~2.txt
  3025.      */
  3026.     if ((hf = CreateFile(pszOldFile, GENERIC_WRITE, 0, NULL, CREATE_NEW,
  3027.     FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
  3028. return -5;
  3029.     if (!CloseHandle(hf))
  3030. return -6;
  3031.     /* rename the temp file to the new file */
  3032.     if (!MoveFile(szTempFile, pszNewFile))
  3033. return -7;
  3034.     /* Seems to be left around on Novell filesystems */
  3035.     DeleteFile(szTempFile);
  3036.     /* finally, remove the empty old file */
  3037.     if (!DeleteFile(pszOldFile))
  3038. return -8;
  3039.     return 0; /* success */
  3040. }
  3041. /*
  3042.  * Special version of getenv(): use $HOME when $VIM not defined.
  3043.  */
  3044.     char_u *
  3045. mch_getenv(char_u *var)
  3046. {
  3047.     char_u  *retval;
  3048.     retval = (char_u *)getenv((char *)var);
  3049.     if (retval == NULL && STRCMP(var, "VIM") == 0)
  3050. retval = (char_u *)getenv("HOME");
  3051. #ifdef MCH_WRITE_DUMP
  3052.     if (fdDump)
  3053.     {
  3054. fprintf(fdDump, "$%s = "%s"n", var, retval);
  3055. fflush(fdDump);
  3056.     }
  3057. #endif
  3058.     return retval;
  3059. }
  3060. /*
  3061.  * Get the default shell for the current hardware platform
  3062.  */
  3063.     char*
  3064. default_shell()
  3065. {
  3066.     char* psz = NULL;
  3067.     PlatformId();
  3068.     if (g_PlatformId == VER_PLATFORM_WIN32_NT) /* Windows NT */
  3069. psz = "cmd.exe";
  3070.     else if (g_PlatformId == VER_PLATFORM_WIN32_WINDOWS) /* Windows 95 */
  3071. psz = "command.com";
  3072.     return psz;
  3073. }
  3074. #ifdef USE_CLIPBOARD
  3075. /*
  3076.  * Clipboard stuff, for cutting and pasting text to other windows.
  3077.  */
  3078. /*
  3079.  * Get the current selection and put it in the clipboard register.
  3080.  *
  3081.  * NOTE: Must use GlobalLock/Unlock here to ensure Win32s compatibility.
  3082.  * On NT/W95 the clipboard data is a fixed global memory object and
  3083.  * so its handle = its pointer.
  3084.  * On Win32s, however, co-operation with the Win16 system means that
  3085.  * the clipboard data is moveable and its handle is not a pointer at all,
  3086.  * so we can't just cast the return value of GetClipboardData to (char_u*).
  3087.  * <VN>
  3088.  */
  3089.     void
  3090. clip_mch_request_selection()
  3091. {
  3092.     int     type;
  3093.     HGLOBAL hMem;
  3094.     char_u  *str = NULL;
  3095.     /*
  3096.      * Don't pass GetActiveWindow() as an argument to OpenClipboard() because
  3097.      * then we can't paste back into the same window for some reason - webb.
  3098.      */
  3099.     if (OpenClipboard(NULL))
  3100.     {
  3101. /* Check for vim's own clipboard format first */
  3102. if ((hMem = GetClipboardData(clipboard.format)) != NULL)
  3103. {
  3104.     str = (char_u *)GlobalLock(hMem);
  3105.     if (str != NULL)
  3106. switch (*str++)
  3107. {
  3108.     default:
  3109.     case 'L': type = MLINE; break;
  3110.     case 'C': type = MCHAR; break;
  3111.     case 'B': type = MBLOCK; break;
  3112. }
  3113. /* TRACE("Got '%c' typen", str[-1]); */
  3114. }
  3115. /* Otherwise, check for the normal text format */
  3116. else if ((hMem = GetClipboardData(CF_TEXT)) != NULL)
  3117. {
  3118.     str = (char_u *)GlobalLock(hMem);
  3119.     if (str != NULL)
  3120. type = (vim_strchr((char*) str, 'r') != NULL) ? MLINE : MCHAR;
  3121.     /* TRACE("TEXTn"); */
  3122. }
  3123. if (hMem != NULL && str != NULL)
  3124. {
  3125.     /*successful lock - must unlock when finished*/
  3126.     if (*str != NUL)
  3127.     {
  3128. LPCSTR psz = (LPCSTR)str;
  3129. char_u *temp_clipboard = (char_u *)lalloc(STRLEN(psz) + 1, TRUE);
  3130. char_u *pszTemp = temp_clipboard;
  3131. if (temp_clipboard != NULL)
  3132. {
  3133.     while (*psz != NUL)
  3134.     {
  3135. const char* pszNL = strchr(psz, 'r');
  3136. const int len = (pszNL != NULL) ?
  3137.     pszNL - psz : STRLEN(psz);
  3138. STRNCPY(pszTemp, psz, len);
  3139. pszTemp += len;
  3140. if (pszNL != NULL)
  3141.     *pszTemp++ = 'n';
  3142. psz += len + ((pszNL != NULL) ? 2 : 0);
  3143.     }
  3144.     *pszTemp = NUL;
  3145.     clip_yank_selection(type, temp_clipboard,
  3146. (long)(pszTemp - temp_clipboard));
  3147.     vim_free(temp_clipboard);
  3148. }
  3149.     }
  3150.     /*unlock the global object*/
  3151.     (void)GlobalUnlock(hMem);
  3152. }
  3153. CloseClipboard();
  3154.     }
  3155. }
  3156. /*
  3157.  * Make vim the owner of the current selection.
  3158.  */
  3159.     void
  3160. clip_mch_lose_selection()
  3161. {
  3162.     /* Nothing needs to be done here */
  3163. }
  3164. /*
  3165.  * Make vim the owner of the current selection.  Return OK upon success.
  3166.  */
  3167.     int
  3168. clip_mch_own_selection()
  3169. {
  3170.     /*
  3171.      * Never actually own the clipboard.  If another application sets the
  3172.      * clipboard, we don't want to think that we still own it.
  3173.      */
  3174.     return FAIL;
  3175. }
  3176. /*
  3177.  * Send the current selection to the clipboard.
  3178.  */
  3179.     void
  3180. clip_mch_set_selection()
  3181. {
  3182.     char_u  *str = NULL;
  3183.     long_u  cch;
  3184.     int     type;
  3185.     HGLOBAL hMem = NULL;
  3186.     HGLOBAL hMemVim = NULL;
  3187.     LPSTR   lpszMem = NULL;
  3188.     LPSTR   lpszMemVim = NULL;
  3189.     /* If the '*' register isn't already filled in, fill it in now */
  3190.     clipboard.owned = TRUE;
  3191.     clip_get_selection();
  3192.     clipboard.owned = FALSE;
  3193.     type = clip_convert_selection(&str, &cch);
  3194.     if (type < 0)
  3195. return;
  3196.     if ((hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cch+1)) != NULL
  3197. && (lpszMem = (LPSTR)GlobalLock(hMem)) != NULL
  3198. && (hMemVim = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, cch+2)) != NULL
  3199. && (lpszMemVim = (LPSTR)GlobalLock(hMemVim)) != NULL)
  3200.     {
  3201. switch (type)
  3202. {
  3203.     default:
  3204.     case MLINE:     *lpszMemVim++ = 'L';    break;
  3205.     case MCHAR:     *lpszMemVim++ = 'C';    break;
  3206.     case MBLOCK:    *lpszMemVim++ = 'B';    break;
  3207. }
  3208. STRNCPY(lpszMem, str, cch);
  3209. lpszMem[cch] = NUL;
  3210. STRNCPY(lpszMemVim, str, cch);
  3211. lpszMemVim[cch] = NUL;
  3212. /*
  3213.  * Don't pass GetActiveWindow() as an argument to OpenClipboard()
  3214.  * because then we can't paste back into the same window for some
  3215.  * reason - webb.
  3216.  */
  3217. if (OpenClipboard(NULL))
  3218. {
  3219.     if (EmptyClipboard())
  3220.     {
  3221. SetClipboardData(clipboard.format, hMemVim);
  3222. SetClipboardData(CF_TEXT, hMem);
  3223.     }
  3224.     CloseClipboard();
  3225. }
  3226.     }
  3227.     if (lpszMem != NULL)
  3228. GlobalUnlock(hMem);
  3229.     if (lpszMemVim != NULL)
  3230. GlobalUnlock(hMemVim);
  3231.     vim_free(str);
  3232. }
  3233. #endif /* USE_CLIPBOARD */
  3234. /*
  3235.  * Debugging helper: expose the MCH_WRITE_DUMP stuff to other modules
  3236.  */
  3237.     void
  3238. DumpPutS(
  3239.     const char* psz)
  3240. {
  3241. # ifdef MCH_WRITE_DUMP
  3242.     if (fdDump)
  3243.     {
  3244. fputs(psz, fdDump);
  3245. if (psz[strlen(psz) - 1] != 'n')
  3246.     fputc('n', fdDump);
  3247. fflush(fdDump);
  3248.     }
  3249. # endif
  3250. }
  3251. #ifdef _DEBUG
  3252. void __cdecl
  3253. Trace(
  3254.     char *pszFormat,
  3255.     ...)
  3256. {
  3257.     CHAR szBuff[2048];
  3258.     va_list args;
  3259.     va_start(args, pszFormat);
  3260.     vsprintf(szBuff, pszFormat, args);
  3261.     va_end(args);
  3262.     OutputDebugString(szBuff);
  3263. }
  3264. #endif //_DEBUG