1 /* vi:set ts=8 sts=4 sw=4 noet:
3 * VIM - Vi IMproved by Bram Moolenaar
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 * See README.txt for an overview of the Vim source code.
12 * Used for both the console version and the Win32 GUI. A lot of code is for
13 * the console version only, so there is a lot of "#ifndef FEAT_GUI_W32".
15 * Win32 (Windows NT and Windows 95) system-dependent routines.
16 * Portions lifted from the Win32 SDK samples, the MSDOS-dependent code,
17 * NetHack 3.1.3, GNU Emacs 19.30, and Vile 5.5.
19 * George V. Reilly <george@reilly.org> wrote most of this.
20 * Roger Knobbe <rogerk@wonderware.com> did the initial port of Vim 3.0.
26 # include "if_mzsch.h"
29 #include <sys/types.h>
33 /* cproto fails on missing include files */
48 # if defined(FEAT_TITLE) && !defined(FEAT_GUI_W32)
49 # include <shellapi.h>
53 #ifdef FEAT_JOB_CHANNEL
54 # include <tlhelp32.h>
58 # ifndef FROM_LEFT_1ST_BUTTON_PRESSED
59 # define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
61 # ifndef RIGHTMOST_BUTTON_PRESSED
62 # define RIGHTMOST_BUTTON_PRESSED 0x0002
64 # ifndef FROM_LEFT_2ND_BUTTON_PRESSED
65 # define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004
67 # ifndef FROM_LEFT_3RD_BUTTON_PRESSED
68 # define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008
70 # ifndef FROM_LEFT_4TH_BUTTON_PRESSED
71 # define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010
78 # define MOUSE_MOVED 0x0001
81 # define DOUBLE_CLICK 0x0002
85 /* Record all output and all keyboard & mouse input */
86 /* #define MCH_WRITE_DUMP */
93 * When generating prototypes for Win32 on Unix, these lines make the syntax
94 * errors disappear. They do not need to be correct.
98 typedef char * LPCSTR;
99 typedef char * LPWSTR;
100 typedef int ACCESS_MASK;
102 typedef int COLORREF;
103 typedef int CONSOLE_CURSOR_INFO;
107 typedef int LPHANDLE;
111 typedef int HINSTANCE;
113 typedef int INPUT_RECORD;
114 typedef int KEY_EVENT_RECORD;
122 typedef int MOUSE_EVENT_RECORD;
126 typedef int PRINTDLG;
127 typedef int PSECURITY_DESCRIPTOR;
129 typedef int SECURITY_INFORMATION;
131 typedef int SMALL_RECT;
132 typedef int TEXTMETRIC;
133 typedef int TOKEN_INFORMATION_CLASS;
138 typedef int BY_HANDLE_FILE_INFORMATION;
139 typedef int SE_OBJECT_TYPE;
140 typedef int PSNSECINFO;
141 typedef int PSNSECINFOW;
142 typedef int STARTUPINFO;
143 typedef int PROCESS_INFORMATION;
144 typedef int LPSECURITY_ATTRIBUTES;
145 # define __stdcall /* empty */
148 #if defined(__BORLANDC__)
149 /* Strangely Borland uses a non-standard name. */
150 # define wcsicmp(a, b) wcscmpi((a), (b))
154 /* Win32 Console handles for input and output */
155 static HANDLE g_hConIn = INVALID_HANDLE_VALUE;
156 static HANDLE g_hConOut = INVALID_HANDLE_VALUE;
158 /* Win32 Screen buffer,coordinate,console I/O information */
159 static SMALL_RECT g_srScrollRegion;
160 static COORD g_coord; /* 0-based, but external coords are 1-based */
162 /* The attribute of the screen when the editor was started */
163 static WORD g_attrDefault = 7; /* lightgray text on black background */
164 static WORD g_attrCurrent;
166 static int g_fCBrkPressed = FALSE; /* set by ctrl-break interrupt */
167 static int g_fCtrlCPressed = FALSE; /* set when ctrl-C or ctrl-break detected */
168 static int g_fForceExit = FALSE; /* set when forcefully exiting */
170 static void termcap_mode_start(void);
171 static void termcap_mode_end(void);
172 static void clear_chars(COORD coord, DWORD n);
173 static void clear_screen(void);
174 static void clear_to_end_of_display(void);
175 static void clear_to_end_of_line(void);
176 static void scroll(unsigned cLines);
177 static void set_scroll_region(unsigned left, unsigned top,
178 unsigned right, unsigned bottom);
179 static void insert_lines(unsigned cLines);
180 static void delete_lines(unsigned cLines);
181 static void gotoxy(unsigned x, unsigned y);
182 static void normvideo(void);
183 static void textattr(WORD wAttr);
184 static void textcolor(WORD wAttr);
185 static void textbackground(WORD wAttr);
186 static void standout(void);
187 static void standend(void);
188 static void visual_bell(void);
189 static void cursor_visible(BOOL fVisible);
190 static DWORD write_chars(char_u *pchBuf, DWORD cbToWrite);
191 static void create_conin(void);
192 static int s_cursor_visible = TRUE;
193 static int did_create_conin = FALSE;
195 static int s_dont_use_vimrun = TRUE;
196 static int need_vimrun_warning = FALSE;
197 static char *vimrun_path = "vimrun ";
200 static int win32_getattrs(char_u *name);
201 static int win32_setattrs(char_u *name, int attrs);
202 static int win32_set_archive(char_u *name);
205 static int suppress_winsize = 1; /* don't fiddle with console */
208 static char_u *exe_path = NULL;
210 static BOOL win8_or_later = FALSE;
214 * Version of ReadConsoleInput() that works with IME.
215 * Works around problems on Windows 8.
220 INPUT_RECORD *lpBuffer,
228 static INPUT_RECORD s_irCache[IRSIZE];
229 static DWORD s_dwIndex = 0;
230 static DWORD s_dwMax = 0;
237 return (s_dwMax > 0) ? TRUE : FALSE;
242 return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
243 return ReadConsoleInputW(hInput, lpBuffer, 1, &dwEvents);
249 return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
250 if (!ReadConsoleInputW(hInput, s_irCache, IRSIZE, &dwEvents))
266 if (s_irCache[head].EventType == WINDOW_BUFFER_SIZE_EVENT
267 && s_irCache[head + 1].EventType
268 == WINDOW_BUFFER_SIZE_EVENT)
270 /* Remove duplicate event to avoid flicker. */
271 for (i = head; i < tail; ++i)
272 s_irCache[i] = s_irCache[i + 1];
282 *lpBuffer = s_irCache[s_dwIndex];
283 if (!(nLength == -1 || nLength == -2) && ++s_dwIndex >= s_dwMax)
290 * Version of PeekConsoleInput() that works with IME.
295 INPUT_RECORD *lpBuffer,
299 return read_console_input(hInput, lpBuffer, -1, lpEvents);
302 # ifdef FEAT_CLIENTSERVER
304 msg_wait_for_multiple_objects(
308 DWORD dwMilliseconds,
311 if (read_console_input(NULL, NULL, -2, NULL))
312 return WAIT_OBJECT_0;
313 return MsgWaitForMultipleObjects(nCount, pHandles, fWaitAll,
314 dwMilliseconds, dwWakeMask);
318 # ifndef FEAT_CLIENTSERVER
320 wait_for_single_object(
322 DWORD dwMilliseconds)
324 if (read_console_input(NULL, NULL, -2, NULL))
325 return WAIT_OBJECT_0;
326 return WaitForSingleObject(hHandle, dwMilliseconds);
334 /* Maximum length of $PATH is more than MAXPATHL. 8191 is often mentioned
335 * as the maximum length that works (plus a NUL byte). */
336 #define MAX_ENV_PATH_LEN 8192
337 char temp[MAX_ENV_PATH_LEN];
340 if (exe_name == NULL)
342 /* store the name of the executable, may be used for $VIM */
343 GetModuleFileName(NULL, temp, MAX_ENV_PATH_LEN - 1);
345 exe_name = FullName_save((char_u *)temp, FALSE);
348 if (exe_path == NULL && exe_name != NULL)
350 exe_path = vim_strnsave(exe_name,
351 (int)(gettail_sep(exe_name) - exe_name));
352 if (exe_path != NULL)
354 /* Append our starting directory to $PATH, so that when doing
355 * "!xxd" it's found in our starting directory. Needed because
356 * SearchPath() also looks there. */
357 p = mch_getenv("PATH");
359 || STRLEN(p) + STRLEN(exe_path) + 2 < MAX_ENV_PATH_LEN)
361 if (p == NULL || *p == NUL)
368 STRCAT(temp, exe_path);
369 vim_setenv((char_u *)"PATH", (char_u *)temp);
376 * Unescape characters in "p" that appear in "escaped".
379 unescape_shellxquote(char_u *p, char_u *escaped)
381 int l = (int)STRLEN(p);
386 if (*p == '^' && vim_strchr(escaped, p[1]) != NULL)
387 mch_memmove(p, p + 1, l--);
389 n = (*mb_ptr2len)(p);
399 * Load library "name".
402 vimLoadLib(char *name)
404 HINSTANCE dll = NULL;
406 /* NOTE: Do not use mch_dirname() and mch_chdir() here, they may call
407 * vimLoadLib() recursively, which causes a stack overflow. */
408 if (exe_path == NULL)
410 if (exe_path != NULL)
412 WCHAR old_dirw[MAXPATHL];
414 if (GetCurrentDirectoryW(MAXPATHL, old_dirw) != 0)
416 /* Change directory to where the executable is, both to make
417 * sure we find a .dll there and to avoid looking for a .dll
418 * in the current directory. */
419 SetCurrentDirectory((LPCSTR)exe_path);
420 dll = LoadLibrary(name);
421 SetCurrentDirectoryW(old_dirw);
428 #if defined(DYNAMIC_ICONV) || defined(DYNAMIC_GETTEXT) || defined(PROTO)
430 * Get related information about 'funcname' which is imported by 'hInst'.
431 * If 'info' is 0, return the function address.
432 * If 'info' is 1, return the module name which the function is imported from.
435 get_imported_func_info(HINSTANCE hInst, const char *funcname, int info)
437 PBYTE pImage = (PBYTE)hInst;
438 PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)hInst;
439 PIMAGE_NT_HEADERS pPE;
440 PIMAGE_IMPORT_DESCRIPTOR pImpDesc;
441 PIMAGE_THUNK_DATA pIAT; /* Import Address Table */
442 PIMAGE_THUNK_DATA pINT; /* Import Name Table */
443 PIMAGE_IMPORT_BY_NAME pImpName;
445 if (pDOS->e_magic != IMAGE_DOS_SIGNATURE)
447 pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew);
448 if (pPE->Signature != IMAGE_NT_SIGNATURE)
450 pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage
451 + pPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
453 for (; pImpDesc->FirstThunk; ++pImpDesc)
455 if (!pImpDesc->OriginalFirstThunk)
457 pIAT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->FirstThunk);
458 pINT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->OriginalFirstThunk);
459 for (; pIAT->u1.Function; ++pIAT, ++pINT)
461 if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))
463 pImpName = (PIMAGE_IMPORT_BY_NAME)(pImage
464 + (UINT_PTR)(pINT->u1.AddressOfData));
465 if (strcmp((char *)pImpName->Name, funcname) == 0)
470 return (void *)pIAT->u1.Function;
472 return (void *)(pImage + pImpDesc->Name);
483 * Get the module handle which 'funcname' in 'hInst' is imported from.
486 find_imported_module_by_funcname(HINSTANCE hInst, const char *funcname)
490 modulename = (char *)get_imported_func_info(hInst, funcname, 1);
491 if (modulename != NULL)
492 return GetModuleHandleA(modulename);
497 * Get the address of 'funcname' which is imported by 'hInst' DLL.
500 get_dll_import_func(HINSTANCE hInst, const char *funcname)
502 return get_imported_func_info(hInst, funcname, 0);
506 #if defined(DYNAMIC_GETTEXT) || defined(PROTO)
508 # define GETTEXT_DLL "libintl.dll"
509 # define GETTEXT_DLL_ALT "libintl-8.dll"
511 /* Dummy functions */
512 static char *null_libintl_gettext(const char *);
513 static char *null_libintl_ngettext(const char *, const char *, unsigned long n);
514 static char *null_libintl_textdomain(const char *);
515 static char *null_libintl_bindtextdomain(const char *, const char *);
516 static char *null_libintl_bind_textdomain_codeset(const char *, const char *);
517 static int null_libintl_putenv(const char *);
518 static int null_libintl_wputenv(const wchar_t *);
520 static HINSTANCE hLibintlDLL = NULL;
521 char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext;
522 char *(*dyn_libintl_ngettext)(const char *, const char *, unsigned long n)
523 = null_libintl_ngettext;
524 char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain;
525 char *(*dyn_libintl_bindtextdomain)(const char *, const char *)
526 = null_libintl_bindtextdomain;
527 char *(*dyn_libintl_bind_textdomain_codeset)(const char *, const char *)
528 = null_libintl_bind_textdomain_codeset;
529 int (*dyn_libintl_putenv)(const char *) = null_libintl_putenv;
530 int (*dyn_libintl_wputenv)(const wchar_t *) = null_libintl_wputenv;
533 dyn_libintl_init(void)
542 {"gettext", (FARPROC*)&dyn_libintl_gettext},
543 {"ngettext", (FARPROC*)&dyn_libintl_ngettext},
544 {"textdomain", (FARPROC*)&dyn_libintl_textdomain},
545 {"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain},
550 /* No need to initialize twice. */
553 /* Load gettext library (libintl.dll) */
554 hLibintlDLL = vimLoadLib(GETTEXT_DLL);
555 #ifdef GETTEXT_DLL_ALT
557 hLibintlDLL = vimLoadLib(GETTEXT_DLL_ALT);
564 EMSG2(_(e_loadlib), GETTEXT_DLL);
569 for (i = 0; libintl_entry[i].name != NULL
570 && libintl_entry[i].ptr != NULL; ++i)
572 if ((*libintl_entry[i].ptr = (FARPROC)GetProcAddress(hLibintlDLL,
573 libintl_entry[i].name)) == NULL)
579 EMSG2(_(e_loadfunc), libintl_entry[i].name);
586 /* The bind_textdomain_codeset() function is optional. */
587 dyn_libintl_bind_textdomain_codeset = (void *)GetProcAddress(hLibintlDLL,
588 "bind_textdomain_codeset");
589 if (dyn_libintl_bind_textdomain_codeset == NULL)
590 dyn_libintl_bind_textdomain_codeset =
591 null_libintl_bind_textdomain_codeset;
593 /* _putenv() function for the libintl.dll is optional. */
594 hmsvcrt = find_imported_module_by_funcname(hLibintlDLL, "getenv");
597 dyn_libintl_putenv = (void *)GetProcAddress(hmsvcrt, "_putenv");
598 dyn_libintl_wputenv = (void *)GetProcAddress(hmsvcrt, "_wputenv");
600 if (dyn_libintl_putenv == NULL || dyn_libintl_putenv == _putenv)
601 dyn_libintl_putenv = null_libintl_putenv;
602 if (dyn_libintl_wputenv == NULL || dyn_libintl_wputenv == _wputenv)
603 dyn_libintl_wputenv = null_libintl_wputenv;
609 dyn_libintl_end(void)
612 FreeLibrary(hLibintlDLL);
614 dyn_libintl_gettext = null_libintl_gettext;
615 dyn_libintl_ngettext = null_libintl_ngettext;
616 dyn_libintl_textdomain = null_libintl_textdomain;
617 dyn_libintl_bindtextdomain = null_libintl_bindtextdomain;
618 dyn_libintl_bind_textdomain_codeset = null_libintl_bind_textdomain_codeset;
619 dyn_libintl_putenv = null_libintl_putenv;
620 dyn_libintl_wputenv = null_libintl_wputenv;
624 null_libintl_gettext(const char *msgid)
630 null_libintl_ngettext(
632 const char *msgid_plural,
635 return (char *)(n == 1 ? msgid : msgid_plural);
639 null_libintl_bindtextdomain(
640 const char *domainname UNUSED,
641 const char *dirname UNUSED)
647 null_libintl_bind_textdomain_codeset(
648 const char *domainname UNUSED,
649 const char *codeset UNUSED)
655 null_libintl_textdomain(const char *domainname UNUSED)
661 null_libintl_putenv(const char *envstring UNUSED)
667 null_libintl_wputenv(const wchar_t *envstring UNUSED)
672 #endif /* DYNAMIC_GETTEXT */
674 /* This symbol is not defined in older versions of the SDK or Visual C++ */
676 #ifndef VER_PLATFORM_WIN32_WINDOWS
677 # define VER_PLATFORM_WIN32_WINDOWS 1
686 # ifndef PROTECTED_DACL_SECURITY_INFORMATION
687 # define PROTECTED_DACL_SECURITY_INFORMATION 0x80000000L
693 * Enables or disables the specified privilege.
696 win32_enable_privilege(LPTSTR lpszPrivilege, BOOL bEnable)
701 TOKEN_PRIVILEGES tokenPrivileges;
703 if (!OpenProcessToken(GetCurrentProcess(),
704 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
707 if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
713 tokenPrivileges.PrivilegeCount = 1;
714 tokenPrivileges.Privileges[0].Luid = luid;
715 tokenPrivileges.Privileges[0].Attributes = bEnable ?
716 SE_PRIVILEGE_ENABLED : 0;
718 bResult = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges,
719 sizeof(TOKEN_PRIVILEGES), NULL, NULL);
723 return bResult && GetLastError() == ERROR_SUCCESS;
728 * Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
729 * VER_PLATFORM_WIN32_WINDOWS (Win95).
734 static int done = FALSE;
740 ovi.dwOSVersionInfoSize = sizeof(ovi);
743 g_PlatformId = ovi.dwPlatformId;
745 if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2)
746 || ovi.dwMajorVersion > 6)
747 win8_or_later = TRUE;
750 /* Enable privilege for getting or setting SACLs. */
751 win32_enable_privilege(SE_SECURITY_NAME, TRUE);
759 #define SHIFT (SHIFT_PRESSED)
760 #define CTRL (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)
761 #define ALT (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)
762 #define ALT_GR (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)
765 /* When uChar.AsciiChar is 0, then we need to look at wVirtualKeyCode.
766 * We map function keys to their ANSI terminal equivalents, as produced
767 * by ANSI.SYS, for compatibility with the MS-DOS version of Vim. Any
768 * ANSI key with a value >= '\300' is nonstandard, but provided anyway
769 * so that the user can have access to all SHIFT-, CTRL-, and ALT-
770 * combinations of function/arrow/etc keys.
784 /* Key ANSI alone shift ctrl alt */
785 { VK_ESCAPE,FALSE, ESC, ESC, ESC, ESC, },
787 { VK_F1, TRUE, ';', 'T', '^', 'h', },
788 { VK_F2, TRUE, '<', 'U', '_', 'i', },
789 { VK_F3, TRUE, '=', 'V', '`', 'j', },
790 { VK_F4, TRUE, '>', 'W', 'a', 'k', },
791 { VK_F5, TRUE, '?', 'X', 'b', 'l', },
792 { VK_F6, TRUE, '@', 'Y', 'c', 'm', },
793 { VK_F7, TRUE, 'A', 'Z', 'd', 'n', },
794 { VK_F8, TRUE, 'B', '[', 'e', 'o', },
795 { VK_F9, TRUE, 'C', '\\', 'f', 'p', },
796 { VK_F10, TRUE, 'D', ']', 'g', 'q', },
797 { VK_F11, TRUE, '\205', '\207', '\211', '\213', },
798 { VK_F12, TRUE, '\206', '\210', '\212', '\214', },
800 { VK_HOME, TRUE, 'G', '\302', 'w', '\303', },
801 { VK_UP, TRUE, 'H', '\304', '\305', '\306', },
802 { VK_PRIOR, TRUE, 'I', '\307', '\204', '\310', }, /*PgUp*/
803 { VK_LEFT, TRUE, 'K', '\311', 's', '\312', },
804 { VK_RIGHT, TRUE, 'M', '\313', 't', '\314', },
805 { VK_END, TRUE, 'O', '\315', 'u', '\316', },
806 { VK_DOWN, TRUE, 'P', '\317', '\320', '\321', },
807 { VK_NEXT, TRUE, 'Q', '\322', 'v', '\323', }, /*PgDn*/
808 { VK_INSERT,TRUE, 'R', '\324', '\325', '\326', },
809 { VK_DELETE,TRUE, 'S', '\327', '\330', '\331', },
811 { VK_SNAPSHOT,TRUE, 0, 0, 0, 'r', }, /*PrtScrn*/
814 /* Most people don't have F13-F20, but what the hell... */
815 { VK_F13, TRUE, '\332', '\333', '\334', '\335', },
816 { VK_F14, TRUE, '\336', '\337', '\340', '\341', },
817 { VK_F15, TRUE, '\342', '\343', '\344', '\345', },
818 { VK_F16, TRUE, '\346', '\347', '\350', '\351', },
819 { VK_F17, TRUE, '\352', '\353', '\354', '\355', },
820 { VK_F18, TRUE, '\356', '\357', '\360', '\361', },
821 { VK_F19, TRUE, '\362', '\363', '\364', '\365', },
822 { VK_F20, TRUE, '\366', '\367', '\370', '\371', },
824 { VK_ADD, TRUE, 'N', 'N', 'N', 'N', }, /* keyp '+' */
825 { VK_SUBTRACT, TRUE,'J', 'J', 'J', 'J', }, /* keyp '-' */
826 /* { VK_DIVIDE, TRUE,'N', 'N', 'N', 'N', }, keyp '/' */
827 { VK_MULTIPLY, TRUE,'7', '7', '7', '7', }, /* keyp '*' */
829 { VK_NUMPAD0,TRUE, '\332', '\333', '\334', '\335', },
830 { VK_NUMPAD1,TRUE, '\336', '\337', '\340', '\341', },
831 { VK_NUMPAD2,TRUE, '\342', '\343', '\344', '\345', },
832 { VK_NUMPAD3,TRUE, '\346', '\347', '\350', '\351', },
833 { VK_NUMPAD4,TRUE, '\352', '\353', '\354', '\355', },
834 { VK_NUMPAD5,TRUE, '\356', '\357', '\360', '\361', },
835 { VK_NUMPAD6,TRUE, '\362', '\363', '\364', '\365', },
836 { VK_NUMPAD7,TRUE, '\366', '\367', '\370', '\371', },
837 { VK_NUMPAD8,TRUE, '\372', '\373', '\374', '\375', },
838 /* Sorry, out of number space! <negri>*/
839 { VK_NUMPAD9,TRUE, '\376', '\377', '\377', '\367', },
845 // The ToAscii bug destroys several registers. Need to turn off optimization
846 // or the GetConsoleKeyboardLayoutName hack will fail in non-debug versions
847 # pragma warning(push)
848 # pragma warning(disable: 4748)
849 # pragma optimize("", off)
852 #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__)
853 # define UChar UnicodeChar
855 # define UChar uChar.UnicodeChar
858 /* The return code indicates key code size. */
864 KEY_EVENT_RECORD *pker)
866 UINT uMods = pker->dwControlKeyState;
867 static int s_iIsDead = 0;
868 static WORD awAnsiCode[2];
869 static BYTE abKeystate[256];
874 pker->UChar = (WCHAR) awAnsiCode[1];
879 if (pker->UChar != 0)
882 vim_memset(abKeystate, 0, sizeof (abKeystate));
884 /* Clear any pending dead keys */
885 ToUnicode(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 2, 0);
887 if (uMods & SHIFT_PRESSED)
888 abKeystate[VK_SHIFT] = 0x80;
889 if (uMods & CAPSLOCK_ON)
890 abKeystate[VK_CAPITAL] = 1;
892 if ((uMods & ALT_GR) == ALT_GR)
894 abKeystate[VK_CONTROL] = abKeystate[VK_LCONTROL] =
895 abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80;
898 s_iIsDead = ToUnicode(pker->wVirtualKeyCode, pker->wVirtualScanCode,
899 abKeystate, awAnsiCode, 2, 0);
902 pker->UChar = (WCHAR) awAnsiCode[0];
908 /* MUST switch optimization on again here, otherwise a call to
909 * decode_key_event() may crash (e.g. when hitting caps-lock) */
910 # pragma optimize("", on)
911 # pragma warning(pop)
913 # if (_MSC_VER < 1100)
914 /* MUST turn off global optimisation for this next function, or
915 * pressing ctrl-minus in insert mode crashes Vim when built with
916 * VC4.1. -- negri. */
917 # pragma optimize("g", off)
921 static BOOL g_fJustGotFocus = FALSE;
924 * Decode a KEY_EVENT into one or two keystrokes
928 KEY_EVENT_RECORD *pker,
935 const int nModifs = pker->dwControlKeyState & (SHIFT | ALT | CTRL);
938 g_fJustGotFocus = FALSE;
940 /* ignore key up events */
944 /* ignore some keystrokes */
945 switch (pker->wVirtualKeyCode)
950 case VK_MENU: /* Alt key */
958 if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 && pker->UChar == NUL)
960 /* Ctrl-6 is Ctrl-^ */
961 if (pker->wVirtualKeyCode == '6')
966 /* Ctrl-2 is Ctrl-@ */
967 else if (pker->wVirtualKeyCode == '2')
972 /* Ctrl-- is Ctrl-_ */
973 else if (pker->wVirtualKeyCode == 0xBD)
981 if (pker->wVirtualKeyCode == VK_TAB && (nModifs & SHIFT_PRESSED))
988 for (i = sizeof(VirtKeyMap) / sizeof(VirtKeyMap[0]); --i >= 0; )
990 if (VirtKeyMap[i].wVirtKey == pker->wVirtualKeyCode)
993 *pch = VirtKeyMap[i].chAlone;
994 else if ((nModifs & SHIFT) != 0 && (nModifs & ~SHIFT) == 0)
995 *pch = VirtKeyMap[i].chShift;
996 else if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0)
997 *pch = VirtKeyMap[i].chCtrl;
998 else if ((nModifs & ALT) != 0 && (nModifs & ~ALT) == 0)
999 *pch = VirtKeyMap[i].chAlt;
1003 if (VirtKeyMap[i].fAnsiKey)
1014 i = win32_kbd_patch_key(pker);
1020 *pch = (i > 0) ? pker->UChar : NUL;
1022 if (pmodifiers != NULL)
1024 /* Pass on the ALT key as a modifier, but only when not combined
1025 * with CTRL (which is ALTGR). */
1026 if ((nModifs & ALT) != 0 && (nModifs & CTRL) == 0)
1027 *pmodifiers |= MOD_MASK_ALT;
1029 /* Pass on SHIFT only for special keys, because we don't know when
1030 * it's already included with the character. */
1031 if ((nModifs & SHIFT) != 0 && *pch <= 0x20)
1032 *pmodifiers |= MOD_MASK_SHIFT;
1034 /* Pass on CTRL only for non-special keys, because we don't know
1035 * when it's already included with the character. And not when
1036 * combined with ALT (which is ALTGR). */
1037 if ((nModifs & CTRL) != 0 && (nModifs & ALT) == 0
1038 && *pch >= 0x20 && *pch < 0x80)
1039 *pmodifiers |= MOD_MASK_CTRL;
1043 return (*pch != NUL);
1047 # pragma optimize("", on)
1050 #endif /* FEAT_GUI_W32 */
1056 * For the GUI the mouse handling is in gui_w32.c.
1058 # ifdef FEAT_GUI_W32
1060 mch_setmouse(int on UNUSED)
1064 static int g_fMouseAvail = FALSE; /* mouse present */
1065 static int g_fMouseActive = FALSE; /* mouse enabled */
1066 static int g_nMouseClick = -1; /* mouse status */
1067 static int g_xMouse; /* mouse x coordinate */
1068 static int g_yMouse; /* mouse y coordinate */
1071 * Enable or disable mouse input
1074 mch_setmouse(int on)
1081 g_fMouseActive = on;
1082 GetConsoleMode(g_hConIn, &cmodein);
1085 cmodein |= ENABLE_MOUSE_INPUT;
1087 cmodein &= ~ENABLE_MOUSE_INPUT;
1089 SetConsoleMode(g_hConIn, cmodein);
1093 * Decode a MOUSE_EVENT. If it's a valid event, return MOUSE_LEFT,
1094 * MOUSE_MIDDLE, or MOUSE_RIGHT for a click; MOUSE_DRAG for a mouse
1095 * move with a button held down; and MOUSE_RELEASE after a MOUSE_DRAG
1096 * or a MOUSE_LEFT, _MIDDLE, or _RIGHT. We encode the button type,
1097 * the number of clicks, and the Shift/Ctrl/Alt modifiers in g_nMouseClick,
1098 * and we return the mouse position in g_xMouse and g_yMouse.
1100 * Every MOUSE_LEFT, _MIDDLE, or _RIGHT will be followed by zero or more
1101 * MOUSE_DRAGs and one MOUSE_RELEASE. MOUSE_RELEASE will be followed only
1102 * by MOUSE_LEFT, _MIDDLE, or _RIGHT.
1104 * For multiple clicks, we send, say, MOUSE_LEFT/1 click, MOUSE_RELEASE,
1105 * MOUSE_LEFT/2 clicks, MOUSE_RELEASE, MOUSE_LEFT/3 clicks, MOUSE_RELEASE, ....
1107 * Windows will send us MOUSE_MOVED notifications whenever the mouse
1108 * moves, even if it stays within the same character cell. We ignore
1109 * all MOUSE_MOVED messages if the position hasn't really changed, and
1110 * we ignore all MOUSE_MOVED messages where no button is held down (i.e.,
1111 * we're only interested in MOUSE_DRAG).
1113 * All of this is complicated by the code that fakes MOUSE_MIDDLE on
1114 * 2-button mouses by pressing the left & right buttons simultaneously.
1115 * In practice, it's almost impossible to click both at the same time,
1116 * so we need to delay a little. Also, we tend not to get MOUSE_RELEASE
1117 * in such cases, if the user is clicking quickly.
1121 MOUSE_EVENT_RECORD *pmer)
1123 static int s_nOldButton = -1;
1124 static int s_nOldMouseClick = -1;
1125 static int s_xOldMouse = -1;
1126 static int s_yOldMouse = -1;
1127 static linenr_T s_old_topline = 0;
1129 static int s_old_topfill = 0;
1131 static int s_cClicks = 1;
1132 static BOOL s_fReleased = TRUE;
1133 static DWORD s_dwLastClickTime = 0;
1134 static BOOL s_fNextIsMiddle = FALSE;
1136 static DWORD cButtons = 0; /* number of buttons supported */
1138 const DWORD LEFT = FROM_LEFT_1ST_BUTTON_PRESSED;
1139 const DWORD MIDDLE = FROM_LEFT_2ND_BUTTON_PRESSED;
1140 const DWORD RIGHT = RIGHTMOST_BUTTON_PRESSED;
1141 const DWORD LEFT_RIGHT = LEFT | RIGHT;
1145 if (cButtons == 0 && !GetNumberOfConsoleMouseButtons(&cButtons))
1148 if (!g_fMouseAvail || !g_fMouseActive)
1154 /* get a spurious MOUSE_EVENT immediately after receiving focus; ignore */
1155 if (g_fJustGotFocus)
1157 g_fJustGotFocus = FALSE;
1161 /* unprocessed mouse click? */
1162 if (g_nMouseClick != -1)
1166 g_xMouse = pmer->dwMousePosition.X;
1167 g_yMouse = pmer->dwMousePosition.Y;
1169 if (pmer->dwEventFlags == MOUSE_MOVED)
1171 /* ignore MOUSE_MOVED events if (x, y) hasn't changed. (We get these
1172 * events even when the mouse moves only within a char cell.) */
1173 if (s_xOldMouse == g_xMouse && s_yOldMouse == g_yMouse)
1177 /* If no buttons are pressed... */
1178 if ((pmer->dwButtonState & ((1 << cButtons) - 1)) == 0)
1180 /* If the last thing returned was MOUSE_RELEASE, ignore this */
1184 nButton = MOUSE_RELEASE;
1187 else /* one or more buttons pressed */
1189 /* on a 2-button mouse, hold down left and right buttons
1190 * simultaneously to get MIDDLE. */
1192 if (cButtons == 2 && s_nOldButton != MOUSE_DRAG)
1194 DWORD dwLR = (pmer->dwButtonState & LEFT_RIGHT);
1196 /* if either left or right button only is pressed, see if the
1197 * next mouse event has both of them pressed */
1198 if (dwLR == LEFT || dwLR == RIGHT)
1202 /* wait a short time for next input event */
1203 if (WaitForSingleObject(g_hConIn, p_mouset / 3)
1210 MOUSE_EVENT_RECORD* pmer2 = &ir.Event.MouseEvent;
1212 peek_console_input(g_hConIn, &ir, 1, &cRecords);
1214 if (cRecords == 0 || ir.EventType != MOUSE_EVENT
1215 || !(pmer2->dwButtonState & LEFT_RIGHT))
1219 if (pmer2->dwEventFlags != MOUSE_MOVED)
1221 read_console_input(g_hConIn, &ir, 1, &cRecords);
1223 return decode_mouse_event(pmer2);
1225 else if (s_xOldMouse == pmer2->dwMousePosition.X &&
1226 s_yOldMouse == pmer2->dwMousePosition.Y)
1228 /* throw away spurious mouse move */
1229 read_console_input(g_hConIn, &ir, 1, &cRecords);
1231 /* are there any more mouse events in queue? */
1232 peek_console_input(g_hConIn, &ir, 1, &cRecords);
1234 if (cRecords==0 || ir.EventType != MOUSE_EVENT)
1245 if (s_fNextIsMiddle)
1247 nButton = (pmer->dwEventFlags == MOUSE_MOVED)
1248 ? MOUSE_DRAG : MOUSE_MIDDLE;
1249 s_fNextIsMiddle = FALSE;
1251 else if (cButtons == 2 &&
1252 ((pmer->dwButtonState & LEFT_RIGHT) == LEFT_RIGHT))
1254 nButton = MOUSE_MIDDLE;
1256 if (! s_fReleased && pmer->dwEventFlags != MOUSE_MOVED)
1258 s_fNextIsMiddle = TRUE;
1259 nButton = MOUSE_RELEASE;
1262 else if ((pmer->dwButtonState & LEFT) == LEFT)
1263 nButton = MOUSE_LEFT;
1264 else if ((pmer->dwButtonState & MIDDLE) == MIDDLE)
1265 nButton = MOUSE_MIDDLE;
1266 else if ((pmer->dwButtonState & RIGHT) == RIGHT)
1267 nButton = MOUSE_RIGHT;
1269 if (! s_fReleased && ! s_fNextIsMiddle
1270 && nButton != s_nOldButton && s_nOldButton != MOUSE_DRAG)
1273 s_fReleased = s_fNextIsMiddle;
1276 if (pmer->dwEventFlags == 0 || pmer->dwEventFlags == DOUBLE_CLICK)
1278 /* button pressed or released, without mouse moving */
1279 if (nButton != -1 && nButton != MOUSE_RELEASE)
1281 DWORD dwCurrentTime = GetTickCount();
1283 if (s_xOldMouse != g_xMouse
1284 || s_yOldMouse != g_yMouse
1285 || s_nOldButton != nButton
1286 || s_old_topline != curwin->w_topline
1288 || s_old_topfill != curwin->w_topfill
1290 || (int)(dwCurrentTime - s_dwLastClickTime) > p_mouset)
1294 else if (++s_cClicks > 4)
1299 s_dwLastClickTime = dwCurrentTime;
1302 else if (pmer->dwEventFlags == MOUSE_MOVED)
1304 if (nButton != -1 && nButton != MOUSE_RELEASE)
1305 nButton = MOUSE_DRAG;
1313 if (nButton != MOUSE_RELEASE)
1314 s_nOldButton = nButton;
1316 g_nMouseClick = nButton;
1318 if (pmer->dwControlKeyState & SHIFT_PRESSED)
1319 g_nMouseClick |= MOUSE_SHIFT;
1320 if (pmer->dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
1321 g_nMouseClick |= MOUSE_CTRL;
1322 if (pmer->dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
1323 g_nMouseClick |= MOUSE_ALT;
1325 if (nButton != MOUSE_DRAG && nButton != MOUSE_RELEASE)
1326 SET_NUM_MOUSE_CLICKS(g_nMouseClick, s_cClicks);
1328 /* only pass on interesting (i.e., different) mouse events */
1329 if (s_xOldMouse == g_xMouse
1330 && s_yOldMouse == g_yMouse
1331 && s_nOldMouseClick == g_nMouseClick)
1337 s_xOldMouse = g_xMouse;
1338 s_yOldMouse = g_yMouse;
1339 s_old_topline = curwin->w_topline;
1341 s_old_topfill = curwin->w_topfill;
1343 s_nOldMouseClick = g_nMouseClick;
1348 # endif /* FEAT_GUI_W32 */
1349 #endif /* FEAT_MOUSE */
1352 #ifdef MCH_CURSOR_SHAPE
1354 * Set the shape of the cursor.
1355 * 'thickness' can be from 1 (thin) to 99 (block)
1358 mch_set_cursor_shape(int thickness)
1360 CONSOLE_CURSOR_INFO ConsoleCursorInfo;
1361 ConsoleCursorInfo.dwSize = thickness;
1362 ConsoleCursorInfo.bVisible = s_cursor_visible;
1364 SetConsoleCursorInfo(g_hConOut, &ConsoleCursorInfo);
1365 if (s_cursor_visible)
1366 SetConsoleCursorPosition(g_hConOut, g_coord);
1370 mch_update_cursor(void)
1376 * How the cursor is drawn depends on the current mode.
1378 idx = get_shape_idx(FALSE);
1380 if (shape_table[idx].shape == SHAPE_BLOCK)
1381 thickness = 99; /* 100 doesn't work on W95 */
1383 thickness = shape_table[idx].percentage;
1384 mch_set_cursor_shape(thickness);
1388 #ifndef FEAT_GUI_W32 /* this isn't used for the GUI */
1390 * Handle FOCUS_EVENT.
1393 handle_focus_event(INPUT_RECORD ir)
1395 g_fJustGotFocus = ir.Event.FocusEvent.bSetFocus;
1396 ui_focus_change((int)g_fJustGotFocus);
1400 * Wait until console input from keyboard or mouse is available,
1401 * or the time is up.
1402 * Return TRUE if something is available FALSE if not.
1405 WaitForChar(long msec)
1407 DWORD dwNow = 0, dwEndTime = 0;
1412 int tb_change_cnt = typebuf.tb_change_cnt;
1416 /* Wait until the specified time has elapsed. */
1417 dwEndTime = GetTickCount() + msec;
1420 dwEndTime = INFINITE;
1422 /* We need to loop until the end of the time period, because
1423 * we might get multiple unusable mouse events in that time.
1427 #ifdef MESSAGE_QUEUE
1428 parse_queued_messages();
1430 #ifdef FEAT_MZSCHEME
1431 mzvim_check_threads();
1433 #ifdef FEAT_CLIENTSERVER
1434 serverProcessPendingMessages();
1439 || g_nMouseClick != -1
1441 #ifdef FEAT_CLIENTSERVER
1442 || input_available()
1449 /* If the specified wait time has passed, return. Beware that
1450 * GetTickCount() may wrap around (overflow). */
1451 dwNow = GetTickCount();
1452 if ((int)(dwNow - dwEndTime) >= 0)
1457 DWORD dwWaitTime = dwEndTime - dwNow;
1459 #ifdef FEAT_JOB_CHANNEL
1460 /* Check channel while waiting for input. */
1461 if (dwWaitTime > 100)
1464 /* If there is readahead then parse_queued_messages() timed out
1465 * and we should call it again soon. */
1466 if (channel_any_readahead())
1471 if (p_beval && dwWaitTime > 100)
1472 /* The 'balloonexpr' may indirectly invoke a callback while
1473 * waiting for a character, need to check often. */
1476 #ifdef FEAT_MZSCHEME
1477 if (mzthreads_allowed() && p_mzq > 0
1478 && (msec < 0 || (long)dwWaitTime > p_mzq))
1479 dwWaitTime = p_mzq; /* don't wait longer than 'mzquantum' */
1485 /* When waiting very briefly don't trigger timers. */
1486 if (dwWaitTime > 10)
1488 /* Trigger timers and then get the time in msec until the
1489 * next one is due. Wait up to that time. */
1490 due_time = check_due_timer();
1491 if (typebuf.tb_change_cnt != tb_change_cnt)
1493 /* timer may have used feedkeys() */
1496 if (due_time > 0 && dwWaitTime > (DWORD)due_time)
1497 dwWaitTime = due_time;
1501 #ifdef FEAT_CLIENTSERVER
1502 /* Wait for either an event on the console input or a message in
1503 * the client-server window. */
1504 if (msg_wait_for_multiple_objects(1, &g_hConIn, FALSE,
1505 dwWaitTime, QS_SENDMESSAGE) != WAIT_OBJECT_0)
1507 if (wait_for_single_object(g_hConIn, dwWaitTime) != WAIT_OBJECT_0)
1513 peek_console_input(g_hConIn, &ir, 1, &cRecords);
1515 #ifdef FEAT_MBYTE_IME
1516 if (State & CMDLINE && msg_row == Rows - 1)
1518 CONSOLE_SCREEN_BUFFER_INFO csbi;
1520 if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
1522 if (csbi.dwCursorPosition.Y != msg_row)
1524 /* The screen is now messed up, must redraw the
1525 * command line and later all the windows. */
1526 redraw_all_later(CLEAR);
1527 cmdline_row -= (msg_row - csbi.dwCursorPosition.Y);
1536 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
1538 #ifdef FEAT_MBYTE_IME
1539 /* Windows IME sends two '\n's with only one 'ENTER'. First:
1540 * wVirtualKeyCode == 13. second: wVirtualKeyCode == 0 */
1541 if (ir.Event.KeyEvent.UChar == 0
1542 && ir.Event.KeyEvent.wVirtualKeyCode == 13)
1544 read_console_input(g_hConIn, &ir, 1, &cRecords);
1548 if (decode_key_event(&ir.Event.KeyEvent, &ch, &ch2,
1553 read_console_input(g_hConIn, &ir, 1, &cRecords);
1555 if (ir.EventType == FOCUS_EVENT)
1556 handle_focus_event(ir);
1557 else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
1560 else if (ir.EventType == MOUSE_EVENT
1561 && decode_mouse_event(&ir.Event.MouseEvent))
1569 #ifdef FEAT_CLIENTSERVER
1570 /* Something might have been received while we were waiting. */
1571 if (input_available())
1578 #ifndef FEAT_GUI_MSWIN
1580 * return non-zero if a character is available
1583 mch_char_avail(void)
1585 return WaitForChar(0L);
1590 * Create the console input. Used when reading stdin doesn't work.
1595 g_hConIn = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE,
1596 FILE_SHARE_READ|FILE_SHARE_WRITE,
1597 (LPSECURITY_ATTRIBUTES) NULL,
1598 OPEN_EXISTING, 0, (HANDLE)NULL);
1599 did_create_conin = TRUE;
1603 * Get a keystroke or a mouse event, use a blocking wait.
1606 tgetch(int *pmodifiers, WCHAR *pch2)
1615 #ifdef FEAT_CLIENTSERVER
1616 (void)WaitForChar(-1L);
1617 if (input_available())
1620 if (g_nMouseClick != -1)
1624 if (read_console_input(g_hConIn, &ir, 1, &cRecords) == 0)
1626 if (did_create_conin)
1632 if (ir.EventType == KEY_EVENT)
1634 if (decode_key_event(&ir.Event.KeyEvent, &ch, pch2,
1638 else if (ir.EventType == FOCUS_EVENT)
1639 handle_focus_event(ir);
1640 else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
1643 else if (ir.EventType == MOUSE_EVENT)
1645 if (decode_mouse_event(&ir.Event.MouseEvent))
1651 #endif /* !FEAT_GUI_W32 */
1655 * mch_inchar(): low-level input function.
1656 * Get one or more characters from the keyboard or the mouse.
1657 * If time == 0, do not wait for characters.
1658 * If time == n, wait a short time for characters.
1659 * If time == -1, wait forever for characters.
1660 * Returns the number of characters read into buf.
1667 int tb_change_cnt UNUSED)
1669 #ifndef FEAT_GUI_W32 /* this isn't used for the GUI */
1673 #define TYPEAHEADLEN 20
1674 static char_u typeahead[TYPEAHEADLEN]; /* previously typed bytes. */
1675 static int typeaheadlen = 0;
1677 /* First use any typeahead that was kept because "buf" was too small. */
1678 if (typeaheadlen > 0)
1683 if (!WaitForChar(time)) /* no character available */
1686 else /* time == -1, wait forever */
1688 mch_set_winsize_now(); /* Allow winsize changes from now on */
1691 * If there is no character available within 2 seconds (default)
1692 * write the autoscript file to disk. Or cause the CursorHold event
1695 if (!WaitForChar(p_ut))
1698 if (trigger_cursorhold() && maxlen >= 3)
1702 buf[2] = (int)KE_CURSORHOLD;
1711 * Try to read as many characters as there are, until the buffer is full.
1714 /* we will get at least one key. Get more if they are available. */
1715 g_fCBrkPressed = FALSE;
1717 #ifdef MCH_WRITE_DUMP
1722 /* Keep looping until there is something in the typeahead buffer and more
1723 * to get and still room in the buffer (up to two bytes for a char and
1724 * three bytes for a modifier). */
1725 while ((typeaheadlen == 0 || WaitForChar(0L))
1726 && typeaheadlen + 5 <= TYPEAHEADLEN)
1728 if (typebuf_changed(tb_change_cnt))
1730 /* "buf" may be invalid now if a client put something in the
1731 * typeahead buffer and "buf" is in the typeahead buffer. */
1736 if (g_nMouseClick != -1)
1738 # ifdef MCH_WRITE_DUMP
1740 fprintf(fdDump, "{%02x @ %d, %d}",
1741 g_nMouseClick, g_xMouse, g_yMouse);
1743 typeahead[typeaheadlen++] = ESC + 128;
1744 typeahead[typeaheadlen++] = 'M';
1745 typeahead[typeaheadlen++] = g_nMouseClick;
1746 typeahead[typeaheadlen++] = g_xMouse + '!';
1747 typeahead[typeaheadlen++] = g_yMouse + '!';
1756 c = tgetch(&modifiers, &ch2);
1758 if (typebuf_changed(tb_change_cnt))
1760 /* "buf" may be invalid now if a client put something in the
1761 * typeahead buffer and "buf" is in the typeahead buffer. */
1766 if (c == Ctrl_C && ctrl_c_interrupts)
1768 #if defined(FEAT_CLIENTSERVER)
1775 if (g_nMouseClick == -1)
1789 if (c >= 0xD800 && c <= 0xDBFF) /* High surrogate */
1791 ch[1] = tgetch(&modifiers, &ch2);
1794 p = utf16_to_enc(ch, &n);
1797 for (i = 0; i < n; i++)
1798 typeahead[typeaheadlen + i] = p[i];
1804 typeahead[typeaheadlen] = c;
1807 typeahead[typeaheadlen + n] = 3;
1808 typeahead[typeaheadlen + n + 1] = (char_u)ch2;
1814 char_u *p = typeahead + typeaheadlen;
1818 char_u *e = typeahead + TYPEAHEADLEN;
1825 mch_memmove(p + 1, p, ((size_t)(e - p)) - 1);
1834 /* Use the ALT key to set the 8th bit of the character
1835 * when it's one byte, the 8th bit isn't set yet and not
1836 * using a double-byte encoding (would become a lead
1838 if ((modifiers & MOD_MASK_ALT)
1840 && (typeahead[typeaheadlen] & 0x80) == 0
1847 n = (*mb_char2bytes)(typeahead[typeaheadlen] | 0x80,
1848 typeahead + typeaheadlen);
1850 typeahead[typeaheadlen] |= 0x80;
1852 modifiers &= ~MOD_MASK_ALT;
1857 /* Prepend modifiers to the character. */
1858 mch_memmove(typeahead + typeaheadlen + 3,
1859 typeahead + typeaheadlen, n);
1860 typeahead[typeaheadlen++] = K_SPECIAL;
1861 typeahead[typeaheadlen++] = (char_u)KS_MODIFIER;
1862 typeahead[typeaheadlen++] = modifiers;
1867 #ifdef MCH_WRITE_DUMP
1875 #ifdef MCH_WRITE_DUMP
1878 fputs("]\n", fdDump);
1884 /* Move typeahead to "buf", as much as fits. */
1886 while (len < maxlen && typeaheadlen > 0)
1888 buf[len++] = typeahead[0];
1889 mch_memmove(typeahead, typeahead + 1, --typeaheadlen);
1893 #else /* FEAT_GUI_W32 */
1895 #endif /* FEAT_GUI_W32 */
1899 # ifndef __MINGW32__
1900 # include <shellapi.h> /* required for FindExecutable() */
1905 * If "use_path" is TRUE: Return TRUE if "name" is in $PATH.
1906 * If "use_path" is FALSE: Return TRUE if "name" exists.
1907 * When returning TRUE and "path" is not NULL save the path and set "*path" to
1908 * the allocated memory.
1909 * TODO: Should somehow check if it's really executable.
1912 executable_exists(char *name, char_u **path, int use_path)
1915 char fname[_MAX_PATH];
1916 char *curpath, *newpath;
1921 if (mch_getperm((char_u *)name) != -1 && !mch_isdir((char_u *)name))
1925 if (mch_isFullName((char_u *)name))
1926 *path = vim_strsave((char_u *)name);
1928 *path = FullName_save((char_u *)name, FALSE);
1936 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
1938 WCHAR *p = enc_to_utf16((char_u *)name, NULL);
1939 WCHAR fnamew[_MAX_PATH];
1941 WCHAR *wcurpath, *wnewpath;
1945 wcurpath = _wgetenv(L"PATH");
1946 wnewpath = (WCHAR*)alloc((unsigned)(wcslen(wcurpath) + 3)
1948 if (wnewpath == NULL)
1950 wcscpy(wnewpath, L".;");
1951 wcscat(wnewpath, wcurpath);
1952 n = (long)SearchPathW(wnewpath, p, NULL, _MAX_PATH, fnamew, &dumw);
1957 if (GetFileAttributesW(fnamew) & FILE_ATTRIBUTE_DIRECTORY)
1960 *path = utf16_to_enc(fnamew, NULL);
1966 curpath = getenv("PATH");
1967 newpath = (char*)alloc((unsigned)(STRLEN(curpath) + 3));
1968 if (newpath == NULL)
1970 STRCPY(newpath, ".;");
1971 STRCAT(newpath, curpath);
1972 n = (long)SearchPath(newpath, name, NULL, _MAX_PATH, fname, &dum);
1976 if (mch_isdir((char_u *)fname))
1979 *path = vim_strsave((char_u *)fname);
1983 #if ((defined(__MINGW32__) || defined (__CYGWIN32__)) && \
1984 __MSVCRT_VERSION__ >= 0x800) || (defined(_MSC_VER) && _MSC_VER >= 1400)
1986 * Bad parameter handler.
1988 * Certain MS CRT functions will intentionally crash when passed invalid
1989 * parameters to highlight possible security holes. Setting this function as
1990 * the bad parameter handler will prevent the crash.
1992 * In debug builds the parameters contain CRT information that might help track
1993 * down the source of a problem, but in non-debug builds the arguments are all
1994 * NULL/0. Debug builds will also produce assert dialogs from the CRT, it is
1995 * worth allowing these to make debugging of issues easier.
1998 bad_param_handler(const wchar_t *expression,
1999 const wchar_t *function,
2000 const wchar_t *file,
2002 uintptr_t pReserved)
2006 # define SET_INVALID_PARAM_HANDLER \
2007 ((void)_set_invalid_parameter_handler(bad_param_handler))
2009 # define SET_INVALID_PARAM_HANDLER
2015 * GUI version of mch_init().
2024 /* Silently handle invalid parameters to CRT functions */
2025 SET_INVALID_PARAM_HANDLER;
2027 /* Let critical errors result in a failure, not in a dialog box. Required
2028 * for the timestamp test to work on removed floppies. */
2029 SetErrorMode(SEM_FAILCRITICALERRORS);
2031 _fmode = O_BINARY; /* we do our own CR-LF translation */
2033 /* Specify window size. Is there a place to get the default from? */
2037 /* Look for 'vimrun' */
2039 char_u vimrun_location[_MAX_PATH + 4];
2041 /* First try in same directory as gvim.exe */
2042 STRCPY(vimrun_location, exe_name);
2043 STRCPY(gettail(vimrun_location), "vimrun.exe");
2044 if (mch_getperm(vimrun_location) >= 0)
2046 if (*skiptowhite(vimrun_location) != NUL)
2048 /* Enclose path with white space in double quotes. */
2049 mch_memmove(vimrun_location + 1, vimrun_location,
2050 STRLEN(vimrun_location) + 1);
2051 *vimrun_location = '"';
2052 STRCPY(gettail(vimrun_location), "vimrun\" ");
2055 STRCPY(gettail(vimrun_location), "vimrun ");
2057 vimrun_path = (char *)vim_strsave(vimrun_location);
2058 s_dont_use_vimrun = FALSE;
2060 else if (executable_exists("vimrun.exe", NULL, TRUE))
2061 s_dont_use_vimrun = FALSE;
2063 /* Don't give the warning for a missing vimrun.exe right now, but only
2064 * when vimrun was supposed to be used. Don't bother people that do
2065 * not need vimrun.exe. */
2066 if (s_dont_use_vimrun)
2067 need_vimrun_warning = TRUE;
2071 * If "finstr.exe" doesn't exist, use "grep -n" for 'grepprg'.
2072 * Otherwise the default "findstr /n" is used.
2074 if (!executable_exists("findstr.exe", NULL, TRUE))
2075 set_option_value((char_u *)"grepprg", 0, (char_u *)"grep -n", 0);
2077 #ifdef FEAT_CLIPBOARD
2083 #else /* FEAT_GUI_W32 */
2085 #define SRWIDTH(sr) ((sr).Right - (sr).Left + 1)
2086 #define SRHEIGHT(sr) ((sr).Bottom - (sr).Top + 1)
2089 * ClearConsoleBuffer()
2091 * Clears the entire contents of the console screen buffer, using the
2092 * specified attribute.
2097 ClearConsoleBuffer(WORD wAttribute)
2099 CONSOLE_SCREEN_BUFFER_INFO csbi;
2101 DWORD NumCells, dummy;
2103 if (!GetConsoleScreenBufferInfo(g_hConOut, &csbi))
2106 NumCells = csbi.dwSize.X * csbi.dwSize.Y;
2109 if (!FillConsoleOutputCharacter(g_hConOut, ' ', NumCells,
2114 if (!FillConsoleOutputAttribute(g_hConOut, wAttribute, NumCells,
2124 * FitConsoleWindow()
2126 * Checks if the console window will fit within given buffer dimensions.
2127 * Also, if requested, will shrink the window to fit.
2136 CONSOLE_SCREEN_BUFFER_INFO csbi;
2138 BOOL NeedAdjust = FALSE;
2140 if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
2143 * A buffer resize will fail if the current console window does
2144 * not lie completely within that buffer. To avoid this, we might
2145 * have to move and possibly shrink the window.
2147 if (csbi.srWindow.Right >= dwBufferSize.X)
2149 dwWindowSize.X = SRWIDTH(csbi.srWindow);
2150 if (dwWindowSize.X > dwBufferSize.X)
2151 dwWindowSize.X = dwBufferSize.X;
2152 csbi.srWindow.Right = dwBufferSize.X - 1;
2153 csbi.srWindow.Left = dwBufferSize.X - dwWindowSize.X;
2156 if (csbi.srWindow.Bottom >= dwBufferSize.Y)
2158 dwWindowSize.Y = SRHEIGHT(csbi.srWindow);
2159 if (dwWindowSize.Y > dwBufferSize.Y)
2160 dwWindowSize.Y = dwBufferSize.Y;
2161 csbi.srWindow.Bottom = dwBufferSize.Y - 1;
2162 csbi.srWindow.Top = dwBufferSize.Y - dwWindowSize.Y;
2165 if (NeedAdjust && WantAdjust)
2167 if (!SetConsoleWindowInfo(g_hConOut, TRUE, &csbi.srWindow))
2176 typedef struct ConsoleBufferStruct
2179 CONSOLE_SCREEN_BUFFER_INFO Info;
2185 * SaveConsoleBuffer()
2187 * Saves important information about the console buffer, including the
2188 * actual buffer contents. The saved information is suitable for later
2189 * restoration by RestoreConsoleBuffer().
2191 * TRUE if all information was saved; FALSE otherwise
2192 * If FALSE, still sets cb->IsValid if buffer characteristics were saved.
2200 SMALL_RECT ReadRegion;
2206 if (!GetConsoleScreenBufferInfo(g_hConOut, &cb->Info))
2208 cb->IsValid = FALSE;
2214 * Allocate a buffer large enough to hold the entire console screen
2215 * buffer. If this ConsoleBuffer structure has already been initialized
2216 * with a buffer of the correct size, then just use that one.
2218 if (!cb->IsValid || cb->Buffer == NULL ||
2219 cb->BufferSize.X != cb->Info.dwSize.X ||
2220 cb->BufferSize.Y != cb->Info.dwSize.Y)
2222 cb->BufferSize.X = cb->Info.dwSize.X;
2223 cb->BufferSize.Y = cb->Info.dwSize.Y;
2224 NumCells = cb->BufferSize.X * cb->BufferSize.Y;
2225 vim_free(cb->Buffer);
2226 cb->Buffer = (PCHAR_INFO)alloc(NumCells * sizeof(CHAR_INFO));
2227 if (cb->Buffer == NULL)
2232 * We will now copy the console screen buffer into our buffer.
2233 * ReadConsoleOutput() seems to be limited as far as how much you
2234 * can read at a time. Empirically, this number seems to be about
2235 * 12000 cells (rows * columns). Start at position (0, 0) and copy
2236 * in chunks until it is all copied. The chunks will all have the
2237 * same horizontal characteristics, so initialize them now. The
2238 * height of each chunk will be (12000 / width).
2241 ReadRegion.Left = 0;
2242 ReadRegion.Right = cb->Info.dwSize.X - 1;
2243 Y_incr = 12000 / cb->Info.dwSize.X;
2244 for (Y = 0; Y < cb->BufferSize.Y; Y += Y_incr)
2247 * Read into position (0, Y) in our buffer.
2251 * Read the region whose top left corner is (0, Y) and whose bottom
2252 * right corner is (width - 1, Y + Y_incr - 1). This should define
2253 * a region of size width by Y_incr. Don't worry if this region is
2254 * too large for the remaining buffer; it will be cropped.
2257 ReadRegion.Bottom = Y + Y_incr - 1;
2258 if (!ReadConsoleOutput(g_hConOut, /* output handle */
2259 cb->Buffer, /* our buffer */
2260 cb->BufferSize, /* dimensions of our buffer */
2261 BufferCoord, /* offset in our buffer */
2262 &ReadRegion)) /* region to save */
2264 vim_free(cb->Buffer);
2274 * RestoreConsoleBuffer()
2276 * Restores important information about the console buffer, including the
2277 * actual buffer contents, if desired. The information to restore is in
2278 * the same format used by SaveConsoleBuffer().
2283 RestoreConsoleBuffer(
2288 SMALL_RECT WriteRegion;
2290 if (cb == NULL || !cb->IsValid)
2294 * Before restoring the buffer contents, clear the current buffer, and
2295 * restore the cursor position and window information. Doing this now
2296 * prevents old buffer contents from "flashing" onto the screen.
2299 ClearConsoleBuffer(cb->Info.wAttributes);
2301 FitConsoleWindow(cb->Info.dwSize, TRUE);
2302 if (!SetConsoleScreenBufferSize(g_hConOut, cb->Info.dwSize))
2304 if (!SetConsoleTextAttribute(g_hConOut, cb->Info.wAttributes))
2310 * No need to restore the screen buffer contents, so we're done.
2315 if (!SetConsoleCursorPosition(g_hConOut, cb->Info.dwCursorPosition))
2317 if (!SetConsoleWindowInfo(g_hConOut, TRUE, &cb->Info.srWindow))
2321 * Restore the screen buffer contents.
2323 if (cb->Buffer != NULL)
2327 WriteRegion.Left = 0;
2328 WriteRegion.Top = 0;
2329 WriteRegion.Right = cb->Info.dwSize.X - 1;
2330 WriteRegion.Bottom = cb->Info.dwSize.Y - 1;
2331 if (!WriteConsoleOutput(g_hConOut, /* output handle */
2332 cb->Buffer, /* our buffer */
2333 cb->BufferSize, /* dimensions of our buffer */
2334 BufferCoord, /* offset in our buffer */
2335 &WriteRegion)) /* region to restore */
2344 #define FEAT_RESTORE_ORIG_SCREEN
2345 #ifdef FEAT_RESTORE_ORIG_SCREEN
2346 static ConsoleBuffer g_cbOrig = { 0 };
2348 static ConsoleBuffer g_cbNonTermcap = { 0 };
2349 static ConsoleBuffer g_cbTermcap = { 0 };
2353 typedef HWND (__stdcall *GETCONSOLEWINDOWPROC)(VOID);
2355 typedef HWND (WINAPI *GETCONSOLEWINDOWPROC)(VOID);
2357 char g_szOrigTitle[256] = { 0 };
2358 HWND g_hWnd = NULL; /* also used in os_mswin.c */
2359 static HICON g_hOrigIconSmall = NULL;
2360 static HICON g_hOrigIcon = NULL;
2361 static HICON g_hVimIcon = NULL;
2362 static BOOL g_fCanChangeIcon = FALSE;
2364 /* ICON* are not defined in VC++ 4.0 */
2366 #define ICON_SMALL 0
2374 * Attempts to retrieve the small icon and/or the big icon currently in
2375 * use by a given window.
2388 if (phIconSmall != NULL)
2389 *phIconSmall = (HICON)SendMessage(hWnd, WM_GETICON,
2390 (WPARAM)ICON_SMALL, (LPARAM)0);
2392 *phIcon = (HICON)SendMessage(hWnd, WM_GETICON,
2393 (WPARAM)ICON_BIG, (LPARAM)0);
2400 * Attempts to change the small icon and/or the big icon currently in
2401 * use by a given window.
2414 if (hIconSmall != NULL)
2415 SendMessage(hWnd, WM_SETICON,
2416 (WPARAM)ICON_SMALL, (LPARAM)hIconSmall);
2418 SendMessage(hWnd, WM_SETICON,
2419 (WPARAM)ICON_BIG, (LPARAM) hIcon);
2424 * SaveConsoleTitleAndIcon()
2426 * Saves the current console window title in g_szOrigTitle, for later
2427 * restoration. Also, attempts to obtain a handle to the console window,
2428 * and use it to save the small and big icons currently in use by the
2429 * console window. This is not always possible on some versions of Windows;
2430 * nor is it possible when running Vim remotely using Telnet (since the
2431 * console window the user sees is owned by a remote process).
2434 SaveConsoleTitleAndIcon(void)
2436 /* Save the original title. */
2437 if (!GetConsoleTitle(g_szOrigTitle, sizeof(g_szOrigTitle)))
2441 * Obtain a handle to the console window using GetConsoleWindow() from
2442 * KERNEL32.DLL; we need to handle in order to change the window icon.
2443 * This function only exists on NT-based Windows, starting with Windows
2444 * 2000. On older operating systems, we can't change the window icon
2447 g_hWnd = GetConsoleWindow();
2451 /* Save the original console window icon. */
2452 GetConsoleIcon(g_hWnd, &g_hOrigIconSmall, &g_hOrigIcon);
2453 if (g_hOrigIconSmall == NULL || g_hOrigIcon == NULL)
2456 /* Extract the first icon contained in the Vim executable. */
2457 if (mch_icon_load((HANDLE *)&g_hVimIcon) == FAIL || g_hVimIcon == NULL)
2458 g_hVimIcon = ExtractIcon(NULL, (LPCSTR)exe_name, 0);
2459 if (g_hVimIcon != NULL)
2460 g_fCanChangeIcon = TRUE;
2464 static int g_fWindInitCalled = FALSE;
2465 static int g_fTermcapMode = FALSE;
2466 static CONSOLE_CURSOR_INFO g_cci;
2467 static DWORD g_cmodein = 0;
2468 static DWORD g_cmodeout = 0;
2471 * non-GUI version of mch_init().
2476 #ifndef FEAT_RESTORE_ORIG_SCREEN
2477 CONSOLE_SCREEN_BUFFER_INFO csbi;
2483 /* Silently handle invalid parameters to CRT functions */
2484 SET_INVALID_PARAM_HANDLER;
2486 /* Let critical errors result in a failure, not in a dialog box. Required
2487 * for the timestamp test to work on removed floppies. */
2488 SetErrorMode(SEM_FAILCRITICALERRORS);
2490 _fmode = O_BINARY; /* we do our own CR-LF translation */
2493 /* Obtain handles for the standard Console I/O devices */
2494 if (read_cmd_fd == 0)
2495 g_hConIn = GetStdHandle(STD_INPUT_HANDLE);
2498 g_hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
2500 #ifdef FEAT_RESTORE_ORIG_SCREEN
2501 /* Save the initial console buffer for later restoration */
2502 SaveConsoleBuffer(&g_cbOrig);
2503 g_attrCurrent = g_attrDefault = g_cbOrig.Info.wAttributes;
2505 /* Get current text attributes */
2506 GetConsoleScreenBufferInfo(g_hConOut, &csbi);
2507 g_attrCurrent = g_attrDefault = csbi.wAttributes;
2509 if (cterm_normal_fg_color == 0)
2510 cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1;
2511 if (cterm_normal_bg_color == 0)
2512 cterm_normal_bg_color = ((g_attrCurrent >> 4) & 0xf) + 1;
2514 /* set termcap codes to current text attributes */
2515 update_tcap(g_attrCurrent);
2517 GetConsoleCursorInfo(g_hConOut, &g_cci);
2518 GetConsoleMode(g_hConIn, &g_cmodein);
2519 GetConsoleMode(g_hConOut, &g_cmodeout);
2522 SaveConsoleTitleAndIcon();
2524 * Set both the small and big icons of the console window to Vim's icon.
2525 * Note that Vim presently only has one size of icon (32x32), but it
2526 * automatically gets scaled down to 16x16 when setting the small icon.
2528 if (g_fCanChangeIcon)
2529 SetConsoleIcon(g_hWnd, g_hVimIcon, g_hVimIcon);
2534 #ifdef MCH_WRITE_DUMP
2535 fdDump = fopen("dump", "wt");
2542 fputs(ctime(&t), fdDump);
2547 g_fWindInitCalled = TRUE;
2550 g_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT);
2553 #ifdef FEAT_CLIPBOARD
2559 * non-GUI version of mch_exit().
2560 * Shut down and exit with status `r'
2561 * Careful: mch_exit() may be called before mch_init()!
2569 if (g_fWindInitCalled)
2570 settmode(TMODE_COOK);
2572 ml_close_all(TRUE); /* remove all memfiles */
2574 if (g_fWindInitCalled)
2577 mch_restore_title(3);
2579 * Restore both the small and big icons of the console window to
2580 * what they were at startup. Don't do this when the window is
2581 * closed, Vim would hang here.
2583 if (g_fCanChangeIcon && !g_fForceExit)
2584 SetConsoleIcon(g_hWnd, g_hOrigIconSmall, g_hOrigIcon);
2587 #ifdef MCH_WRITE_DUMP
2593 fputs(ctime(&t), fdDump);
2600 SetConsoleCursorInfo(g_hConOut, &g_cci);
2601 SetConsoleMode(g_hConIn, g_cmodein);
2602 SetConsoleMode(g_hConOut, g_cmodeout);
2604 #ifdef DYNAMIC_GETTEXT
2610 #endif /* !FEAT_GUI_W32 */
2613 * Do we have an interactive window?
2623 return OK; /* GUI always has a tty */
2634 * fname_casew(): Wide version of fname_case(). Set the case of the file name,
2635 * if it already exists. When "len" is > 0, also expand short to long
2637 * Return FAIL if wide functions are not available, OK otherwise.
2638 * NOTE: much of this is identical to fname_case(), keep in sync!
2645 WCHAR szTrueName[_MAX_PATH + 2];
2646 WCHAR szTrueNameTemp[_MAX_PATH + 2];
2647 WCHAR *ptrue, *ptruePrev;
2648 WCHAR *porig, *porigPrev;
2650 WIN32_FIND_DATAW fb;
2651 HANDLE hFind = INVALID_HANDLE_VALUE;
2655 flen = (int)wcslen(name);
2656 if (flen > _MAX_PATH)
2659 /* slash_adjust(name) not needed, already adjusted by fname_case(). */
2661 /* Build the new name in szTrueName[] one component at a time. */
2665 if (iswalpha(porig[0]) && porig[1] == L':')
2667 /* copy leading drive letter */
2668 *ptrue++ = *porig++;
2669 *ptrue++ = *porig++;
2671 *ptrue = NUL; /* in case nothing follows */
2673 while (*porig != NUL)
2675 /* copy \ characters */
2676 while (*porig == psepc)
2677 *ptrue++ = *porig++;
2681 while (*porig != NUL && *porig != psepc)
2683 *ptrue++ = *porig++;
2687 /* To avoid a slow failure append "\*" when searching a directory,
2688 * server or network share. */
2689 wcscpy(szTrueNameTemp, szTrueName);
2690 slen = (int)wcslen(szTrueNameTemp);
2691 if (*porig == psepc && slen + 2 < _MAX_PATH)
2692 wcscpy(szTrueNameTemp + slen, L"\\*");
2694 /* Skip "", "." and "..". */
2695 if (ptrue > ptruePrev
2696 && (ptruePrev[0] != L'.'
2697 || (ptruePrev[1] != NUL
2698 && (ptruePrev[1] != L'.' || ptruePrev[2] != NUL)))
2699 && (hFind = FindFirstFileW(szTrueNameTemp, &fb))
2700 != INVALID_HANDLE_VALUE)
2705 /* Only use the match when it's the same name (ignoring case) or
2706 * expansion is allowed and there is a match with the short name
2707 * and there is enough room. */
2708 if (_wcsicoll(porigPrev, fb.cFileName) == 0
2710 && (_wcsicoll(porigPrev, fb.cAlternateFileName) == 0
2711 && (int)(ptruePrev - szTrueName)
2712 + (int)wcslen(fb.cFileName) < len)))
2714 wcscpy(ptruePrev, fb.cFileName);
2716 /* Look for exact match and prefer it if found. Must be a
2717 * long name, otherwise there would be only one match. */
2718 while (FindNextFileW(hFind, &fb))
2720 if (*fb.cAlternateFileName != NUL
2721 && (wcscoll(porigPrev, fb.cFileName) == 0
2723 && (_wcsicoll(porigPrev,
2724 fb.cAlternateFileName) == 0
2725 && (int)(ptruePrev - szTrueName)
2726 + (int)wcslen(fb.cFileName) < len))))
2728 wcscpy(ptruePrev, fb.cFileName);
2735 ptrue = ptruePrev + wcslen(ptruePrev);
2739 wcscpy(name, szTrueName);
2745 * fname_case(): Set the case of the file name, if it already exists.
2746 * When "len" is > 0, also expand short to long filenames.
2747 * NOTE: much of this is identical to fname_casew(), keep in sync!
2754 char szTrueName[_MAX_PATH + 2];
2755 char szTrueNameTemp[_MAX_PATH + 2];
2756 char *ptrue, *ptruePrev;
2757 char *porig, *porigPrev;
2764 flen = (int)STRLEN(name);
2771 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2773 WCHAR *p = enc_to_utf16(name, NULL);
2778 WCHAR buf[_MAX_PATH + 1];
2780 wcsncpy(buf, p, _MAX_PATH);
2781 buf[_MAX_PATH] = L'\0';
2784 if (fname_casew(buf, (len > 0) ? _MAX_PATH : 0) == OK)
2786 q = utf16_to_enc(buf, NULL);
2789 vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
2799 /* If 'enc' is utf-8, flen can be larger than _MAX_PATH.
2800 * So we should check this after calling wide function. */
2801 if (flen > _MAX_PATH)
2804 /* Build the new name in szTrueName[] one component at a time. */
2805 porig = (char *)name;
2808 if (isalpha(porig[0]) && porig[1] == ':')
2810 /* copy leading drive letter */
2811 *ptrue++ = *porig++;
2812 *ptrue++ = *porig++;
2814 *ptrue = NUL; /* in case nothing follows */
2816 while (*porig != NUL)
2818 /* copy \ characters */
2819 while (*porig == psepc)
2820 *ptrue++ = *porig++;
2824 while (*porig != NUL && *porig != psepc)
2831 l = (*mb_ptr2len)((char_u *)porig);
2833 *ptrue++ = *porig++;
2837 *ptrue++ = *porig++;
2841 /* To avoid a slow failure append "\*" when searching a directory,
2842 * server or network share. */
2843 STRCPY(szTrueNameTemp, szTrueName);
2844 slen = (int)strlen(szTrueNameTemp);
2845 if (*porig == psepc && slen + 2 < _MAX_PATH)
2846 STRCPY(szTrueNameTemp + slen, "\\*");
2848 /* Skip "", "." and "..". */
2849 if (ptrue > ptruePrev
2850 && (ptruePrev[0] != '.'
2851 || (ptruePrev[1] != NUL
2852 && (ptruePrev[1] != '.' || ptruePrev[2] != NUL)))
2853 && (hFind = FindFirstFile(szTrueNameTemp, &fb))
2854 != INVALID_HANDLE_VALUE)
2859 /* Only use the match when it's the same name (ignoring case) or
2860 * expansion is allowed and there is a match with the short name
2861 * and there is enough room. */
2862 if (_stricoll(porigPrev, fb.cFileName) == 0
2864 && (_stricoll(porigPrev, fb.cAlternateFileName) == 0
2865 && (int)(ptruePrev - szTrueName)
2866 + (int)strlen(fb.cFileName) < len)))
2868 STRCPY(ptruePrev, fb.cFileName);
2870 /* Look for exact match and prefer it if found. Must be a
2871 * long name, otherwise there would be only one match. */
2872 while (FindNextFile(hFind, &fb))
2874 if (*fb.cAlternateFileName != NUL
2875 && (strcoll(porigPrev, fb.cFileName) == 0
2877 && (_stricoll(porigPrev,
2878 fb.cAlternateFileName) == 0
2879 && (int)(ptruePrev - szTrueName)
2880 + (int)strlen(fb.cFileName) < len))))
2882 STRCPY(ptruePrev, fb.cFileName);
2889 ptrue = ptruePrev + strlen(ptruePrev);
2893 STRCPY(name, szTrueName);
2898 * Insert user name in s[len].
2905 char szUserName[256 + 1]; /* UNLEN is 256 */
2906 DWORD cch = sizeof szUserName;
2909 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2911 WCHAR wszUserName[256 + 1]; /* UNLEN is 256 */
2912 DWORD wcch = sizeof(wszUserName) / sizeof(WCHAR);
2914 if (GetUserNameW(wszUserName, &wcch))
2916 char_u *p = utf16_to_enc(wszUserName, NULL);
2920 vim_strncpy(s, p, len - 1);
2927 if (GetUserName(szUserName, &cch))
2929 vim_strncpy(s, (char_u *)szUserName, len - 1);
2938 * Insert host name in s[len].
2948 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2950 WCHAR wszHostName[256 + 1];
2951 DWORD wcch = sizeof(wszHostName) / sizeof(WCHAR);
2953 if (GetComputerNameW(wszHostName, &wcch))
2955 char_u *p = utf16_to_enc(wszHostName, NULL);
2959 vim_strncpy(s, p, len - 1);
2966 if (!GetComputerName((LPSTR)s, &cch))
2967 vim_strncpy(s, (char_u *)"PC (Win32 Vim)", len - 1);
2977 return (long)GetCurrentProcessId();
2982 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2983 * Return OK for success, FAIL for failure.
2991 * Originally this was:
2992 * return (getcwd(buf, len) != NULL ? OK : FAIL);
2993 * But the Win32s known bug list says that getcwd() doesn't work
2994 * so use the Win32 system call instead. <Negri>
2997 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2999 WCHAR wbuf[_MAX_PATH + 1];
3001 if (GetCurrentDirectoryW(_MAX_PATH, wbuf) != 0)
3003 char_u *p = utf16_to_enc(wbuf, NULL);
3007 vim_strncpy(buf, p, len - 1);
3015 return (GetCurrentDirectory(len, (LPSTR)buf) != 0 ? OK : FAIL);
3019 * Get file permissions for "name".
3020 * Return mode_t or -1 for error.
3023 mch_getperm(char_u *name)
3028 n = mch_stat((char *)name, &st);
3029 return n == 0 ? (long)(unsigned short)st.st_mode : -1L;
3034 * Set file permission for "name" to "perm".
3036 * Return FAIL for failure, OK otherwise.
3039 mch_setperm(char_u *name, long perm)
3044 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3046 WCHAR *p = enc_to_utf16(name, NULL);
3050 n = _wchmod(p, perm);
3058 n = _chmod((const char *)name, perm);
3062 win32_set_archive(name);
3068 * Set hidden flag for "name".
3071 mch_hide(char_u *name)
3073 int attrs = win32_getattrs(name);
3077 attrs |= FILE_ATTRIBUTE_HIDDEN;
3078 win32_setattrs(name, attrs);
3082 * Return TRUE if file "name" exists and is hidden.
3085 mch_ishidden(char_u *name)
3087 int f = win32_getattrs(name);
3090 return FALSE; /* file does not exist at all */
3092 return (f & FILE_ATTRIBUTE_HIDDEN) != 0;
3096 * return TRUE if "name" is a directory
3097 * return FALSE if "name" is not a directory or upon error
3100 mch_isdir(char_u *name)
3102 int f = win32_getattrs(name);
3105 return FALSE; /* file does not exist at all */
3107 return (f & FILE_ATTRIBUTE_DIRECTORY) != 0;
3111 * return TRUE if "name" is a directory, NOT a symlink to a directory
3112 * return FALSE if "name" is not a directory
3113 * return FALSE for error
3116 mch_isrealdir(char_u *name)
3118 return mch_isdir(name) && !mch_is_symbolic_link(name);
3122 * Create directory "name".
3123 * Return 0 on success, -1 on error.
3126 mch_mkdir(char_u *name)
3129 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3134 p = enc_to_utf16(name, NULL);
3137 retval = _wmkdir(p);
3142 return _mkdir((const char *)name);
3146 * Delete directory "name".
3147 * Return 0 on success, -1 on error.
3150 mch_rmdir(char_u *name)
3153 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3158 p = enc_to_utf16(name, NULL);
3161 retval = _wrmdir(p);
3166 return _rmdir((const char *)name);
3170 * Return TRUE if file "fname" has more than one link.
3173 mch_is_hard_link(char_u *fname)
3175 BY_HANDLE_FILE_INFORMATION info;
3177 return win32_fileinfo(fname, &info) == FILEINFO_OK
3178 && info.nNumberOfLinks > 1;
3182 * Return TRUE if "name" is a symbolic link (or a junction).
3185 mch_is_symbolic_link(char_u *name)
3189 WIN32_FIND_DATAA findDataA;
3190 DWORD fileFlags = 0, reparseTag = 0;
3193 WIN32_FIND_DATAW findDataW;
3195 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3196 wn = enc_to_utf16(name, NULL);
3199 hFind = FindFirstFileW(wn, &findDataW);
3201 if (hFind != INVALID_HANDLE_VALUE)
3203 fileFlags = findDataW.dwFileAttributes;
3204 reparseTag = findDataW.dwReserved0;
3210 hFind = FindFirstFile((LPCSTR)name, &findDataA);
3211 if (hFind != INVALID_HANDLE_VALUE)
3213 fileFlags = findDataA.dwFileAttributes;
3214 reparseTag = findDataA.dwReserved0;
3218 if (hFind != INVALID_HANDLE_VALUE)
3221 if ((fileFlags & FILE_ATTRIBUTE_REPARSE_POINT)
3222 && (reparseTag == IO_REPARSE_TAG_SYMLINK
3223 || reparseTag == IO_REPARSE_TAG_MOUNT_POINT))
3230 * Return TRUE if file "fname" has more than one link or if it is a symbolic
3234 mch_is_linked(char_u *fname)
3236 if (mch_is_hard_link(fname) || mch_is_symbolic_link(fname))
3242 * Get the by-handle-file-information for "fname".
3243 * Returns FILEINFO_OK when OK.
3244 * returns FILEINFO_ENC_FAIL when enc_to_utf16() failed.
3245 * Returns FILEINFO_READ_FAIL when CreateFile() failed.
3246 * Returns FILEINFO_INFO_FAIL when GetFileInformationByHandle() failed.
3249 win32_fileinfo(char_u *fname, BY_HANDLE_FILE_INFORMATION *info)
3252 int res = FILEINFO_READ_FAIL;
3256 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3258 wn = enc_to_utf16(fname, NULL);
3260 return FILEINFO_ENC_FAIL;
3264 hFile = CreateFileW(wn, /* file name */
3265 GENERIC_READ, /* access mode */
3266 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
3267 NULL, /* security descriptor */
3268 OPEN_EXISTING, /* creation disposition */
3269 FILE_FLAG_BACKUP_SEMANTICS, /* file attributes */
3270 NULL); /* handle to template file */
3275 hFile = CreateFile((LPCSTR)fname, /* file name */
3276 GENERIC_READ, /* access mode */
3277 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
3278 NULL, /* security descriptor */
3279 OPEN_EXISTING, /* creation disposition */
3280 FILE_FLAG_BACKUP_SEMANTICS, /* file attributes */
3281 NULL); /* handle to template file */
3283 if (hFile != INVALID_HANDLE_VALUE)
3285 if (GetFileInformationByHandle(hFile, info) != 0)
3288 res = FILEINFO_INFO_FAIL;
3296 * get file attributes for `name'
3298 * else FILE_ATTRIBUTE_* defined in winnt.h
3301 win32_getattrs(char_u *name)
3307 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3308 p = enc_to_utf16(name, NULL);
3312 attr = GetFileAttributesW(p);
3317 attr = GetFileAttributes((char *)name);
3323 * set file attributes for `name' to `attrs'
3325 * return -1 for failure, 0 otherwise
3329 win32_setattrs(char_u *name, int attrs)
3335 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3336 p = enc_to_utf16(name, NULL);
3340 res = SetFileAttributesW(p, attrs);
3345 res = SetFileAttributes((char *)name, attrs);
3347 return res ? 0 : -1;
3351 * Set archive flag for "name".
3355 win32_set_archive(char_u *name)
3357 int attrs = win32_getattrs(name);
3361 attrs |= FILE_ATTRIBUTE_ARCHIVE;
3362 return win32_setattrs(name, attrs);
3366 * Return TRUE if file or directory "name" is writable (not readonly).
3367 * Strange semantics of Win32: a readonly directory is writable, but you can't
3368 * delete a file. Let's say this means it is writable.
3371 mch_writable(char_u *name)
3373 int attrs = win32_getattrs(name);
3375 return (attrs != -1 && (!(attrs & FILE_ATTRIBUTE_READONLY)
3376 || (attrs & FILE_ATTRIBUTE_DIRECTORY)));
3380 * Return TRUE if "name" can be executed, FALSE if not.
3381 * If "use_path" is FALSE only check if "name" is executable.
3382 * When returning TRUE and "path" is not NULL save the path and set "*path" to
3383 * the allocated memory.
3386 mch_can_exe(char_u *name, char_u **path, int use_path)
3388 char_u buf[_MAX_PATH];
3389 int len = (int)STRLEN(name);
3392 if (len >= _MAX_PATH) /* safety check */
3395 /* If there already is an extension try using the name directly. Also do
3396 * this with a Unix-shell like 'shell'. */
3397 if (vim_strchr(gettail(name), '.') != NULL
3398 || strstr((char *)gettail(p_sh), "sh") != NULL)
3399 if (executable_exists((char *)name, path, use_path))
3403 * Loop over all extensions in $PATHEXT.
3405 vim_strncpy(buf, name, _MAX_PATH - 1);
3406 p = mch_getenv("PATHEXT");
3408 p = (char_u *)".com;.exe;.bat;.cmd";
3411 if (p[0] == '.' && (p[1] == NUL || p[1] == ';'))
3413 /* A single "." means no extension is added. */
3420 copy_option_part(&p, buf + len, _MAX_PATH - len, ";");
3421 if (executable_exists((char *)buf, path, use_path))
3428 * Check what "name" is:
3429 * NODE_NORMAL: file or directory (or doesn't exist)
3430 * NODE_WRITABLE: writable device, socket, fifo, etc.
3431 * NODE_OTHER: non-writable things
3434 mch_nodetype(char_u *name)
3442 /* We can't open a file with a name "\\.\con" or "\\.\prn" and trying to
3443 * read from it later will cause Vim to hang. Thus return NODE_WRITABLE
3445 if (STRNCMP(name, "\\\\.\\", 4) == 0)
3446 return NODE_WRITABLE;
3449 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3450 wn = enc_to_utf16(name, NULL);
3454 hFile = CreateFileW(wn, /* file name */
3455 GENERIC_WRITE, /* access mode */
3457 NULL, /* security descriptor */
3458 OPEN_EXISTING, /* creation disposition */
3459 0, /* file attributes */
3460 NULL); /* handle to template file */
3465 hFile = CreateFile((LPCSTR)name, /* file name */
3466 GENERIC_WRITE, /* access mode */
3468 NULL, /* security descriptor */
3469 OPEN_EXISTING, /* creation disposition */
3470 0, /* file attributes */
3471 NULL); /* handle to template file */
3473 if (hFile == INVALID_HANDLE_VALUE)
3476 type = GetFileType(hFile);
3478 if (type == FILE_TYPE_CHAR)
3479 return NODE_WRITABLE;
3480 if (type == FILE_TYPE_DISK)
3488 PSECURITY_DESCRIPTOR pSecurityDescriptor;
3497 * Return a pointer to the ACL of file "fname" in allocated memory.
3498 * Return NULL if the ACL is not available for whatever reason.
3501 mch_get_acl(char_u *fname)
3504 return (vim_acl_T)NULL;
3506 struct my_acl *p = NULL;
3509 p = (struct my_acl *)alloc_clear((unsigned)sizeof(struct my_acl));
3515 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3516 wn = enc_to_utf16(fname, NULL);
3519 /* Try to retrieve the entire security descriptor. */
3520 err = GetNamedSecurityInfoW(
3521 wn, // Abstract filename
3522 SE_FILE_OBJECT, // File Object
3523 OWNER_SECURITY_INFORMATION |
3524 GROUP_SECURITY_INFORMATION |
3525 DACL_SECURITY_INFORMATION |
3526 SACL_SECURITY_INFORMATION,
3527 &p->pSidOwner, // Ownership information.
3528 &p->pSidGroup, // Group membership.
3529 &p->pDacl, // Discretionary information.
3530 &p->pSacl, // For auditing purposes.
3531 &p->pSecurityDescriptor);
3532 if (err == ERROR_ACCESS_DENIED ||
3533 err == ERROR_PRIVILEGE_NOT_HELD)
3535 /* Retrieve only DACL. */
3536 (void)GetNamedSecurityInfoW(
3539 DACL_SECURITY_INFORMATION,
3544 &p->pSecurityDescriptor);
3546 if (p->pSecurityDescriptor == NULL)
3548 mch_free_acl((vim_acl_T)p);
3556 /* Try to retrieve the entire security descriptor. */
3557 err = GetNamedSecurityInfo(
3558 (LPSTR)fname, // Abstract filename
3559 SE_FILE_OBJECT, // File Object
3560 OWNER_SECURITY_INFORMATION |
3561 GROUP_SECURITY_INFORMATION |
3562 DACL_SECURITY_INFORMATION |
3563 SACL_SECURITY_INFORMATION,
3564 &p->pSidOwner, // Ownership information.
3565 &p->pSidGroup, // Group membership.
3566 &p->pDacl, // Discretionary information.
3567 &p->pSacl, // For auditing purposes.
3568 &p->pSecurityDescriptor);
3569 if (err == ERROR_ACCESS_DENIED ||
3570 err == ERROR_PRIVILEGE_NOT_HELD)
3572 /* Retrieve only DACL. */
3573 (void)GetNamedSecurityInfo(
3576 DACL_SECURITY_INFORMATION,
3581 &p->pSecurityDescriptor);
3583 if (p->pSecurityDescriptor == NULL)
3585 mch_free_acl((vim_acl_T)p);
3591 return (vim_acl_T)p;
3597 * Check if "acl" contains inherited ACE.
3600 is_acl_inherited(PACL acl)
3603 ACL_SIZE_INFORMATION acl_info;
3604 PACCESS_ALLOWED_ACE ace;
3606 acl_info.AceCount = 0;
3607 GetAclInformation(acl, &acl_info, sizeof(acl_info), AclSizeInformation);
3608 for (i = 0; i < acl_info.AceCount; i++)
3610 GetAce(acl, i, (LPVOID *)&ace);
3611 if (ace->Header.AceFlags & INHERITED_ACE)
3619 * Set the ACL of file "fname" to "acl" (unless it's NULL).
3620 * Errors are ignored.
3621 * This must only be called with "acl" equal to what mch_get_acl() returned.
3624 mch_set_acl(char_u *fname, vim_acl_T acl)
3627 struct my_acl *p = (struct my_acl *)acl;
3628 SECURITY_INFORMATION sec_info = 0;
3636 /* Set security flags */
3638 sec_info |= OWNER_SECURITY_INFORMATION;
3640 sec_info |= GROUP_SECURITY_INFORMATION;
3643 sec_info |= DACL_SECURITY_INFORMATION;
3644 /* Do not inherit its parent's DACL.
3645 * If the DACL is inherited, Cygwin permissions would be changed.
3647 if (!is_acl_inherited(p->pDacl))
3648 sec_info |= PROTECTED_DACL_SECURITY_INFORMATION;
3651 sec_info |= SACL_SECURITY_INFORMATION;
3654 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3655 wn = enc_to_utf16(fname, NULL);
3658 (void)SetNamedSecurityInfoW(
3659 wn, // Abstract filename
3660 SE_FILE_OBJECT, // File Object
3662 p->pSidOwner, // Ownership information.
3663 p->pSidGroup, // Group membership.
3664 p->pDacl, // Discretionary information.
3665 p->pSacl // For auditing purposes.
3672 (void)SetNamedSecurityInfo(
3673 (LPSTR)fname, // Abstract filename
3674 SE_FILE_OBJECT, // File Object
3676 p->pSidOwner, // Ownership information.
3677 p->pSidGroup, // Group membership.
3678 p->pDacl, // Discretionary information.
3679 p->pSacl // For auditing purposes.
3687 mch_free_acl(vim_acl_T acl)
3690 struct my_acl *p = (struct my_acl *)acl;
3694 LocalFree(p->pSecurityDescriptor); // Free the memory just in case
3700 #ifndef FEAT_GUI_W32
3703 * handler for ctrl-break, ctrl-c interrupts, and fatal events.
3712 if (ctrl_c_interrupts)
3713 g_fCtrlCPressed = TRUE;
3716 case CTRL_BREAK_EVENT:
3717 g_fCBrkPressed = TRUE;
3720 /* fatal events: shut down gracefully */
3721 case CTRL_CLOSE_EVENT:
3722 case CTRL_LOGOFF_EVENT:
3723 case CTRL_SHUTDOWN_EVENT:
3724 windgoto((int)Rows - 1, 0);
3725 g_fForceExit = TRUE;
3727 vim_snprintf((char *)IObuff, IOSIZE, _("Vim: Caught %s event\n"),
3728 (dwCtrlType == CTRL_CLOSE_EVENT
3730 : dwCtrlType == CTRL_LOGOFF_EVENT
3734 OutputDebugString(IObuff);
3737 preserve_exit(); /* output IObuff, preserve files and exit */
3739 return TRUE; /* not reached */
3748 * set the tty in (raw) ? "raw" : "cooked" mode
3751 mch_settmode(int tmode)
3755 BOOL bEnableHandler;
3757 GetConsoleMode(g_hConIn, &cmodein);
3758 GetConsoleMode(g_hConOut, &cmodeout);
3759 if (tmode == TMODE_RAW)
3761 cmodein &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
3765 cmodein |= ENABLE_MOUSE_INPUT;
3767 cmodeout &= ~(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
3768 bEnableHandler = TRUE;
3772 cmodein |= (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
3774 cmodeout |= (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
3775 bEnableHandler = FALSE;
3777 SetConsoleMode(g_hConIn, cmodein);
3778 SetConsoleMode(g_hConOut, cmodeout);
3779 SetConsoleCtrlHandler(handler_routine, bEnableHandler);
3781 #ifdef MCH_WRITE_DUMP
3784 fprintf(fdDump, "mch_settmode(%s, in = %x, out = %x)\n",
3785 tmode == TMODE_RAW ? "raw" :
3786 tmode == TMODE_COOK ? "cooked" : "normal",
3795 * Get the size of the current window in `Rows' and `Columns'
3796 * Return OK when size could be determined, FAIL otherwise.
3799 mch_get_shellsize(void)
3801 CONSOLE_SCREEN_BUFFER_INFO csbi;
3803 if (!g_fTermcapMode && g_cbTermcap.IsValid)
3806 * For some reason, we are trying to get the screen dimensions
3807 * even though we are not in termcap mode. The 'Rows' and 'Columns'
3808 * variables are really intended to mean the size of Vim screen
3809 * while in termcap mode.
3811 Rows = g_cbTermcap.Info.dwSize.Y;
3812 Columns = g_cbTermcap.Info.dwSize.X;
3814 else if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
3816 Rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3817 Columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3828 * Set a console window to `xSize' * `ySize'
3831 ResizeConBufAndWindow(
3836 CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */
3837 SMALL_RECT srWindowRect; /* hold the new console size */
3840 #ifdef MCH_WRITE_DUMP
3843 fprintf(fdDump, "ResizeConBufAndWindow(%d, %d)\n", xSize, ySize);
3848 /* get the largest size we can size the console window to */
3849 coordScreen = GetLargestConsoleWindowSize(hConsole);
3851 /* define the new console window size and scroll position */
3852 srWindowRect.Left = srWindowRect.Top = (SHORT) 0;
3853 srWindowRect.Right = (SHORT) (min(xSize, coordScreen.X) - 1);
3854 srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1);
3856 if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
3860 sx = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3861 sy = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3862 if (sy < ySize || sx < xSize)
3865 * Increasing number of lines/columns, do buffer first.
3866 * Use the maximal size in x and y direction.
3869 coordScreen.Y = ySize;
3873 coordScreen.X = xSize;
3876 SetConsoleScreenBufferSize(hConsole, coordScreen);
3880 if (!SetConsoleWindowInfo(g_hConOut, TRUE, &srWindowRect))
3882 #ifdef MCH_WRITE_DUMP
3885 fprintf(fdDump, "SetConsoleWindowInfo failed: %lx\n",
3892 /* define the new console buffer size */
3893 coordScreen.X = xSize;
3894 coordScreen.Y = ySize;
3896 if (!SetConsoleScreenBufferSize(hConsole, coordScreen))
3898 #ifdef MCH_WRITE_DUMP
3901 fprintf(fdDump, "SetConsoleScreenBufferSize failed: %lx\n",
3911 * Set the console window to `Rows' * `Columns'
3914 mch_set_shellsize(void)
3918 /* Don't change window size while still starting up */
3919 if (suppress_winsize != 0)
3921 suppress_winsize = 2;
3927 coordScreen = GetLargestConsoleWindowSize(g_hConOut);
3929 /* Clamp Rows and Columns to reasonable values */
3930 if (Rows > coordScreen.Y)
3931 Rows = coordScreen.Y;
3932 if (Columns > coordScreen.X)
3933 Columns = coordScreen.X;
3935 ResizeConBufAndWindow(g_hConOut, Columns, Rows);
3940 * Rows and/or Columns has changed.
3943 mch_new_shellsize(void)
3945 set_scroll_region(0, 0, Columns - 1, Rows - 1);
3950 * Called when started up, to set the winsize that was delayed.
3953 mch_set_winsize_now(void)
3955 if (suppress_winsize == 2)
3957 suppress_winsize = 0;
3958 mch_set_shellsize();
3961 suppress_winsize = 0;
3963 #endif /* FEAT_GUI_W32 */
3968 BOOL inherit_handles,
3971 PROCESS_INFORMATION *pi)
3974 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3976 WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL);
3981 ret = CreateProcessW(
3982 NULL, /* Executable name */
3983 wcmd, /* Command to execute */
3984 NULL, /* Process security attributes */
3985 NULL, /* Thread security attributes */
3986 inherit_handles, /* Inherit handles */
3987 flags, /* Creation flags */
3988 NULL, /* Environment */
3989 NULL, /* Current directory */
3990 (LPSTARTUPINFOW)si, /* Startup information */
3991 pi); /* Process information */
3997 return CreateProcess(
3998 NULL, /* Executable name */
3999 cmd, /* Command to execute */
4000 NULL, /* Process security attributes */
4001 NULL, /* Thread security attributes */
4002 inherit_handles, /* Inherit handles */
4003 flags, /* Creation flags */
4004 NULL, /* Environment */
4005 NULL, /* Current directory */
4006 si, /* Startup information */
4007 pi); /* Process information */
4017 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4019 WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL);
4023 ret = ShellExecuteW(NULL, NULL, wcmd, NULL, NULL, n_show_cmd);
4029 return ShellExecute(NULL, NULL, cmd, NULL, NULL, n_show_cmd);
4033 #if defined(FEAT_GUI_W32) || defined(PROTO)
4036 * Specialised version of system() for Win32 GUI mode.
4037 * This version proceeds as follows:
4038 * 1. Create a console window for use by the subprocess
4039 * 2. Run the subprocess (it gets the allocated console by default)
4040 * 3. Wait for the subprocess to terminate and get its exit code
4041 * 4. Prompt the user to press a key to close the console window
4044 mch_system_classic(char *cmd, int options)
4047 PROCESS_INFORMATION pi;
4049 HWND hwnd = GetFocus();
4052 si.lpReserved = NULL;
4053 si.lpDesktop = NULL;
4055 si.dwFlags = STARTF_USESHOWWINDOW;
4057 * It's nicer to run a filter command in a minimized window.
4058 * Don't activate the window to keep focus on Vim.
4060 if (options & SHELL_DOOUT)
4061 si.wShowWindow = SW_SHOWMINNOACTIVE;
4063 si.wShowWindow = SW_SHOWNORMAL;
4065 si.lpReserved2 = NULL;
4067 /* Now, run the command */
4068 vim_create_process(cmd, FALSE,
4069 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE, &si, &pi);
4071 /* Wait for the command to terminate before continuing */
4076 /* Keep updating the window while waiting for the shell to finish. */
4081 if (pPeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
4083 TranslateMessage(&msg);
4084 pDispatchMessage(&msg);
4088 if (WaitForSingleObject(pi.hProcess, delay) != WAIT_TIMEOUT)
4091 /* We start waiting for a very short time and then increase it, so
4092 * that we respond quickly when the process is quick, and don't
4093 * consume too much overhead when it's slow. */
4098 WaitForSingleObject(pi.hProcess, INFINITE);
4101 /* Get the command exit code */
4102 GetExitCodeProcess(pi.hProcess, &ret);
4105 /* Close the handles to the subprocess, so that it goes away */
4106 CloseHandle(pi.hThread);
4107 CloseHandle(pi.hProcess);
4109 /* Try to get input focus back. Doesn't always work though. */
4110 PostMessage(hwnd, WM_SETFOCUS, 0, 0);
4116 * Thread launched by the gui to send the current buffer data to the
4117 * process. This way avoid to hang up vim totally if the children
4118 * process take a long time to process the lines.
4120 static unsigned int __stdcall
4121 sub_process_writer(LPVOID param)
4123 HANDLE g_hChildStd_IN_Wr = param;
4124 linenr_T lnum = curbuf->b_op_start.lnum;
4127 char_u *lp = ml_get(lnum);
4133 l = (DWORD)STRLEN(lp + written);
4136 else if (lp[written] == NL)
4138 /* NL -> NUL translation */
4139 WriteFile(g_hChildStd_IN_Wr, "", 1, &len, NULL);
4143 s = vim_strchr(lp + written, NL);
4144 WriteFile(g_hChildStd_IN_Wr, (char *)lp + written,
4145 s == NULL ? l : (DWORD)(s - (lp + written)),
4150 /* Finished a line, add a NL, unless this line should not have
4152 if (lnum != curbuf->b_op_end.lnum
4153 || (!curbuf->b_p_bin
4154 && curbuf->b_p_fixeol)
4155 || (lnum != curbuf->b_no_eol_lnum
4156 && (lnum != curbuf->b_ml.ml_line_count
4157 || curbuf->b_p_eol)))
4159 WriteFile(g_hChildStd_IN_Wr, "\n", 1, (LPDWORD)&ignored, NULL);
4163 if (lnum > curbuf->b_op_end.lnum)
4173 /* finished all the lines, close pipe */
4174 CloseHandle(g_hChildStd_IN_Wr);
4179 # define BUFLEN 100 /* length for buffer, stolen from unix version */
4182 * This function read from the children's stdout and write the
4183 * data on screen or in the buffer accordingly.
4186 dump_pipe(int options,
4187 HANDLE g_hChildStd_OUT_Rd,
4192 DWORD availableBytes = 0;
4199 /* we query the pipe to see if there is any data to read
4200 * to avoid to perform a blocking read */
4201 ret = PeekNamedPipe(g_hChildStd_OUT_Rd, /* pipe to query */
4202 NULL, /* optional buffer */
4203 0, /* buffer size */
4204 NULL, /* number of read bytes */
4205 &availableBytes, /* available bytes total */
4206 NULL); /* byteLeft */
4209 /* We got real data in the pipe, read it */
4210 while (ret != 0 && availableBytes > 0)
4215 (DWORD)(BUFLEN - *buffer_off);
4219 toRead = availableBytes < toRead ? availableBytes : toRead;
4220 ReadFile(g_hChildStd_OUT_Rd, buffer
4222 + *buffer_off, toRead
4228 /* If we haven't read anything, there is a problem */
4232 availableBytes -= len;
4234 if (options & SHELL_READ)
4236 /* Do NUL -> NL translation, append NL separated
4237 * lines to the current buffer. */
4238 for (i = 0; i < len; ++i)
4240 if (buffer[i] == NL)
4242 else if (buffer[i] == NUL)
4245 ga_append(ga, buffer[i]);
4258 /* Check if the last character in buffer[] is
4259 * incomplete, keep these bytes for the next
4261 for (p = buffer; p < buffer + len; p += l)
4265 l = 1; /* NUL byte? */
4266 else if (MB_BYTE2LEN(*p) != l)
4269 if (p == buffer) /* no complete character */
4271 /* avoid getting stuck at an illegal byte */
4283 if (p < buffer + len)
4286 *buffer_off = (DWORD)((buffer + len) - p);
4287 mch_memmove(buffer, p, *buffer_off);
4292 # endif /* FEAT_MBYTE */
4299 windgoto(msg_row, msg_col);
4306 * Version of system to use for windows NT > 5.0 (Win2K), use pipe
4307 * for communication and doesn't open any new window.
4310 mch_system_piped(char *cmd, int options)
4313 PROCESS_INFORMATION pi;
4316 HANDLE g_hChildStd_IN_Rd = NULL;
4317 HANDLE g_hChildStd_IN_Wr = NULL;
4318 HANDLE g_hChildStd_OUT_Rd = NULL;
4319 HANDLE g_hChildStd_OUT_Wr = NULL;
4321 char_u buffer[BUFLEN + 1]; /* reading buffer + size */
4324 /* buffer used to receive keys */
4325 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4326 int ta_len = 0; /* valid bytes in ta_buf[] */
4333 DWORD buffer_off = 0; /* valid bytes in buffer[] */
4336 SECURITY_ATTRIBUTES saAttr;
4338 /* Set the bInheritHandle flag so pipe handles are inherited. */
4339 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
4340 saAttr.bInheritHandle = TRUE;
4341 saAttr.lpSecurityDescriptor = NULL;
4343 if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)
4344 /* Ensure the read handle to the pipe for STDOUT is not inherited. */
4345 || ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)
4346 /* Create a pipe for the child process's STDIN. */
4347 || ! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)
4348 /* Ensure the write handle to the pipe for STDIN is not inherited. */
4349 || ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
4351 CloseHandle(g_hChildStd_IN_Rd);
4352 CloseHandle(g_hChildStd_IN_Wr);
4353 CloseHandle(g_hChildStd_OUT_Rd);
4354 CloseHandle(g_hChildStd_OUT_Wr);
4355 MSG_PUTS(_("\nCannot create pipes\n"));
4359 si.lpReserved = NULL;
4360 si.lpDesktop = NULL;
4362 si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
4364 /* set-up our file redirection */
4365 si.hStdError = g_hChildStd_OUT_Wr;
4366 si.hStdOutput = g_hChildStd_OUT_Wr;
4367 si.hStdInput = g_hChildStd_IN_Rd;
4368 si.wShowWindow = SW_HIDE;
4370 si.lpReserved2 = NULL;
4372 if (options & SHELL_READ)
4373 ga_init2(&ga, 1, BUFLEN);
4377 p = (char *)vim_strsave((char_u *)cmd);
4379 unescape_shellxquote((char_u *)p, p_sxe);
4384 /* Now, run the command.
4385 * About "Inherit handles" being TRUE: this command can be litigious,
4386 * handle inheritance was deactivated for pending temp file, but, if we
4387 * deactivate it, the pipes don't work for some reason. */
4388 vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE, &si, &pi);
4393 /* Close our unused side of the pipes */
4394 CloseHandle(g_hChildStd_IN_Rd);
4395 CloseHandle(g_hChildStd_OUT_Wr);
4397 if (options & SHELL_WRITE)
4399 HANDLE thread = (HANDLE)
4400 _beginthreadex(NULL, /* security attributes */
4401 0, /* default stack size */
4402 sub_process_writer, /* function to be executed */
4403 g_hChildStd_IN_Wr, /* parameter */
4404 0, /* creation flag, start immediately */
4405 NULL); /* we don't care about thread id */
4406 CloseHandle(thread);
4407 g_hChildStd_IN_Wr = NULL;
4410 /* Keep updating the window while waiting for the shell to finish. */
4415 if (pPeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
4417 TranslateMessage(&msg);
4418 pDispatchMessage(&msg);
4421 /* write pipe information in the window */
4422 if ((options & (SHELL_READ|SHELL_WRITE))
4429 if (!(options & SHELL_EXPAND)
4431 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4432 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4437 && (ta_len > 0 || noread_cnt > 4))
4441 /* Get extra characters when we don't have any. Reset the
4442 * counter and timer. */
4444 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4446 if (ta_len > 0 || len > 0)
4449 * For pipes: Check for CTRL-C: send interrupt signal to
4450 * child. Check for CTRL-D: EOF, close pipe to child.
4452 if (len == 1 && cmd != NULL)
4454 if (ta_buf[ta_len] == Ctrl_C)
4456 /* Learn what exit code is expected, for
4457 * now put 9 as SIGKILL */
4458 TerminateProcess(pi.hProcess, 9);
4460 if (ta_buf[ta_len] == Ctrl_D)
4462 CloseHandle(g_hChildStd_IN_Wr);
4463 g_hChildStd_IN_Wr = NULL;
4467 /* replace K_BS by <BS> and K_DEL by <DEL> */
4468 for (i = ta_len; i < ta_len + len; ++i)
4470 if (ta_buf[i] == CSI && len - i > 2)
4472 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4473 if (c == K_DEL || c == K_KDEL || c == K_BS)
4475 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4476 (size_t)(len - i - 2));
4477 if (c == K_DEL || c == K_KDEL)
4484 else if (ta_buf[i] == '\r')
4488 i += (*mb_ptr2len_len)(ta_buf + i,
4489 ta_len + len - i) - 1;
4494 * For pipes: echo the typed characters. For a pty this
4495 * does not seem to work.
4497 for (i = ta_len; i < ta_len + len; ++i)
4499 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4500 msg_putchar(ta_buf[i]);
4504 int l = (*mb_ptr2len)(ta_buf + i);
4506 msg_outtrans_len(ta_buf + i, l);
4511 msg_outtrans_len(ta_buf + i, 1);
4513 windgoto(msg_row, msg_col);
4519 * Write the characters to the child, unless EOF has been
4520 * typed for pipes. Write one character at a time, to
4521 * avoid losing too much typeahead. When writing buffer
4522 * lines, drop the typed characters (only check for
4525 if (options & SHELL_WRITE)
4527 else if (g_hChildStd_IN_Wr != NULL)
4529 WriteFile(g_hChildStd_IN_Wr, (char*)ta_buf,
4531 // if we are typing in, we want to keep things reactive
4536 mch_memmove(ta_buf, ta_buf + len, ta_len);
4544 ui_inchar_undo(ta_buf, ta_len);
4546 if (WaitForSingleObject(pi.hProcess, delay) != WAIT_TIMEOUT)
4548 dump_pipe(options, g_hChildStd_OUT_Rd, &ga, buffer, &buffer_off);
4553 dump_pipe(options, g_hChildStd_OUT_Rd, &ga, buffer, &buffer_off);
4555 /* We start waiting for a very short time and then increase it, so
4556 * that we respond quickly when the process is quick, and don't
4557 * consume too much overhead when it's slow. */
4562 /* Close the pipe */
4563 CloseHandle(g_hChildStd_OUT_Rd);
4564 if (g_hChildStd_IN_Wr != NULL)
4565 CloseHandle(g_hChildStd_IN_Wr);
4567 WaitForSingleObject(pi.hProcess, INFINITE);
4569 /* Get the command exit code */
4570 GetExitCodeProcess(pi.hProcess, &ret);
4572 if (options & SHELL_READ)
4576 append_ga_line(&ga);
4577 /* remember that the NL was missing */
4578 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
4581 curbuf->b_no_eol_lnum = 0;
4585 /* Close the handles to the subprocess, so that it goes away */
4586 CloseHandle(pi.hThread);
4587 CloseHandle(pi.hProcess);
4593 mch_system(char *cmd, int options)
4595 /* if we can pipe and the shelltemp option is off */
4597 return mch_system_piped(cmd, options);
4599 return mch_system_classic(cmd, options);
4605 mch_system(char *cmd, int options)
4607 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4609 WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL);
4612 int ret = _wsystem(wcmd);
4620 # define mch_system(c, o) system(c)
4626 * Either execute a command by calling the shell or start a new shell
4631 int options) /* SHELL_*, see vim.h */
4634 int tmode = cur_tmode;
4636 char szShellTitle[512];
4638 int did_set_title = FALSE;
4640 /* Change the title to reflect that we are in a subshell. */
4641 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4643 WCHAR szShellTitle[512];
4645 if (GetConsoleTitleW(szShellTitle,
4646 sizeof(szShellTitle)/sizeof(WCHAR) - 4) > 0)
4649 wcscat(szShellTitle, L" :sh");
4652 WCHAR *wn = enc_to_utf16((char_u *)cmd, NULL);
4656 wcscat(szShellTitle, L" - !");
4657 if ((wcslen(szShellTitle) + wcslen(wn) <
4658 sizeof(szShellTitle)/sizeof(WCHAR)))
4659 wcscat(szShellTitle, wn);
4660 SetConsoleTitleW(szShellTitle);
4662 did_set_title = TRUE;
4669 /* Change the title to reflect that we are in a subshell. */
4670 if (GetConsoleTitle(szShellTitle, sizeof(szShellTitle) - 4) > 0)
4673 strcat(szShellTitle, " :sh");
4676 strcat(szShellTitle, " - !");
4677 if ((strlen(szShellTitle) + strlen((char *)cmd)
4678 < sizeof(szShellTitle)))
4679 strcat(szShellTitle, (char *)cmd);
4681 SetConsoleTitle(szShellTitle);
4687 #ifdef MCH_WRITE_DUMP
4690 fprintf(fdDump, "mch_call_shell(\"%s\", %d)\n", cmd, options);
4696 * Catch all deadly signals while running the external command, because a
4697 * CTRL-C, Ctrl-Break or illegal instruction might otherwise kill us.
4699 signal(SIGINT, SIG_IGN);
4700 #if defined(__GNUC__) && !defined(__MINGW32__)
4701 signal(SIGKILL, SIG_IGN);
4703 signal(SIGBREAK, SIG_IGN);
4705 signal(SIGILL, SIG_IGN);
4706 signal(SIGFPE, SIG_IGN);
4707 signal(SIGSEGV, SIG_IGN);
4708 signal(SIGTERM, SIG_IGN);
4709 signal(SIGABRT, SIG_IGN);
4711 if (options & SHELL_COOKED)
4712 settmode(TMODE_COOK); /* set to normal mode */
4716 x = mch_system((char *)p_sh, options);
4720 /* we use "command" or "cmd" to start the shell; slow but easy */
4721 char_u *newcmd = NULL;
4722 char_u *cmdbase = cmd;
4725 /* Skip a leading ", ( and "(. */
4726 if (*cmdbase == '"' )
4728 if (*cmdbase == '(')
4731 if ((STRNICMP(cmdbase, "start", 5) == 0) && VIM_ISWHITE(cmdbase[5]))
4734 PROCESS_INFORMATION pi;
4735 DWORD flags = CREATE_NEW_CONSOLE;
4736 INT n_show_cmd = SW_SHOWNORMAL;
4739 ZeroMemory(&si, sizeof(si));
4741 si.lpReserved = NULL;
4742 si.lpDesktop = NULL;
4746 si.lpReserved2 = NULL;
4748 cmdbase = skipwhite(cmdbase + 5);
4749 if ((STRNICMP(cmdbase, "/min", 4) == 0)
4750 && VIM_ISWHITE(cmdbase[4]))
4752 cmdbase = skipwhite(cmdbase + 4);
4753 si.dwFlags = STARTF_USESHOWWINDOW;
4754 si.wShowWindow = SW_SHOWMINNOACTIVE;
4755 n_show_cmd = SW_SHOWMINNOACTIVE;
4757 else if ((STRNICMP(cmdbase, "/b", 2) == 0)
4758 && VIM_ISWHITE(cmdbase[2]))
4760 cmdbase = skipwhite(cmdbase + 2);
4761 flags = CREATE_NO_WINDOW;
4762 si.dwFlags = STARTF_USESTDHANDLES;
4763 si.hStdInput = CreateFile("\\\\.\\NUL", // File name
4764 GENERIC_READ, // Access flags
4766 NULL, // Security att.
4767 OPEN_EXISTING, // Open flags
4768 FILE_ATTRIBUTE_NORMAL, // File att.
4770 si.hStdOutput = si.hStdInput;
4771 si.hStdError = si.hStdInput;
4774 /* Remove a trailing ", ) and )" if they have a match
4775 * at the start of the command. */
4778 p = cmdbase + STRLEN(cmdbase);
4779 if (p > cmdbase && p[-1] == '"' && *cmd == '"')
4781 if (p > cmdbase && p[-1] == ')'
4782 && (*cmd =='(' || cmd[1] == '('))
4787 unescape_shellxquote(cmdbase, p_sxe);
4790 * If creating new console, arguments are passed to the
4791 * 'cmd.exe' as-is. If it's not, arguments are not treated
4792 * correctly for current 'cmd.exe'. So unescape characters in
4793 * shellxescape except '|' for avoiding to be treated as
4794 * argument to them. Pass the arguments to sub-shell.
4796 if (flags != CREATE_NEW_CONSOLE)
4799 char_u *cmd_shell = mch_getenv("COMSPEC");
4801 if (cmd_shell == NULL || *cmd_shell == NUL)
4802 cmd_shell = (char_u *)default_shell();
4804 subcmd = vim_strsave_escaped_ext(cmdbase,
4805 (char_u *)"|", '^', FALSE);
4808 /* make "cmd.exe /c arguments" */
4809 cmdlen = STRLEN(cmd_shell) + STRLEN(subcmd) + 5;
4810 newcmd = lalloc(cmdlen, TRUE);
4812 vim_snprintf((char *)newcmd, cmdlen, "%s /c %s",
4821 * Now, start the command as a process, so that it doesn't
4822 * inherit our handles which causes unpleasant dangling swap
4823 * files if we exit before the spawned process
4825 if (vim_create_process((char *)newcmd, FALSE, flags, &si, &pi))
4827 else if (vim_shell_execute((char *)newcmd, n_show_cmd)
4834 EMSG(_("E371: Command not found"));
4838 if (newcmd != cmdbase)
4841 if (si.dwFlags == STARTF_USESTDHANDLES && si.hStdInput != NULL)
4843 /* Close the handle to \\.\NUL created above. */
4844 CloseHandle(si.hStdInput);
4846 /* Close the handles to the subprocess, so that it goes away */
4847 CloseHandle(pi.hThread);
4848 CloseHandle(pi.hProcess);
4854 (!p_stmp ? 0 : STRLEN(vimrun_path)) +
4856 STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10);
4858 newcmd = lalloc(cmdlen, TRUE);
4861 #if defined(FEAT_GUI_W32)
4862 if (need_vimrun_warning)
4864 char *msg = _("VIMRUN.EXE not found in your $PATH.\n"
4865 "External commands will not pause after completion.\n"
4866 "See :help win32-vimrun for more information.");
4867 char *title = _("Vim Warning");
4869 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4871 WCHAR *wmsg = enc_to_utf16((char_u *)msg, NULL);
4872 WCHAR *wtitle = enc_to_utf16((char_u *)title, NULL);
4874 if (wmsg != NULL && wtitle != NULL)
4875 MessageBoxW(NULL, wmsg, wtitle, MB_ICONWARNING);
4881 MessageBox(NULL, msg, title, MB_ICONWARNING);
4882 need_vimrun_warning = FALSE;
4884 if (!s_dont_use_vimrun && p_stmp)
4885 /* Use vimrun to execute the command. It opens a console
4886 * window, which can be closed without killing Vim. */
4887 vim_snprintf((char *)newcmd, cmdlen, "%s%s%s %s %s",
4889 (msg_silent != 0 || (options & SHELL_DOOUT))
4894 vim_snprintf((char *)newcmd, cmdlen, "%s %s %s",
4896 x = mch_system((char *)newcmd, options);
4902 if (tmode == TMODE_RAW)
4903 settmode(TMODE_RAW); /* set to raw mode */
4905 /* Print the return value, unless "vimrun" was used. */
4906 if (x != 0 && !(options & SHELL_SILENT) && !emsg_silent
4907 #if defined(FEAT_GUI_W32)
4908 && ((options & SHELL_DOOUT) || s_dont_use_vimrun || !p_stmp)
4912 smsg((char_u *)_("shell returned %d"), x);
4919 signal(SIGINT, SIG_DFL);
4920 #if defined(__GNUC__) && !defined(__MINGW32__)
4921 signal(SIGKILL, SIG_DFL);
4923 signal(SIGBREAK, SIG_DFL);
4925 signal(SIGILL, SIG_DFL);
4926 signal(SIGFPE, SIG_DFL);
4927 signal(SIGSEGV, SIG_DFL);
4928 signal(SIGTERM, SIG_DFL);
4929 signal(SIGABRT, SIG_DFL);
4934 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
4938 DWORD dwDesiredAccess,
4940 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4941 DWORD dwCreationDisposition,
4942 DWORD dwFlagsAndAttributes)
4947 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4949 wn = enc_to_utf16(fname, NULL);
4952 h = CreateFileW(wn, dwDesiredAccess, dwShareMode,
4953 lpSecurityAttributes, dwCreationDisposition,
4954 dwFlagsAndAttributes, NULL);
4960 h = CreateFile((LPCSTR)fname, dwDesiredAccess, dwShareMode,
4961 lpSecurityAttributes, dwCreationDisposition,
4962 dwFlagsAndAttributes, NULL);
4967 mch_start_job(char *cmd, job_T *job, jobopt_T *options)
4970 PROCESS_INFORMATION pi;
4972 SECURITY_ATTRIBUTES saAttr;
4973 channel_T *channel = NULL;
4978 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
4979 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
4980 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
4981 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
4982 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
4983 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
4984 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
4986 if (use_out_for_err && use_null_for_out)
4987 use_null_for_err = TRUE;
4989 ifd[0] = INVALID_HANDLE_VALUE;
4990 ifd[1] = INVALID_HANDLE_VALUE;
4991 ofd[0] = INVALID_HANDLE_VALUE;
4992 ofd[1] = INVALID_HANDLE_VALUE;
4993 efd[0] = INVALID_HANDLE_VALUE;
4994 efd[1] = INVALID_HANDLE_VALUE;
4996 jo = CreateJobObject(NULL, NULL);
4999 job->jv_status = JOB_FAILED;
5003 ZeroMemory(&pi, sizeof(pi));
5004 ZeroMemory(&si, sizeof(si));
5006 si.dwFlags |= STARTF_USESHOWWINDOW;
5007 si.wShowWindow = SW_HIDE;
5009 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
5010 saAttr.bInheritHandle = TRUE;
5011 saAttr.lpSecurityDescriptor = NULL;
5013 if (use_file_for_in)
5015 char_u *fname = options->jo_io_name[PART_IN];
5017 ifd[0] = job_io_file_open(fname, GENERIC_READ,
5018 FILE_SHARE_READ | FILE_SHARE_WRITE,
5019 &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL);
5020 if (ifd[0] == INVALID_HANDLE_VALUE)
5022 EMSG2(_(e_notopen), fname);
5026 else if (!use_null_for_in &&
5027 (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
5028 || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)))
5031 if (use_file_for_out)
5033 char_u *fname = options->jo_io_name[PART_OUT];
5035 ofd[1] = job_io_file_open(fname, GENERIC_WRITE,
5036 FILE_SHARE_READ | FILE_SHARE_WRITE,
5037 &saAttr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL);
5038 if (ofd[1] == INVALID_HANDLE_VALUE)
5040 EMSG2(_(e_notopen), fname);
5044 else if (!use_null_for_out &&
5045 (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
5046 || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)))
5049 if (use_file_for_err)
5051 char_u *fname = options->jo_io_name[PART_ERR];
5053 efd[1] = job_io_file_open(fname, GENERIC_WRITE,
5054 FILE_SHARE_READ | FILE_SHARE_WRITE,
5055 &saAttr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL);
5056 if (efd[1] == INVALID_HANDLE_VALUE)
5058 EMSG2(_(e_notopen), fname);
5062 else if (!use_out_for_err && !use_null_for_err &&
5063 (!CreatePipe(&efd[0], &efd[1], &saAttr, 0)
5064 || !SetHandleInformation(efd[0], HANDLE_FLAG_INHERIT, 0)))
5067 si.dwFlags |= STARTF_USESTDHANDLES;
5068 si.hStdInput = ifd[0];
5069 si.hStdOutput = ofd[1];
5070 si.hStdError = use_out_for_err ? ofd[1] : efd[1];
5072 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5074 if (options->jo_set & JO_CHANNEL)
5076 channel = options->jo_channel;
5077 if (channel != NULL)
5078 ++channel->ch_refcount;
5081 channel = add_channel();
5082 if (channel == NULL)
5086 if (!vim_create_process(cmd, TRUE,
5088 CREATE_DEFAULT_ERROR_MODE |
5089 CREATE_NEW_PROCESS_GROUP |
5094 job->jv_status = JOB_FAILED;
5098 if (!AssignProcessToJobObject(jo, pi.hProcess))
5100 /* if failing, switch the way to terminate
5101 * process with TerminateProcess. */
5105 ResumeThread(pi.hThread);
5106 CloseHandle(pi.hThread);
5107 job->jv_proc_info = pi;
5108 job->jv_job_object = jo;
5109 job->jv_status = JOB_STARTED;
5111 CloseHandle(ifd[0]);
5112 CloseHandle(ofd[1]);
5113 if (!use_out_for_err && !use_null_for_err)
5114 CloseHandle(efd[1]);
5116 job->jv_channel = channel;
5117 if (channel != NULL)
5119 channel_set_pipes(channel,
5120 use_file_for_in || use_null_for_in
5121 ? INVALID_FD : (sock_T)ifd[1],
5122 use_file_for_out || use_null_for_out
5123 ? INVALID_FD : (sock_T)ofd[0],
5124 use_out_for_err || use_file_for_err || use_null_for_err
5125 ? INVALID_FD : (sock_T)efd[0]);
5126 channel_set_job(channel, job, options);
5131 CloseHandle(ifd[0]);
5132 CloseHandle(ofd[0]);
5133 CloseHandle(efd[0]);
5134 CloseHandle(ifd[1]);
5135 CloseHandle(ofd[1]);
5136 CloseHandle(efd[1]);
5137 channel_unref(channel);
5141 mch_job_status(job_T *job)
5143 DWORD dwExitCode = 0;
5145 if (!GetExitCodeProcess(job->jv_proc_info.hProcess, &dwExitCode)
5146 || dwExitCode != STILL_ACTIVE)
5148 job->jv_exitval = (int)dwExitCode;
5149 if (job->jv_status < JOB_ENDED)
5151 ch_log(job->jv_channel, "Job ended");
5152 job->jv_status = JOB_ENDED;
5160 mch_detect_ended_job(job_T *job_list)
5162 HANDLE jobHandles[MAXIMUM_WAIT_OBJECTS];
5163 job_T *jobArray[MAXIMUM_WAIT_OBJECTS];
5164 job_T *job = job_list;
5171 for (n = 0; n < MAXIMUM_WAIT_OBJECTS
5172 && job != NULL; job = job->jv_next)
5174 if (job->jv_status == JOB_STARTED)
5176 jobHandles[n] = job->jv_proc_info.hProcess;
5183 result = WaitForMultipleObjects(n, jobHandles, FALSE, 0);
5184 if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + n)
5186 job_T *wait_job = jobArray[result - WAIT_OBJECT_0];
5188 if (STRCMP(mch_job_status(wait_job), "dead") == 0)
5196 terminate_all(HANDLE process, int code)
5199 HANDLE h = INVALID_HANDLE_VALUE;
5200 DWORD pid = GetProcessId(process);
5204 h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
5205 if (h != INVALID_HANDLE_VALUE)
5207 pe.dwSize = sizeof(PROCESSENTRY32);
5208 if (!Process32First(h, &pe))
5213 if (pe.th32ParentProcessID == pid)
5215 HANDLE ph = OpenProcess(
5216 PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
5219 terminate_all(ph, code);
5223 } while (Process32Next(h, &pe));
5230 return TerminateProcess(process, code);
5234 * Send a (deadly) signal to "job".
5235 * Return FAIL if it didn't work.
5238 mch_stop_job(job_T *job, char_u *how)
5242 if (STRCMP(how, "term") == 0 || STRCMP(how, "kill") == 0 || *how == NUL)
5245 if (job->jv_job_object != NULL)
5246 return TerminateJobObject(job->jv_job_object, 0) ? OK : FAIL;
5247 return terminate_all(job->jv_proc_info.hProcess, 0) ? OK : FAIL;
5250 if (!AttachConsole(job->jv_proc_info.dwProcessId))
5252 ret = GenerateConsoleCtrlEvent(
5253 STRCMP(how, "int") == 0 ? CTRL_C_EVENT : CTRL_BREAK_EVENT,
5254 job->jv_proc_info.dwProcessId)
5261 * Clear the data related to "job".
5264 mch_clear_job(job_T *job)
5266 if (job->jv_status != JOB_FAILED)
5268 if (job->jv_job_object != NULL)
5269 CloseHandle(job->jv_job_object);
5270 CloseHandle(job->jv_proc_info.hProcess);
5276 #ifndef FEAT_GUI_W32
5279 * Start termcap mode
5282 termcap_mode_start(void)
5289 SaveConsoleBuffer(&g_cbNonTermcap);
5291 if (g_cbTermcap.IsValid)
5294 * We've been in termcap mode before. Restore certain screen
5295 * characteristics, including the buffer size and the window
5296 * size. Since we will be redrawing the screen, we don't need
5297 * to restore the actual contents of the buffer.
5299 RestoreConsoleBuffer(&g_cbTermcap, FALSE);
5300 SetConsoleWindowInfo(g_hConOut, TRUE, &g_cbTermcap.Info.srWindow);
5301 Rows = g_cbTermcap.Info.dwSize.Y;
5302 Columns = g_cbTermcap.Info.dwSize.X;
5307 * This is our first time entering termcap mode. Clear the console
5308 * screen buffer, and resize the buffer to match the current window
5309 * size. We will use this as the size of our editing environment.
5311 ClearConsoleBuffer(g_attrCurrent);
5312 ResizeConBufAndWindow(g_hConOut, Columns, Rows);
5319 GetConsoleMode(g_hConIn, &cmodein);
5322 cmodein |= ENABLE_MOUSE_INPUT;
5324 cmodein &= ~ENABLE_MOUSE_INPUT;
5326 cmodein |= ENABLE_WINDOW_INPUT;
5327 SetConsoleMode(g_hConIn, cmodein);
5329 redraw_later_clear();
5330 g_fTermcapMode = TRUE;
5338 termcap_mode_end(void)
5345 if (!g_fTermcapMode)
5348 SaveConsoleBuffer(&g_cbTermcap);
5350 GetConsoleMode(g_hConIn, &cmodein);
5351 cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
5352 SetConsoleMode(g_hConIn, cmodein);
5354 #ifdef FEAT_RESTORE_ORIG_SCREEN
5355 cb = exiting ? &g_cbOrig : &g_cbNonTermcap;
5357 cb = &g_cbNonTermcap;
5359 RestoreConsoleBuffer(cb, p_rs);
5360 SetConsoleCursorInfo(g_hConOut, &g_cci);
5362 if (p_rs || exiting)
5365 * Clear anything that happens to be on the current line.
5368 coord.Y = (SHORT) (p_rs ? cb->Info.dwCursorPosition.Y : (Rows - 1));
5369 FillConsoleOutputCharacter(g_hConOut, ' ',
5370 cb->Info.dwSize.X, coord, &dwDummy);
5372 * The following is just for aesthetics. If we are exiting without
5373 * restoring the screen, then we want to have a prompt string
5374 * appear at the bottom line. However, the command interpreter
5375 * seems to always advance the cursor one line before displaying
5376 * the prompt string, which causes the screen to scroll. To
5377 * counter this, move the cursor up one line before exiting.
5379 if (exiting && !p_rs)
5382 * Position the cursor at the leftmost column of the desired row.
5384 SetConsoleCursorPosition(g_hConOut, coord);
5387 g_fTermcapMode = FALSE;
5389 #endif /* FEAT_GUI_W32 */
5404 * clear `n' chars, starting from `coord'
5413 FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
5414 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy);
5424 g_coord.X = g_coord.Y = 0;
5425 clear_chars(g_coord, Rows * Columns);
5430 * Clear to end of display
5433 clear_to_end_of_display(void)
5435 clear_chars(g_coord, (Rows - g_coord.Y - 1)
5436 * Columns + (Columns - g_coord.X));
5441 * Clear to end of line
5444 clear_to_end_of_line(void)
5446 clear_chars(g_coord, Columns - g_coord.X);
5451 * Scroll the scroll region up by `cLines' lines
5454 scroll(unsigned cLines)
5456 COORD oldcoord = g_coord;
5458 gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Top + 1);
5459 delete_lines(cLines);
5466 * Set the scroll region
5477 || right > (unsigned) Columns - 1
5478 || bottom > (unsigned) Rows - 1)
5481 g_srScrollRegion.Left = left;
5482 g_srScrollRegion.Top = top;
5483 g_srScrollRegion.Right = right;
5484 g_srScrollRegion.Bottom = bottom;
5489 * Insert `cLines' lines at the current cursor position
5492 insert_lines(unsigned cLines)
5499 dest.Y = g_coord.Y + cLines;
5502 source.Top = g_coord.Y;
5503 source.Right = g_srScrollRegion.Right;
5504 source.Bottom = g_srScrollRegion.Bottom - cLines;
5506 fill.Char.AsciiChar = ' ';
5507 fill.Attributes = g_attrCurrent;
5509 ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
5511 /* Here we have to deal with a win32 console flake: If the scroll
5512 * region looks like abc and we scroll c to a and fill with d we get
5513 * cbd... if we scroll block c one line at a time to a, we get cdd...
5514 * vim expects cdd consistently... So we have to deal with that
5515 * here... (this also occurs scrolling the same way in the other
5518 if (source.Bottom < dest.Y)
5523 coord.Y = source.Bottom;
5524 clear_chars(coord, Columns * (dest.Y - source.Bottom));
5530 * Delete `cLines' lines at the current cursor position
5533 delete_lines(unsigned cLines)
5544 source.Top = g_coord.Y + cLines;
5545 source.Right = g_srScrollRegion.Right;
5546 source.Bottom = g_srScrollRegion.Bottom;
5548 fill.Char.AsciiChar = ' ';
5549 fill.Attributes = g_attrCurrent;
5551 ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
5553 /* Here we have to deal with a win32 console flake: If the scroll
5554 * region looks like abc and we scroll c to a and fill with d we get
5555 * cbd... if we scroll block c one line at a time to a, we get cdd...
5556 * vim expects cdd consistently... So we have to deal with that
5557 * here... (this also occurs scrolling the same way in the other
5560 nb = dest.Y + (source.Bottom - source.Top) + 1;
5562 if (nb < source.Top)
5568 clear_chars(coord, Columns * (source.Top - nb));
5574 * Set the cursor position
5581 if (x < 1 || x > (unsigned)Columns || y < 1 || y > (unsigned)Rows)
5584 /* external cursor coords are 1-based; internal are 0-based */
5587 SetConsoleCursorPosition(g_hConOut, g_coord);
5592 * Set the current text attribute = (foreground | background)
5593 * See ../doc/os_win32.txt for the numbers.
5596 textattr(WORD wAttr)
5598 g_attrCurrent = wAttr & 0xff;
5600 SetConsoleTextAttribute(g_hConOut, wAttr);
5605 textcolor(WORD wAttr)
5607 g_attrCurrent = (g_attrCurrent & 0xf0) + (wAttr & 0x0f);
5609 SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
5614 textbackground(WORD wAttr)
5616 g_attrCurrent = (g_attrCurrent & 0x0f) + ((wAttr & 0x0f) << 4);
5618 SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
5623 * restore the default text attribute (whatever we started with)
5628 textattr(g_attrDefault);
5632 static WORD g_attrPreStandout = 0;
5635 * Make the text standout, by brightening it
5640 g_attrPreStandout = g_attrCurrent;
5641 textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY));
5646 * Turn off standout mode
5651 if (g_attrPreStandout)
5653 textattr(g_attrPreStandout);
5654 g_attrPreStandout = 0;
5660 * Set normal fg/bg color, based on T_ME. Called when t_me has been set.
5663 mch_set_normal_colors(void)
5668 cterm_normal_fg_color = (g_attrDefault & 0xf) + 1;
5669 cterm_normal_bg_color = ((g_attrDefault >> 4) & 0xf) + 1;
5670 if (T_ME[0] == ESC && T_ME[1] == '|')
5674 if (*p == 'm' && n > 0)
5676 cterm_normal_fg_color = (n & 0xf) + 1;
5677 cterm_normal_bg_color = ((n >> 4) & 0xf) + 1;
5684 * visual bell: flash the screen
5689 COORD coordOrigin = {0, 0};
5690 WORD attrFlash = ~g_attrCurrent & 0xff;
5693 LPWORD oldattrs = (LPWORD)alloc(Rows * Columns * sizeof(WORD));
5695 if (oldattrs == NULL)
5697 ReadConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
5698 coordOrigin, &dwDummy);
5699 FillConsoleOutputAttribute(g_hConOut, attrFlash, Rows * Columns,
5700 coordOrigin, &dwDummy);
5702 Sleep(15); /* wait for 15 msec */
5703 WriteConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
5704 coordOrigin, &dwDummy);
5710 * Make the cursor visible or invisible
5713 cursor_visible(BOOL fVisible)
5715 s_cursor_visible = fVisible;
5716 #ifdef MCH_CURSOR_SHAPE
5717 mch_update_cursor();
5723 * write `cbToWrite' bytes in `pchBuf' to the screen
5724 * Returns the number of bytes actually written (at least one).
5731 COORD coord = g_coord;
5735 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
5737 static WCHAR *unicodebuf = NULL;
5738 static int unibuflen = 0;
5740 DWORD n, cchwritten, cells;
5742 length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0);
5743 if (unicodebuf == NULL || length > unibuflen)
5745 vim_free(unicodebuf);
5746 unicodebuf = (WCHAR *)lalloc(length * sizeof(WCHAR), FALSE);
5749 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite,
5750 unicodebuf, unibuflen);
5752 cells = mb_string2cells(pchBuf, cbToWrite);
5753 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells,
5755 /* When writing fails or didn't write a single character, pretend one
5756 * character was written, otherwise we get stuck. */
5757 if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length,
5758 coord, &cchwritten) == 0
5762 if (cchwritten == length)
5764 written = cbToWrite;
5765 g_coord.X += (SHORT)cells;
5770 for (n = 0; n < cchwritten; n++)
5772 written = p - pchBuf;
5773 g_coord.X += (SHORT)mb_string2cells(pchBuf, written);
5779 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite,
5781 /* When writing fails or didn't write a single character, pretend one
5782 * character was written, otherwise we get stuck. */
5783 if (WriteConsoleOutputCharacter(g_hConOut, (LPCSTR)pchBuf, cbToWrite,
5784 coord, &written) == 0
5788 g_coord.X += (SHORT) written;
5791 while (g_coord.X > g_srScrollRegion.Right)
5793 g_coord.X -= (SHORT) Columns;
5794 if (g_coord.Y < g_srScrollRegion.Bottom)
5798 gotoxy(g_coord.X + 1, g_coord.Y + 1);
5805 * mch_write(): write the output buffer to the screen, translating ESC
5806 * sequences into calls to console output routines.
5817 write(1, s, (unsigned)len);
5821 /* translate ESC | sequences into faked bios calls */
5824 /* optimization: use one single write_chars for runs of text,
5825 * rather than once per character It ain't curses, but it helps. */
5826 DWORD prefix = (DWORD)strcspn((char *)s, "\n\r\b\a\033");
5839 nWritten = write_chars(s, prefix);
5840 #ifdef MCH_WRITE_DUMP
5844 fwrite(s, sizeof(char_u), nWritten, fdDump);
5845 fputs("<\n", fdDump);
5848 len -= (nWritten - 1);
5851 else if (s[0] == '\n')
5853 /* \n, newline: go to the beginning of the next line or scroll */
5854 if (g_coord.Y == g_srScrollRegion.Bottom)
5857 gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Bottom + 1);
5861 gotoxy(g_srScrollRegion.Left + 1, g_coord.Y + 2);
5863 #ifdef MCH_WRITE_DUMP
5865 fputs("\\n\n", fdDump);
5869 else if (s[0] == '\r')
5871 /* \r, carriage return: go to beginning of line */
5872 gotoxy(g_srScrollRegion.Left+1, g_coord.Y + 1);
5873 #ifdef MCH_WRITE_DUMP
5875 fputs("\\r\n", fdDump);
5879 else if (s[0] == '\b')
5881 /* \b, backspace: move cursor one position left */
5882 if (g_coord.X > g_srScrollRegion.Left)
5884 else if (g_coord.Y > g_srScrollRegion.Top)
5886 g_coord.X = g_srScrollRegion.Right;
5889 gotoxy(g_coord.X + 1, g_coord.Y + 1);
5890 #ifdef MCH_WRITE_DUMP
5892 fputs("\\b\n", fdDump);
5896 else if (s[0] == '\a')
5899 MessageBeep(0xFFFFFFFF);
5900 #ifdef MCH_WRITE_DUMP
5902 fputs("\\a\n", fdDump);
5906 else if (s[0] == ESC && len >= 3-1 && s[1] == '|')
5908 #ifdef MCH_WRITE_DUMP
5912 int arg1 = 0, arg2 = 0;
5916 /* one or two numeric arguments, separated by ';' */
5918 case '0': case '1': case '2': case '3': case '4':
5919 case '5': case '6': case '7': case '8': case '9':
5921 arg1 = getdigits(&p); /* no check for length! */
5928 arg2 = getdigits(&p); /* no check for length! */
5935 set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1);
5939 /* move cursor up arg1 lines in same column */
5940 gotoxy(g_coord.X + 1,
5941 max(g_srScrollRegion.Top, g_coord.Y - arg1) + 1);
5945 /* move cursor right arg1 columns in same line */
5946 gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1,
5962 textattr((WORD) arg1);
5966 textcolor((WORD) arg1);
5970 textbackground((WORD) arg1);
5977 len -= (int)(p - s);
5982 /* Three-character escape sequences */
5985 /* move cursor up one line in same column */
5986 gotoxy(g_coord.X + 1,
5987 max(g_srScrollRegion.Top, g_coord.Y - 1) + 1);
5995 /* move cursor right one column in same line */
5996 gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1,
6017 clear_to_end_of_display();
6025 clear_to_end_of_line();
6037 termcap_mode_start();
6041 cursor_visible(TRUE);
6045 cursor_visible(FALSE);
6053 #ifdef MCH_WRITE_DUMP
6056 fputs("ESC | ", fdDump);
6057 fwrite(old_s + 2, sizeof(char_u), s - old_s - 2, fdDump);
6058 fputc('\n', fdDump);
6064 /* Write a single character */
6067 nWritten = write_chars(s, 1);
6068 #ifdef MCH_WRITE_DUMP
6072 fwrite(s, sizeof(char_u), nWritten, fdDump);
6073 fputs("<\n", fdDump);
6077 len -= (nWritten - 1);
6082 #ifdef MCH_WRITE_DUMP
6088 #endif /* FEAT_GUI_W32 */
6092 * Delay for "msec" milliseconds.
6097 int ignoreinput UNUSED)
6100 Sleep((int)msec); /* never wait for input */
6103 # ifdef FEAT_MZSCHEME
6104 if (mzthreads_allowed() && p_mzq > 0 && msec > p_mzq)
6108 /* if msec is large enough, wait by portions in p_mzq */
6111 mzvim_check_threads();
6128 * This version of remove is not scared by a readonly (backup) file.
6129 * This can also remove a symbolic link like Unix.
6130 * Return 0 for success, -1 for failure.
6133 mch_remove(char_u *name)
6141 * On Windows, deleting a directory's symbolic link is done by
6142 * RemoveDirectory(): mch_rmdir. It seems unnatural, but it is fact.
6144 if (mch_isdir(name) && mch_is_symbolic_link(name))
6145 return mch_rmdir(name);
6147 win32_setattrs(name, FILE_ATTRIBUTE_NORMAL);
6150 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6152 wn = enc_to_utf16(name, NULL);
6155 n = DeleteFileW(wn) ? 0 : -1;
6161 return DeleteFile((LPCSTR)name) ? 0 : -1;
6166 * Check for an "interrupt signal": CTRL-break or CTRL-C.
6169 mch_breakcheck(int force)
6171 #ifndef FEAT_GUI_W32 /* never used */
6172 if (g_fCtrlCPressed || g_fCBrkPressed)
6174 g_fCtrlCPressed = g_fCBrkPressed = FALSE;
6180 /* physical RAM to leave for the OS */
6181 #define WINNT_RESERVE_BYTES (256*1024*1024)
6184 * How much main memory in KiB that can be used by VIM.
6187 mch_total_mem(int special UNUSED)
6192 /* Need to use GlobalMemoryStatusEx() when there is more memory than
6193 * what fits in 32 bits. But it's not always available. */
6194 ms.dwLength = sizeof(MEMORYSTATUSEX);
6195 GlobalMemoryStatusEx(&ms);
6196 if (ms.ullAvailVirtual < ms.ullTotalPhys)
6198 /* Process address space fits in physical RAM, use all of it. */
6199 return (long_u)(ms.ullAvailVirtual / 1024);
6201 if (ms.ullTotalPhys <= WINNT_RESERVE_BYTES)
6203 /* Catch old NT box or perverse hardware setup. */
6204 return (long_u)((ms.ullTotalPhys / 2) / 1024);
6206 /* Use physical RAM less reserve for OS + data. */
6207 return (long_u)((ms.ullTotalPhys - WINNT_RESERVE_BYTES) / 1024);
6212 * Same code as below, but with wide functions and no comments.
6213 * Return 0 for success, non-zero for failure.
6216 mch_wrename(WCHAR *wold, WCHAR *wnew)
6220 WCHAR szTempFile[_MAX_PATH + 1];
6221 WCHAR szNewPath[_MAX_PATH + 1];
6225 for (i = 0; wold[i] != NUL; ++i)
6226 if ((wold[i] == '/' || wold[i] == '\\' || wold[i] == ':')
6227 && wold[i + 1] != 0)
6229 if ((int)(wold + i - p) < 8 || p[6] != '~')
6230 return (MoveFileW(wold, wnew) == 0);
6232 if (GetFullPathNameW(wnew, _MAX_PATH, szNewPath, &p) == 0 || p == NULL)
6236 if (GetTempFileNameW(szNewPath, L"VIM", 0, szTempFile) == 0)
6239 if (!DeleteFileW(szTempFile))
6242 if (!MoveFileW(wold, szTempFile))
6245 if ((hf = CreateFileW(wold, GENERIC_WRITE, 0, NULL, CREATE_NEW,
6246 FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
6248 if (!CloseHandle(hf))
6251 if (!MoveFileW(szTempFile, wnew))
6253 (void)MoveFileW(szTempFile, wold);
6257 DeleteFileW(szTempFile);
6259 if (!DeleteFileW(wold))
6268 * mch_rename() works around a bug in rename (aka MoveFile) in
6269 * Windows 95: rename("foo.bar", "foo.bar~") will generate a
6270 * file whose short file name is "FOO.BAR" (its long file name will
6271 * be correct: "foo.bar~"). Because a file can be accessed by
6272 * either its SFN or its LFN, "foo.bar" has effectively been
6273 * renamed to "foo.bar", which is not at all what was wanted. This
6274 * seems to happen only when renaming files with three-character
6275 * extensions by appending a suffix that does not include ".".
6276 * Windows NT gets it right, however, with an SFN of "FOO~1.BAR".
6278 * There is another problem, which isn't really a bug but isn't right either:
6279 * When renaming "abcdef~1.txt" to "abcdef~1.txt~", the short name can be
6280 * "abcdef~1.txt" again. This has been reported on Windows NT 4.0 with
6281 * service pack 6. Doesn't seem to happen on Windows 98.
6283 * Like rename(), returns 0 upon success, non-zero upon failure.
6284 * Should probably set errno appropriately when errors occur.
6288 const char *pszOldFile,
6289 const char *pszNewFile)
6291 char szTempFile[_MAX_PATH+1];
6292 char szNewPath[_MAX_PATH+1];
6300 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6302 wold = enc_to_utf16((char_u *)pszOldFile, NULL);
6303 wnew = enc_to_utf16((char_u *)pszNewFile, NULL);
6304 if (wold != NULL && wnew != NULL)
6305 retval = mch_wrename(wold, wnew);
6313 * No need to play tricks unless the file name contains a "~" as the
6314 * seventh character.
6316 pszFilePart = (char *)gettail((char_u *)pszOldFile);
6317 if (STRLEN(pszFilePart) < 8 || pszFilePart[6] != '~')
6318 return rename(pszOldFile, pszNewFile);
6320 /* Get base path of new file name. Undocumented feature: If pszNewFile is
6321 * a directory, no error is returned and pszFilePart will be NULL. */
6322 if (GetFullPathName(pszNewFile, _MAX_PATH, szNewPath, &pszFilePart) == 0
6323 || pszFilePart == NULL)
6327 /* Get (and create) a unique temporary file name in directory of new file */
6328 if (GetTempFileName(szNewPath, "VIM", 0, szTempFile) == 0)
6331 /* blow the temp file away */
6332 if (!DeleteFile(szTempFile))
6335 /* rename old file to the temp file */
6336 if (!MoveFile(pszOldFile, szTempFile))
6339 /* now create an empty file called pszOldFile; this prevents the operating
6340 * system using pszOldFile as an alias (SFN) if we're renaming within the
6341 * same directory. For example, we're editing a file called
6342 * filename.asc.txt by its SFN, filena~1.txt. If we rename filena~1.txt
6343 * to filena~1.txt~ (i.e., we're making a backup while writing it), the
6344 * SFN for filena~1.txt~ will be filena~1.txt, by default, which will
6345 * cause all sorts of problems later in buf_write(). So, we create an
6346 * empty file called filena~1.txt and the system will have to find some
6347 * other SFN for filena~1.txt~, such as filena~2.txt
6349 if ((hf = CreateFile(pszOldFile, GENERIC_WRITE, 0, NULL, CREATE_NEW,
6350 FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
6352 if (!CloseHandle(hf))
6355 /* rename the temp file to the new file */
6356 if (!MoveFile(szTempFile, pszNewFile))
6358 /* Renaming failed. Rename the file back to its old name, so that it
6359 * looks like nothing happened. */
6360 (void)MoveFile(szTempFile, pszOldFile);
6365 /* Seems to be left around on Novell filesystems */
6366 DeleteFile(szTempFile);
6368 /* finally, remove the empty old file */
6369 if (!DeleteFile(pszOldFile))
6372 return 0; /* success */
6376 * Get the default shell for the current hardware platform
6387 * mch_access() extends access() to do more detailed check on network drives.
6388 * Returns 0 if file "n" has access rights according to "p", -1 otherwise.
6391 mch_access(char *n, int p)
6395 int retval = -1; /* default: fail */
6399 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6400 wn = enc_to_utf16((char_u *)n, NULL);
6403 if (mch_isdir((char_u *)n))
6405 char TempName[_MAX_PATH + 16] = "";
6407 WCHAR TempNameW[_MAX_PATH + 16] = L"";
6412 /* Read check is performed by seeing if we can do a find file on
6413 * the directory for any file. */
6420 for (i = 0; i < _MAX_PATH && wn[i] != 0; ++i)
6421 TempNameW[i] = wn[i];
6422 if (TempNameW[i - 1] != '\\' && TempNameW[i - 1] != '/')
6423 TempNameW[i++] = '\\';
6424 TempNameW[i++] = '*';
6427 hFile = FindFirstFileW(TempNameW, &d);
6428 if (hFile == INVALID_HANDLE_VALUE)
6431 (void)FindClose(hFile);
6439 vim_strncpy((char_u *)TempName, (char_u *)n, _MAX_PATH);
6440 pch = TempName + STRLEN(TempName) - 1;
6441 if (*pch != '\\' && *pch != '/')
6446 hFile = FindFirstFile(TempName, &d);
6447 if (hFile == INVALID_HANDLE_VALUE)
6449 (void)FindClose(hFile);
6455 /* Trying to create a temporary file in the directory should catch
6456 * directories on read-only network shares. However, in
6457 * directories whose ACL allows writes but denies deletes will end
6458 * up keeping the temporary file :-(. */
6462 if (!GetTempFileNameW(wn, L"VIM", 0, TempNameW))
6465 DeleteFileW(TempNameW);
6470 if (!GetTempFileName(n, "VIM", 0, TempName))
6472 mch_remove((char_u *)TempName);
6478 /* Trying to open the file for the required access does ACL, read-only
6479 * network share, and file attribute checks. */
6480 am = ((p & W_OK) ? GENERIC_WRITE : 0)
6481 | ((p & R_OK) ? GENERIC_READ : 0);
6484 hFile = CreateFileW(wn, am, 0, NULL, OPEN_EXISTING, 0, NULL);
6487 hFile = CreateFile(n, am, 0, NULL, OPEN_EXISTING, 0, NULL);
6488 if (hFile == INVALID_HANDLE_VALUE)
6493 retval = 0; /* success */
6501 #if defined(FEAT_MBYTE) || defined(PROTO)
6503 * Version of open() that may use UTF-16 file name.
6506 mch_open(char *name, int flags, int mode)
6508 /* _wopen() does not work with Borland C 5.5: creates a read-only file. */
6509 # ifndef __BORLANDC__
6513 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6515 wn = enc_to_utf16((char_u *)name, NULL);
6518 f = _wopen(wn, flags, mode);
6525 /* open() can open a file which name is longer than _MAX_PATH bytes
6526 * and shorter than _MAX_PATH characters successfully, but sometimes it
6527 * causes unexpected error in another part. We make it an error explicitly
6529 if (strlen(name) >= _MAX_PATH)
6532 return open(name, flags, mode);
6536 * Version of fopen() that may use UTF-16 file name.
6539 mch_fopen(char *name, char *mode)
6544 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6546 # if defined(DEBUG) && _MSC_VER >= 1400
6547 /* Work around an annoying assertion in the Microsoft debug CRT
6548 * when mode's text/binary setting doesn't match _get_fmode(). */
6549 char newMode = mode[strlen(mode) - 1];
6552 _get_fmode(&oldMode);
6554 _set_fmode(_O_TEXT);
6555 else if (newMode == 'b')
6556 _set_fmode(_O_BINARY);
6558 wn = enc_to_utf16((char_u *)name, NULL);
6559 wm = enc_to_utf16((char_u *)mode, NULL);
6560 if (wn != NULL && wm != NULL)
6561 f = _wfopen(wn, wm);
6565 # if defined(DEBUG) && _MSC_VER >= 1400
6566 _set_fmode(oldMode);
6571 /* fopen() can open a file which name is longer than _MAX_PATH bytes
6572 * and shorter than _MAX_PATH characters successfully, but sometimes it
6573 * causes unexpected error in another part. We make it an error explicitly
6575 if (strlen(name) >= _MAX_PATH)
6578 return fopen(name, mode);
6584 * SUB STREAM (aka info stream) handling:
6586 * NTFS can have sub streams for each file. Normal contents of file is
6587 * stored in the main stream, and extra contents (author information and
6588 * title and so on) can be stored in sub stream. After Windows 2000, user
6589 * can access and store those informations in sub streams via explorer's
6590 * property menuitem in right click menu. Those informations in sub streams
6591 * were lost when copying only the main stream. So we have to copy sub
6594 * Incomplete explanation:
6595 * http://msdn.microsoft.com/library/en-us/dnw2k/html/ntfs5.asp
6596 * More useful info and an example:
6597 * http://www.sysinternals.com/ntw2k/source/misc.shtml#streams
6601 * Copy info stream data "substream". Read from the file with BackupRead(sh)
6602 * and write to stream "substream" of file "to".
6603 * Errors are ignored.
6606 copy_substream(HANDLE sh, void *context, WCHAR *to, WCHAR *substream, long len)
6611 to_name = malloc((wcslen(to) + wcslen(substream) + 1) * sizeof(WCHAR));
6612 wcscpy(to_name, to);
6613 wcscat(to_name, substream);
6615 hTo = CreateFileW(to_name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
6616 FILE_ATTRIBUTE_NORMAL, NULL);
6617 if (hTo != INVALID_HANDLE_VALUE)
6621 DWORD readcnt, written;
6624 /* Copy block of bytes at a time. Abort when something goes wrong. */
6625 for (done = 0; done < len; done += written)
6627 /* (size_t) cast for Borland C 5.5 */
6628 todo = (DWORD)((size_t)(len - done) > sizeof(buf) ? sizeof(buf)
6629 : (size_t)(len - done));
6630 if (!BackupRead(sh, (LPBYTE)buf, todo, &readcnt,
6631 FALSE, FALSE, context)
6633 || !WriteFile(hTo, buf, todo, &written, NULL)
6644 * Copy info streams from file "from" to file "to".
6647 copy_infostreams(char_u *from, char_u *to)
6652 WIN32_STREAM_ID sid;
6654 WCHAR streamname[_MAX_PATH];
6656 void *context = NULL;
6660 /* Convert the file names to wide characters. */
6661 fromw = enc_to_utf16(from, NULL);
6662 tow = enc_to_utf16(to, NULL);
6663 if (fromw != NULL && tow != NULL)
6665 /* Open the file for reading. */
6666 sh = CreateFileW(fromw, GENERIC_READ, FILE_SHARE_READ, NULL,
6667 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
6668 if (sh != INVALID_HANDLE_VALUE)
6670 /* Use BackupRead() to find the info streams. Repeat until we
6671 * have done them all.*/
6674 /* Get the header to find the length of the stream name. If
6675 * the "readcount" is zero we have done all info streams. */
6676 ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
6677 headersize = (int)((char *)&sid.cStreamName - (char *)&sid.dwStreamId);
6678 if (!BackupRead(sh, (LPBYTE)&sid, headersize,
6679 &readcount, FALSE, FALSE, &context)
6683 /* We only deal with streams that have a name. The normal
6684 * file data appears to be without a name, even though docs
6685 * suggest it is called "::$DATA". */
6686 if (sid.dwStreamNameSize > 0)
6688 /* Read the stream name. */
6689 if (!BackupRead(sh, (LPBYTE)streamname,
6690 sid.dwStreamNameSize,
6691 &readcount, FALSE, FALSE, &context))
6694 /* Copy an info stream with a name ":anything:$DATA".
6695 * Skip "::$DATA", it has no stream name (examples suggest
6696 * it might be used for the normal file contents).
6697 * Note that BackupRead() counts bytes, but the name is in
6698 * wide characters. */
6699 len = readcount / sizeof(WCHAR);
6700 streamname[len] = 0;
6701 if (len > 7 && wcsicmp(streamname + len - 6,
6704 streamname[len - 6] = 0;
6705 copy_substream(sh, &context, tow, streamname,
6706 (long)sid.Size.u.LowPart);
6710 /* Advance to the next stream. We might try seeking too far,
6711 * but BackupSeek() doesn't skip over stream borders, thus
6713 (void)BackupSeek(sh, sid.Size.u.LowPart, sid.Size.u.HighPart,
6714 &lo, &hi, &context);
6717 /* Clear the context. */
6718 (void)BackupRead(sh, NULL, 0, &readcount, TRUE, FALSE, &context);
6729 * Copy file attributes from file "from" to file "to".
6730 * For Windows NT and later we copy info streams.
6731 * Always returns zero, errors are ignored.
6734 mch_copy_file_attribute(char_u *from, char_u *to)
6737 /* File streams only work on Windows NT and later. */
6739 copy_infostreams(from, to);
6744 #if defined(MYRESETSTKOFLW) || defined(PROTO)
6746 * Recreate a destroyed stack guard page in win32.
6747 * Written by Benjamin Peterson.
6750 /* These magic numbers are from the MS header files */
6751 #define MIN_STACK_WINNT 2
6754 * This function does the same thing as _resetstkoflw(), which is only
6755 * available in DevStudio .net and later.
6756 * Returns 0 for failure, 1 for success.
6759 myresetstkoflw(void)
6764 BYTE *pLowestPossiblePage;
6765 MEMORY_BASIC_INFORMATION mbi;
6772 /* We need to know the system page size. */
6774 nPageSize = si.dwPageSize;
6776 /* ...and the current stack pointer */
6777 pStackPtr = (BYTE*)_alloca(1);
6779 /* ...and the base of the stack. */
6780 if (VirtualQuery(pStackPtr, &mbi, sizeof mbi) == 0)
6782 pStackBase = (BYTE*)mbi.AllocationBase;
6784 /* ...and the page thats min_stack_req pages away from stack base; this is
6785 * the lowest page we could use. */
6786 pLowestPossiblePage = pStackBase + MIN_STACK_WINNT * nPageSize;
6789 /* We want the first committed page in the stack Start at the stack
6790 * base and move forward through memory until we find a committed block.
6792 BYTE *pBlock = pStackBase;
6796 if (VirtualQuery(pBlock, &mbi, sizeof mbi) == 0)
6799 pBlock += mbi.RegionSize;
6801 if (mbi.State & MEM_COMMIT)
6805 /* mbi now describes the first committed block in the stack. */
6806 if (mbi.Protect & PAGE_GUARD)
6809 /* decide where the guard page should start */
6810 if ((long_u)(mbi.BaseAddress) < (long_u)pLowestPossiblePage)
6811 pGuardPage = pLowestPossiblePage;
6813 pGuardPage = (BYTE*)mbi.BaseAddress;
6815 /* allocate the guard page */
6816 if (!VirtualAlloc(pGuardPage, nPageSize, MEM_COMMIT, PAGE_READWRITE))
6819 /* apply the guard attribute to the page */
6820 if (!VirtualProtect(pGuardPage, nPageSize, PAGE_READWRITE | PAGE_GUARD,
6830 #if defined(FEAT_MBYTE) || defined(PROTO)
6832 * The command line arguments in UCS2
6834 static int nArgsW = 0;
6835 static LPWSTR *ArglistW = NULL;
6836 static int global_argc = 0;
6837 static char **global_argv;
6839 static int used_file_argc = 0; /* last argument in global_argv[] used
6840 for the argument list. */
6841 static int *used_file_indexes = NULL; /* indexes in global_argv[] for
6842 command line arguments added to
6843 the argument list */
6844 static int used_file_count = 0; /* nr of entries in used_file_indexes */
6845 static int used_file_literal = FALSE; /* take file names literally */
6846 static int used_file_full_path = FALSE; /* file name was full path */
6847 static int used_file_diff_mode = FALSE; /* file name was with diff mode */
6848 static int used_alist_count = 0;
6852 * Get the command line arguments. Unicode version.
6853 * Returns argc. Zero when something fails.
6856 get_cmd_argsW(char ***argvp)
6863 ArglistW = CommandLineToArgvW(GetCommandLineW(), &nArgsW);
6864 if (ArglistW != NULL)
6866 argv = malloc((nArgsW + 1) * sizeof(char *));
6871 for (i = 0; i < argc; ++i)
6875 /* Convert each Unicode argument to the current codepage. */
6876 WideCharToMultiByte_alloc(GetACP(), 0,
6877 ArglistW[i], (int)wcslen(ArglistW[i]) + 1,
6878 (LPSTR *)&argv[i], &len, 0, 0);
6879 if (argv[i] == NULL)
6881 /* Out of memory, clear everything. */
6896 if (used_file_indexes != NULL)
6897 free(used_file_indexes);
6898 used_file_indexes = malloc(argc * sizeof(int));
6907 free_cmd_argsW(void)
6909 if (ArglistW != NULL)
6911 GlobalFree(ArglistW);
6917 * Remember "name" is an argument that was added to the argument list.
6918 * This avoids that we have to re-parse the argument list when fix_arg_enc()
6922 used_file_arg(char *name, int literal, int full_path, int diff_mode)
6926 if (used_file_indexes == NULL)
6928 for (i = used_file_argc + 1; i < global_argc; ++i)
6929 if (STRCMP(global_argv[i], name) == 0)
6932 used_file_indexes[used_file_count++] = i;
6935 used_file_literal = literal;
6936 used_file_full_path = full_path;
6937 used_file_diff_mode = diff_mode;
6941 * Remember the length of the argument list as it was. If it changes then we
6942 * leave it alone when 'encoding' is set.
6945 set_alist_count(void)
6947 used_alist_count = GARGCOUNT;
6951 * Fix the encoding of the command line arguments. Invoked when 'encoding'
6952 * has been changed while starting up. Use the UCS-2 command line arguments
6953 * and convert them to 'encoding'.
6964 * - if argument count differs between the wide and non-wide argument
6965 * list, something must be wrong.
6966 * - the file name arguments must have been located.
6967 * - the length of the argument list wasn't changed by the user.
6969 if (global_argc != nArgsW
6971 || used_file_indexes == NULL
6972 || used_file_count == 0
6973 || used_alist_count != GARGCOUNT)
6976 /* Remember the buffer numbers for the arguments. */
6977 fnum_list = (int *)alloc((int)sizeof(int) * GARGCOUNT);
6978 if (fnum_list == NULL)
6979 return; /* out of memory */
6980 for (i = 0; i < GARGCOUNT; ++i)
6981 fnum_list[i] = GARGLIST[i].ae_fnum;
6983 /* Clear the argument list. Make room for the new arguments. */
6984 alist_clear(&global_alist);
6985 if (ga_grow(&global_alist.al_ga, used_file_count) == FAIL)
6986 return; /* out of memory */
6988 for (i = 0; i < used_file_count; ++i)
6990 idx = used_file_indexes[i];
6991 str = utf16_to_enc(ArglistW[idx], NULL);
6995 /* When using diff mode may need to concatenate file name to
6996 * directory name. Just like it's done in main(). */
6997 if (used_file_diff_mode && mch_isdir(str) && GARGCOUNT > 0
6998 && !mch_isdir(alist_name(&GARGLIST[0])))
7002 r = concat_fnames(str, gettail(alist_name(&GARGLIST[0])), TRUE);
7010 /* Re-use the old buffer by renaming it. When not using literal
7011 * names it's done by alist_expand() below. */
7012 if (used_file_literal)
7013 buf_set_name(fnum_list[i], str);
7015 alist_add(&global_alist, str, used_file_literal ? 2 : 0);
7019 if (!used_file_literal)
7021 /* Now expand wildcards in the arguments. */
7022 /* Temporarily add '(' and ')' to 'isfname'. These are valid
7023 * filename characters but are excluded from 'isfname' to make
7024 * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
7025 do_cmdline_cmd((char_u *)":let SaVe_ISF = &isf|set isf+=(,)");
7026 alist_expand(fnum_list, used_alist_count);
7027 do_cmdline_cmd((char_u *)":let &isf = SaVe_ISF|unlet SaVe_ISF");
7030 /* If wildcard expansion failed, we are editing the first file of the
7031 * arglist and there is no file name: Edit the first argument now. */
7032 if (curwin->w_arg_idx == 0 && curbuf->b_fname == NULL)
7034 do_cmdline_cmd((char_u *)":rewind");
7035 if (GARGCOUNT == 1 && used_file_full_path)
7036 (void)vim_chdirfile(alist_name(&GARGLIST[0]));
7044 mch_setenv(char *var, char *value, int x)
7048 envbuf = alloc((unsigned)(STRLEN(var) + STRLEN(value) + 2));
7052 sprintf((char *)envbuf, "%s=%s", var, value);
7055 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
7057 WCHAR *p = enc_to_utf16(envbuf, NULL);
7063 # ifdef libintl_wputenv
7066 /* Unlike Un*x systems, we can free the string for _wputenv(). */
7072 _putenv((char *)envbuf);
7073 # ifdef libintl_putenv
7074 libintl_putenv((char *)envbuf);
7076 /* Unlike Un*x systems, we can free the string for _putenv(). */