Imported Upstream version 8.0.586
[platform/upstream/vim.git] / src / os_win32.c
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved    by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 /*
10  * os_win32.c
11  *
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".
14  *
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.
18  *
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.
21  */
22
23 #include "vim.h"
24
25 #ifdef FEAT_MZSCHEME
26 # include "if_mzsch.h"
27 #endif
28
29 #include <sys/types.h>
30 #include <signal.h>
31 #include <limits.h>
32
33 /* cproto fails on missing include files */
34 #ifndef PROTO
35 # include <process.h>
36 #endif
37
38 #undef chdir
39 #ifdef __GNUC__
40 # ifndef __MINGW32__
41 #  include <dirent.h>
42 # endif
43 #else
44 # include <direct.h>
45 #endif
46
47 #ifndef PROTO
48 # if defined(FEAT_TITLE) && !defined(FEAT_GUI_W32)
49 #  include <shellapi.h>
50 # endif
51 #endif
52
53 #ifdef FEAT_JOB_CHANNEL
54 # include <tlhelp32.h>
55 #endif
56
57 #ifdef __MINGW32__
58 # ifndef FROM_LEFT_1ST_BUTTON_PRESSED
59 #  define FROM_LEFT_1ST_BUTTON_PRESSED    0x0001
60 # endif
61 # ifndef RIGHTMOST_BUTTON_PRESSED
62 #  define RIGHTMOST_BUTTON_PRESSED        0x0002
63 # endif
64 # ifndef FROM_LEFT_2ND_BUTTON_PRESSED
65 #  define FROM_LEFT_2ND_BUTTON_PRESSED    0x0004
66 # endif
67 # ifndef FROM_LEFT_3RD_BUTTON_PRESSED
68 #  define FROM_LEFT_3RD_BUTTON_PRESSED    0x0008
69 # endif
70 # ifndef FROM_LEFT_4TH_BUTTON_PRESSED
71 #  define FROM_LEFT_4TH_BUTTON_PRESSED    0x0010
72 # endif
73
74 /*
75  * EventFlags
76  */
77 # ifndef MOUSE_MOVED
78 #  define MOUSE_MOVED   0x0001
79 # endif
80 # ifndef DOUBLE_CLICK
81 #  define DOUBLE_CLICK  0x0002
82 # endif
83 #endif
84
85 /* Record all output and all keyboard & mouse input */
86 /* #define MCH_WRITE_DUMP */
87
88 #ifdef MCH_WRITE_DUMP
89 FILE* fdDump = NULL;
90 #endif
91
92 /*
93  * When generating prototypes for Win32 on Unix, these lines make the syntax
94  * errors disappear.  They do not need to be correct.
95  */
96 #ifdef PROTO
97 #define WINAPI
98 typedef char * LPCSTR;
99 typedef char * LPWSTR;
100 typedef int ACCESS_MASK;
101 typedef int BOOL;
102 typedef int COLORREF;
103 typedef int CONSOLE_CURSOR_INFO;
104 typedef int COORD;
105 typedef int DWORD;
106 typedef int HANDLE;
107 typedef int LPHANDLE;
108 typedef int HDC;
109 typedef int HFONT;
110 typedef int HICON;
111 typedef int HINSTANCE;
112 typedef int HWND;
113 typedef int INPUT_RECORD;
114 typedef int KEY_EVENT_RECORD;
115 typedef int LOGFONT;
116 typedef int LPBOOL;
117 typedef int LPCTSTR;
118 typedef int LPDWORD;
119 typedef int LPSTR;
120 typedef int LPTSTR;
121 typedef int LPVOID;
122 typedef int MOUSE_EVENT_RECORD;
123 typedef int PACL;
124 typedef int PDWORD;
125 typedef int PHANDLE;
126 typedef int PRINTDLG;
127 typedef int PSECURITY_DESCRIPTOR;
128 typedef int PSID;
129 typedef int SECURITY_INFORMATION;
130 typedef int SHORT;
131 typedef int SMALL_RECT;
132 typedef int TEXTMETRIC;
133 typedef int TOKEN_INFORMATION_CLASS;
134 typedef int TRUSTEE;
135 typedef int WORD;
136 typedef int WCHAR;
137 typedef void VOID;
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 */
146 #endif
147
148 #if defined(__BORLANDC__)
149 /* Strangely Borland uses a non-standard name. */
150 # define wcsicmp(a, b) wcscmpi((a), (b))
151 #endif
152
153 #ifndef FEAT_GUI_W32
154 /* Win32 Console handles for input and output */
155 static HANDLE g_hConIn  = INVALID_HANDLE_VALUE;
156 static HANDLE g_hConOut = INVALID_HANDLE_VALUE;
157
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 */
161
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;
165
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 */
169
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;
194 #else
195 static int s_dont_use_vimrun = TRUE;
196 static int need_vimrun_warning = FALSE;
197 static char *vimrun_path = "vimrun ";
198 #endif
199
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);
203
204 #ifndef FEAT_GUI_W32
205 static int suppress_winsize = 1;        /* don't fiddle with console */
206 #endif
207
208 static char_u *exe_path = NULL;
209
210 static BOOL win8_or_later = FALSE;
211
212 #ifndef FEAT_GUI_W32
213 /*
214  * Version of ReadConsoleInput() that works with IME.
215  * Works around problems on Windows 8.
216  */
217     static BOOL
218 read_console_input(
219     HANDLE          hInput,
220     INPUT_RECORD    *lpBuffer,
221     DWORD           nLength,
222     LPDWORD         lpEvents)
223 {
224     enum
225     {
226         IRSIZE = 10
227     };
228     static INPUT_RECORD s_irCache[IRSIZE];
229     static DWORD s_dwIndex = 0;
230     static DWORD s_dwMax = 0;
231     DWORD dwEvents;
232     int head;
233     int tail;
234     int i;
235
236     if (nLength == -2)
237         return (s_dwMax > 0) ? TRUE : FALSE;
238
239     if (!win8_or_later)
240     {
241         if (nLength == -1)
242             return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
243         return ReadConsoleInputW(hInput, lpBuffer, 1, &dwEvents);
244     }
245
246     if (s_dwMax == 0)
247     {
248         if (nLength == -1)
249             return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
250         if (!ReadConsoleInputW(hInput, s_irCache, IRSIZE, &dwEvents))
251             return FALSE;
252         s_dwIndex = 0;
253         s_dwMax = dwEvents;
254         if (dwEvents == 0)
255         {
256             *lpEvents = 0;
257             return TRUE;
258         }
259
260         if (s_dwMax > 1)
261         {
262             head = 0;
263             tail = s_dwMax - 1;
264             while (head != tail)
265             {
266                 if (s_irCache[head].EventType == WINDOW_BUFFER_SIZE_EVENT
267                         && s_irCache[head + 1].EventType
268                                                   == WINDOW_BUFFER_SIZE_EVENT)
269                 {
270                     /* Remove duplicate event to avoid flicker. */
271                     for (i = head; i < tail; ++i)
272                         s_irCache[i] = s_irCache[i + 1];
273                     --tail;
274                     continue;
275                 }
276                 head++;
277             }
278             s_dwMax = tail + 1;
279         }
280     }
281
282     *lpBuffer = s_irCache[s_dwIndex];
283     if (!(nLength == -1 || nLength == -2) && ++s_dwIndex >= s_dwMax)
284         s_dwMax = 0;
285     *lpEvents = 1;
286     return TRUE;
287 }
288
289 /*
290  * Version of PeekConsoleInput() that works with IME.
291  */
292     static BOOL
293 peek_console_input(
294     HANDLE          hInput,
295     INPUT_RECORD    *lpBuffer,
296     DWORD           nLength,
297     LPDWORD         lpEvents)
298 {
299     return read_console_input(hInput, lpBuffer, -1, lpEvents);
300 }
301
302 # ifdef FEAT_CLIENTSERVER
303     static DWORD
304 msg_wait_for_multiple_objects(
305     DWORD    nCount,
306     LPHANDLE pHandles,
307     BOOL     fWaitAll,
308     DWORD    dwMilliseconds,
309     DWORD    dwWakeMask)
310 {
311     if (read_console_input(NULL, NULL, -2, NULL))
312         return WAIT_OBJECT_0;
313     return MsgWaitForMultipleObjects(nCount, pHandles, fWaitAll,
314                                      dwMilliseconds, dwWakeMask);
315 }
316 # endif
317
318 # ifndef FEAT_CLIENTSERVER
319     static DWORD
320 wait_for_single_object(
321     HANDLE hHandle,
322     DWORD dwMilliseconds)
323 {
324     if (read_console_input(NULL, NULL, -2, NULL))
325         return WAIT_OBJECT_0;
326     return WaitForSingleObject(hHandle, dwMilliseconds);
327 }
328 # endif
329 #endif
330
331     static void
332 get_exe_name(void)
333 {
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];
338     char_u      *p;
339
340     if (exe_name == NULL)
341     {
342         /* store the name of the executable, may be used for $VIM */
343         GetModuleFileName(NULL, temp, MAX_ENV_PATH_LEN - 1);
344         if (*temp != NUL)
345             exe_name = FullName_save((char_u *)temp, FALSE);
346     }
347
348     if (exe_path == NULL && exe_name != NULL)
349     {
350         exe_path = vim_strnsave(exe_name,
351                                      (int)(gettail_sep(exe_name) - exe_name));
352         if (exe_path != NULL)
353         {
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");
358             if (p == NULL
359                        || STRLEN(p) + STRLEN(exe_path) + 2 < MAX_ENV_PATH_LEN)
360             {
361                 if (p == NULL || *p == NUL)
362                     temp[0] = NUL;
363                 else
364                 {
365                     STRCPY(temp, p);
366                     STRCAT(temp, ";");
367                 }
368                 STRCAT(temp, exe_path);
369                 vim_setenv((char_u *)"PATH", (char_u *)temp);
370             }
371         }
372     }
373 }
374
375 /*
376  * Unescape characters in "p" that appear in "escaped".
377  */
378     static void
379 unescape_shellxquote(char_u *p, char_u *escaped)
380 {
381     int     l = (int)STRLEN(p);
382     int     n;
383
384     while (*p != NUL)
385     {
386         if (*p == '^' && vim_strchr(escaped, p[1]) != NULL)
387             mch_memmove(p, p + 1, l--);
388 #ifdef FEAT_MBYTE
389         n = (*mb_ptr2len)(p);
390 #else
391         n = 1;
392 #endif
393         p += n;
394         l -= n;
395     }
396 }
397
398 /*
399  * Load library "name".
400  */
401     HINSTANCE
402 vimLoadLib(char *name)
403 {
404     HINSTANCE   dll = NULL;
405
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)
409         get_exe_name();
410     if (exe_path != NULL)
411     {
412         WCHAR old_dirw[MAXPATHL];
413
414         if (GetCurrentDirectoryW(MAXPATHL, old_dirw) != 0)
415         {
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);
422             return dll;
423         }
424     }
425     return dll;
426 }
427
428 #if defined(DYNAMIC_ICONV) || defined(DYNAMIC_GETTEXT) || defined(PROTO)
429 /*
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.
433  */
434     static void *
435 get_imported_func_info(HINSTANCE hInst, const char *funcname, int info)
436 {
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;
444
445     if (pDOS->e_magic != IMAGE_DOS_SIGNATURE)
446         return NULL;
447     pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew);
448     if (pPE->Signature != IMAGE_NT_SIGNATURE)
449         return NULL;
450     pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage
451             + pPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
452                                                             .VirtualAddress);
453     for (; pImpDesc->FirstThunk; ++pImpDesc)
454     {
455         if (!pImpDesc->OriginalFirstThunk)
456             continue;
457         pIAT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->FirstThunk);
458         pINT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->OriginalFirstThunk);
459         for (; pIAT->u1.Function; ++pIAT, ++pINT)
460         {
461             if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))
462                 continue;
463             pImpName = (PIMAGE_IMPORT_BY_NAME)(pImage
464                                         + (UINT_PTR)(pINT->u1.AddressOfData));
465             if (strcmp((char *)pImpName->Name, funcname) == 0)
466             {
467                 switch (info)
468                 {
469                     case 0:
470                         return (void *)pIAT->u1.Function;
471                     case 1:
472                         return (void *)(pImage + pImpDesc->Name);
473                     default:
474                         return NULL;
475                 }
476             }
477         }
478     }
479     return NULL;
480 }
481
482 /*
483  * Get the module handle which 'funcname' in 'hInst' is imported from.
484  */
485     HINSTANCE
486 find_imported_module_by_funcname(HINSTANCE hInst, const char *funcname)
487 {
488     char    *modulename;
489
490     modulename = (char *)get_imported_func_info(hInst, funcname, 1);
491     if (modulename != NULL)
492         return GetModuleHandleA(modulename);
493     return NULL;
494 }
495
496 /*
497  * Get the address of 'funcname' which is imported by 'hInst' DLL.
498  */
499     void *
500 get_dll_import_func(HINSTANCE hInst, const char *funcname)
501 {
502     return get_imported_func_info(hInst, funcname, 0);
503 }
504 #endif
505
506 #if defined(DYNAMIC_GETTEXT) || defined(PROTO)
507 # ifndef GETTEXT_DLL
508 #  define GETTEXT_DLL "libintl.dll"
509 #  define GETTEXT_DLL_ALT "libintl-8.dll"
510 # endif
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 *);
519
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;
531
532     int
533 dyn_libintl_init(void)
534 {
535     int i;
536     static struct
537     {
538         char        *name;
539         FARPROC     *ptr;
540     } libintl_entry[] =
541     {
542         {"gettext", (FARPROC*)&dyn_libintl_gettext},
543         {"ngettext", (FARPROC*)&dyn_libintl_ngettext},
544         {"textdomain", (FARPROC*)&dyn_libintl_textdomain},
545         {"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain},
546         {NULL, NULL}
547     };
548     HINSTANCE hmsvcrt;
549
550     /* No need to initialize twice. */
551     if (hLibintlDLL)
552         return 1;
553     /* Load gettext library (libintl.dll) */
554     hLibintlDLL = vimLoadLib(GETTEXT_DLL);
555 #ifdef GETTEXT_DLL_ALT
556     if (!hLibintlDLL)
557         hLibintlDLL = vimLoadLib(GETTEXT_DLL_ALT);
558 #endif
559     if (!hLibintlDLL)
560     {
561         if (p_verbose > 0)
562         {
563             verbose_enter();
564             EMSG2(_(e_loadlib), GETTEXT_DLL);
565             verbose_leave();
566         }
567         return 0;
568     }
569     for (i = 0; libintl_entry[i].name != NULL
570                                          && libintl_entry[i].ptr != NULL; ++i)
571     {
572         if ((*libintl_entry[i].ptr = (FARPROC)GetProcAddress(hLibintlDLL,
573                                               libintl_entry[i].name)) == NULL)
574         {
575             dyn_libintl_end();
576             if (p_verbose > 0)
577             {
578                 verbose_enter();
579                 EMSG2(_(e_loadfunc), libintl_entry[i].name);
580                 verbose_leave();
581             }
582             return 0;
583         }
584     }
585
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;
592
593     /* _putenv() function for the libintl.dll is optional. */
594     hmsvcrt = find_imported_module_by_funcname(hLibintlDLL, "getenv");
595     if (hmsvcrt != NULL)
596     {
597         dyn_libintl_putenv = (void *)GetProcAddress(hmsvcrt, "_putenv");
598         dyn_libintl_wputenv = (void *)GetProcAddress(hmsvcrt, "_wputenv");
599     }
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;
604
605     return 1;
606 }
607
608     void
609 dyn_libintl_end(void)
610 {
611     if (hLibintlDLL)
612         FreeLibrary(hLibintlDLL);
613     hLibintlDLL                 = NULL;
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;
621 }
622
623     static char *
624 null_libintl_gettext(const char *msgid)
625 {
626     return (char*)msgid;
627 }
628
629     static char *
630 null_libintl_ngettext(
631         const char *msgid,
632         const char *msgid_plural,
633         unsigned long n)
634 {
635     return (char *)(n == 1 ? msgid : msgid_plural);
636 }
637
638     static char *
639 null_libintl_bindtextdomain(
640         const char *domainname UNUSED,
641         const char *dirname UNUSED)
642 {
643     return NULL;
644 }
645
646     static char *
647 null_libintl_bind_textdomain_codeset(
648         const char *domainname UNUSED,
649         const char *codeset UNUSED)
650 {
651     return NULL;
652 }
653
654     static char *
655 null_libintl_textdomain(const char *domainname UNUSED)
656 {
657     return NULL;
658 }
659
660     int
661 null_libintl_putenv(const char *envstring UNUSED)
662 {
663     return 0;
664 }
665
666     int
667 null_libintl_wputenv(const wchar_t *envstring UNUSED)
668 {
669     return 0;
670 }
671
672 #endif /* DYNAMIC_GETTEXT */
673
674 /* This symbol is not defined in older versions of the SDK or Visual C++ */
675
676 #ifndef VER_PLATFORM_WIN32_WINDOWS
677 # define VER_PLATFORM_WIN32_WINDOWS 1
678 #endif
679
680 DWORD g_PlatformId;
681
682 #ifdef HAVE_ACL
683 # ifndef PROTO
684 #  include <aclapi.h>
685 # endif
686 # ifndef PROTECTED_DACL_SECURITY_INFORMATION
687 #  define PROTECTED_DACL_SECURITY_INFORMATION   0x80000000L
688 # endif
689 #endif
690
691 #ifdef HAVE_ACL
692 /*
693  * Enables or disables the specified privilege.
694  */
695     static BOOL
696 win32_enable_privilege(LPTSTR lpszPrivilege, BOOL bEnable)
697 {
698     BOOL                bResult;
699     LUID                luid;
700     HANDLE              hToken;
701     TOKEN_PRIVILEGES    tokenPrivileges;
702
703     if (!OpenProcessToken(GetCurrentProcess(),
704                 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
705         return FALSE;
706
707     if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
708     {
709         CloseHandle(hToken);
710         return FALSE;
711     }
712
713     tokenPrivileges.PrivilegeCount           = 1;
714     tokenPrivileges.Privileges[0].Luid       = luid;
715     tokenPrivileges.Privileges[0].Attributes = bEnable ?
716                                                     SE_PRIVILEGE_ENABLED : 0;
717
718     bResult = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges,
719             sizeof(TOKEN_PRIVILEGES), NULL, NULL);
720
721     CloseHandle(hToken);
722
723     return bResult && GetLastError() == ERROR_SUCCESS;
724 }
725 #endif
726
727 /*
728  * Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
729  * VER_PLATFORM_WIN32_WINDOWS (Win95).
730  */
731     void
732 PlatformId(void)
733 {
734     static int done = FALSE;
735
736     if (!done)
737     {
738         OSVERSIONINFO ovi;
739
740         ovi.dwOSVersionInfoSize = sizeof(ovi);
741         GetVersionEx(&ovi);
742
743         g_PlatformId = ovi.dwPlatformId;
744
745         if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2)
746                 || ovi.dwMajorVersion > 6)
747             win8_or_later = TRUE;
748
749 #ifdef HAVE_ACL
750         /* Enable privilege for getting or setting SACLs. */
751         win32_enable_privilege(SE_SECURITY_NAME, TRUE);
752 #endif
753         done = TRUE;
754     }
755 }
756
757 #ifndef FEAT_GUI_W32
758
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)
763
764
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.
771  */
772
773 static const struct
774 {
775     WORD    wVirtKey;
776     BOOL    fAnsiKey;
777     int     chAlone;
778     int     chShift;
779     int     chCtrl;
780     int     chAlt;
781 } VirtKeyMap[] =
782 {
783
784 /*    Key       ANSI    alone   shift   ctrl        alt */
785     { VK_ESCAPE,FALSE,  ESC,    ESC,    ESC,        ESC,    },
786
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', },
799
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', },
810
811     { VK_SNAPSHOT,TRUE, 0,      0,      0,          'r', }, /*PrtScrn*/
812
813 #if 0
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', },
823 #endif
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 '*' */
828
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', },
840
841 };
842
843
844 #ifdef _MSC_VER
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)
850 #endif
851
852 #if defined(__GNUC__) && !defined(__MINGW32__)  && !defined(__CYGWIN__)
853 # define UChar UnicodeChar
854 #else
855 # define UChar uChar.UnicodeChar
856 #endif
857
858 /* The return code indicates key code size. */
859     static int
860 #ifdef __BORLANDC__
861     __stdcall
862 #endif
863 win32_kbd_patch_key(
864     KEY_EVENT_RECORD *pker)
865 {
866     UINT uMods = pker->dwControlKeyState;
867     static int s_iIsDead = 0;
868     static WORD awAnsiCode[2];
869     static BYTE abKeystate[256];
870
871
872     if (s_iIsDead == 2)
873     {
874         pker->UChar = (WCHAR) awAnsiCode[1];
875         s_iIsDead = 0;
876         return 1;
877     }
878
879     if (pker->UChar != 0)
880         return 1;
881
882     vim_memset(abKeystate, 0, sizeof (abKeystate));
883
884     /* Clear any pending dead keys */
885     ToUnicode(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 2, 0);
886
887     if (uMods & SHIFT_PRESSED)
888         abKeystate[VK_SHIFT] = 0x80;
889     if (uMods & CAPSLOCK_ON)
890         abKeystate[VK_CAPITAL] = 1;
891
892     if ((uMods & ALT_GR) == ALT_GR)
893     {
894         abKeystate[VK_CONTROL] = abKeystate[VK_LCONTROL] =
895             abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80;
896     }
897
898     s_iIsDead = ToUnicode(pker->wVirtualKeyCode, pker->wVirtualScanCode,
899                         abKeystate, awAnsiCode, 2, 0);
900
901     if (s_iIsDead > 0)
902         pker->UChar = (WCHAR) awAnsiCode[0];
903
904     return s_iIsDead;
905 }
906
907 #ifdef _MSC_VER
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)
912
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)
918 # endif
919 #endif
920
921 static BOOL g_fJustGotFocus = FALSE;
922
923 /*
924  * Decode a KEY_EVENT into one or two keystrokes
925  */
926     static BOOL
927 decode_key_event(
928     KEY_EVENT_RECORD    *pker,
929     WCHAR               *pch,
930     WCHAR               *pch2,
931     int                 *pmodifiers,
932     BOOL                fDoPost)
933 {
934     int i;
935     const int nModifs = pker->dwControlKeyState & (SHIFT | ALT | CTRL);
936
937     *pch = *pch2 = NUL;
938     g_fJustGotFocus = FALSE;
939
940     /* ignore key up events */
941     if (!pker->bKeyDown)
942         return FALSE;
943
944     /* ignore some keystrokes */
945     switch (pker->wVirtualKeyCode)
946     {
947     /* modifiers */
948     case VK_SHIFT:
949     case VK_CONTROL:
950     case VK_MENU:   /* Alt key */
951         return FALSE;
952
953     default:
954         break;
955     }
956
957     /* special cases */
958     if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 && pker->UChar == NUL)
959     {
960         /* Ctrl-6 is Ctrl-^ */
961         if (pker->wVirtualKeyCode == '6')
962         {
963             *pch = Ctrl_HAT;
964             return TRUE;
965         }
966         /* Ctrl-2 is Ctrl-@ */
967         else if (pker->wVirtualKeyCode == '2')
968         {
969             *pch = NUL;
970             return TRUE;
971         }
972         /* Ctrl-- is Ctrl-_ */
973         else if (pker->wVirtualKeyCode == 0xBD)
974         {
975             *pch = Ctrl__;
976             return TRUE;
977         }
978     }
979
980     /* Shift-TAB */
981     if (pker->wVirtualKeyCode == VK_TAB && (nModifs & SHIFT_PRESSED))
982     {
983         *pch = K_NUL;
984         *pch2 = '\017';
985         return TRUE;
986     }
987
988     for (i = sizeof(VirtKeyMap) / sizeof(VirtKeyMap[0]);  --i >= 0;  )
989     {
990         if (VirtKeyMap[i].wVirtKey == pker->wVirtualKeyCode)
991         {
992             if (nModifs == 0)
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;
1000
1001             if (*pch != 0)
1002             {
1003                 if (VirtKeyMap[i].fAnsiKey)
1004                 {
1005                     *pch2 = *pch;
1006                     *pch = K_NUL;
1007                 }
1008
1009                 return TRUE;
1010             }
1011         }
1012     }
1013
1014     i = win32_kbd_patch_key(pker);
1015
1016     if (i < 0)
1017         *pch = NUL;
1018     else
1019     {
1020         *pch = (i > 0) ? pker->UChar : NUL;
1021
1022         if (pmodifiers != NULL)
1023         {
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;
1028
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;
1033
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;
1040         }
1041     }
1042
1043     return (*pch != NUL);
1044 }
1045
1046 #ifdef _MSC_VER
1047 # pragma optimize("", on)
1048 #endif
1049
1050 #endif /* FEAT_GUI_W32 */
1051
1052
1053 #ifdef FEAT_MOUSE
1054
1055 /*
1056  * For the GUI the mouse handling is in gui_w32.c.
1057  */
1058 # ifdef FEAT_GUI_W32
1059     void
1060 mch_setmouse(int on UNUSED)
1061 {
1062 }
1063 # else
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 */
1069
1070 /*
1071  * Enable or disable mouse input
1072  */
1073     void
1074 mch_setmouse(int on)
1075 {
1076     DWORD cmodein;
1077
1078     if (!g_fMouseAvail)
1079         return;
1080
1081     g_fMouseActive = on;
1082     GetConsoleMode(g_hConIn, &cmodein);
1083
1084     if (g_fMouseActive)
1085         cmodein |= ENABLE_MOUSE_INPUT;
1086     else
1087         cmodein &= ~ENABLE_MOUSE_INPUT;
1088
1089     SetConsoleMode(g_hConIn, cmodein);
1090 }
1091
1092 /*
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.
1099  *
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.
1103  *
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, ....
1106  *
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).
1112  *
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.
1118  */
1119     static BOOL
1120 decode_mouse_event(
1121     MOUSE_EVENT_RECORD *pmer)
1122 {
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;
1128 #ifdef FEAT_DIFF
1129     static int s_old_topfill = 0;
1130 #endif
1131     static int s_cClicks = 1;
1132     static BOOL s_fReleased = TRUE;
1133     static DWORD s_dwLastClickTime = 0;
1134     static BOOL s_fNextIsMiddle = FALSE;
1135
1136     static DWORD cButtons = 0;  /* number of buttons supported */
1137
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;
1142
1143     int nButton;
1144
1145     if (cButtons == 0 && !GetNumberOfConsoleMouseButtons(&cButtons))
1146         cButtons = 2;
1147
1148     if (!g_fMouseAvail || !g_fMouseActive)
1149     {
1150         g_nMouseClick = -1;
1151         return FALSE;
1152     }
1153
1154     /* get a spurious MOUSE_EVENT immediately after receiving focus; ignore */
1155     if (g_fJustGotFocus)
1156     {
1157         g_fJustGotFocus = FALSE;
1158         return FALSE;
1159     }
1160
1161     /* unprocessed mouse click? */
1162     if (g_nMouseClick != -1)
1163         return TRUE;
1164
1165     nButton = -1;
1166     g_xMouse = pmer->dwMousePosition.X;
1167     g_yMouse = pmer->dwMousePosition.Y;
1168
1169     if (pmer->dwEventFlags == MOUSE_MOVED)
1170     {
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)
1174             return FALSE;
1175     }
1176
1177     /* If no buttons are pressed... */
1178     if ((pmer->dwButtonState & ((1 << cButtons) - 1)) == 0)
1179     {
1180         /* If the last thing returned was MOUSE_RELEASE, ignore this */
1181         if (s_fReleased)
1182             return FALSE;
1183
1184         nButton = MOUSE_RELEASE;
1185         s_fReleased = TRUE;
1186     }
1187     else    /* one or more buttons pressed */
1188     {
1189         /* on a 2-button mouse, hold down left and right buttons
1190          * simultaneously to get MIDDLE. */
1191
1192         if (cButtons == 2 && s_nOldButton != MOUSE_DRAG)
1193         {
1194             DWORD dwLR = (pmer->dwButtonState & LEFT_RIGHT);
1195
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)
1199             {
1200                 for (;;)
1201                 {
1202                     /* wait a short time for next input event */
1203                     if (WaitForSingleObject(g_hConIn, p_mouset / 3)
1204                                                              != WAIT_OBJECT_0)
1205                         break;
1206                     else
1207                     {
1208                         DWORD cRecords = 0;
1209                         INPUT_RECORD ir;
1210                         MOUSE_EVENT_RECORD* pmer2 = &ir.Event.MouseEvent;
1211
1212                         peek_console_input(g_hConIn, &ir, 1, &cRecords);
1213
1214                         if (cRecords == 0 || ir.EventType != MOUSE_EVENT
1215                                 || !(pmer2->dwButtonState & LEFT_RIGHT))
1216                             break;
1217                         else
1218                         {
1219                             if (pmer2->dwEventFlags != MOUSE_MOVED)
1220                             {
1221                                 read_console_input(g_hConIn, &ir, 1, &cRecords);
1222
1223                                 return decode_mouse_event(pmer2);
1224                             }
1225                             else if (s_xOldMouse == pmer2->dwMousePosition.X &&
1226                                      s_yOldMouse == pmer2->dwMousePosition.Y)
1227                             {
1228                                 /* throw away spurious mouse move */
1229                                 read_console_input(g_hConIn, &ir, 1, &cRecords);
1230
1231                                 /* are there any more mouse events in queue? */
1232                                 peek_console_input(g_hConIn, &ir, 1, &cRecords);
1233
1234                                 if (cRecords==0 || ir.EventType != MOUSE_EVENT)
1235                                     break;
1236                             }
1237                             else
1238                                 break;
1239                         }
1240                     }
1241                 }
1242             }
1243         }
1244
1245         if (s_fNextIsMiddle)
1246         {
1247             nButton = (pmer->dwEventFlags == MOUSE_MOVED)
1248                 ? MOUSE_DRAG : MOUSE_MIDDLE;
1249             s_fNextIsMiddle = FALSE;
1250         }
1251         else if (cButtons == 2  &&
1252             ((pmer->dwButtonState & LEFT_RIGHT) == LEFT_RIGHT))
1253         {
1254             nButton = MOUSE_MIDDLE;
1255
1256             if (! s_fReleased && pmer->dwEventFlags != MOUSE_MOVED)
1257             {
1258                 s_fNextIsMiddle = TRUE;
1259                 nButton = MOUSE_RELEASE;
1260             }
1261         }
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;
1268
1269         if (! s_fReleased && ! s_fNextIsMiddle
1270                 && nButton != s_nOldButton && s_nOldButton != MOUSE_DRAG)
1271             return FALSE;
1272
1273         s_fReleased = s_fNextIsMiddle;
1274     }
1275
1276     if (pmer->dwEventFlags == 0 || pmer->dwEventFlags == DOUBLE_CLICK)
1277     {
1278         /* button pressed or released, without mouse moving */
1279         if (nButton != -1 && nButton != MOUSE_RELEASE)
1280         {
1281             DWORD dwCurrentTime = GetTickCount();
1282
1283             if (s_xOldMouse != g_xMouse
1284                     || s_yOldMouse != g_yMouse
1285                     || s_nOldButton != nButton
1286                     || s_old_topline != curwin->w_topline
1287 #ifdef FEAT_DIFF
1288                     || s_old_topfill != curwin->w_topfill
1289 #endif
1290                     || (int)(dwCurrentTime - s_dwLastClickTime) > p_mouset)
1291             {
1292                 s_cClicks = 1;
1293             }
1294             else if (++s_cClicks > 4)
1295             {
1296                 s_cClicks = 1;
1297             }
1298
1299             s_dwLastClickTime = dwCurrentTime;
1300         }
1301     }
1302     else if (pmer->dwEventFlags == MOUSE_MOVED)
1303     {
1304         if (nButton != -1 && nButton != MOUSE_RELEASE)
1305             nButton = MOUSE_DRAG;
1306
1307         s_cClicks = 1;
1308     }
1309
1310     if (nButton == -1)
1311         return FALSE;
1312
1313     if (nButton != MOUSE_RELEASE)
1314         s_nOldButton = nButton;
1315
1316     g_nMouseClick = nButton;
1317
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;
1324
1325     if (nButton != MOUSE_DRAG && nButton != MOUSE_RELEASE)
1326         SET_NUM_MOUSE_CLICKS(g_nMouseClick, s_cClicks);
1327
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)
1332     {
1333         g_nMouseClick = -1;
1334         return FALSE;
1335     }
1336
1337     s_xOldMouse = g_xMouse;
1338     s_yOldMouse = g_yMouse;
1339     s_old_topline = curwin->w_topline;
1340 #ifdef FEAT_DIFF
1341     s_old_topfill = curwin->w_topfill;
1342 #endif
1343     s_nOldMouseClick = g_nMouseClick;
1344
1345     return TRUE;
1346 }
1347
1348 # endif /* FEAT_GUI_W32 */
1349 #endif /* FEAT_MOUSE */
1350
1351
1352 #ifdef MCH_CURSOR_SHAPE
1353 /*
1354  * Set the shape of the cursor.
1355  * 'thickness' can be from 1 (thin) to 99 (block)
1356  */
1357     static void
1358 mch_set_cursor_shape(int thickness)
1359 {
1360     CONSOLE_CURSOR_INFO ConsoleCursorInfo;
1361     ConsoleCursorInfo.dwSize = thickness;
1362     ConsoleCursorInfo.bVisible = s_cursor_visible;
1363
1364     SetConsoleCursorInfo(g_hConOut, &ConsoleCursorInfo);
1365     if (s_cursor_visible)
1366         SetConsoleCursorPosition(g_hConOut, g_coord);
1367 }
1368
1369     void
1370 mch_update_cursor(void)
1371 {
1372     int         idx;
1373     int         thickness;
1374
1375     /*
1376      * How the cursor is drawn depends on the current mode.
1377      */
1378     idx = get_shape_idx(FALSE);
1379
1380     if (shape_table[idx].shape == SHAPE_BLOCK)
1381         thickness = 99; /* 100 doesn't work on W95 */
1382     else
1383         thickness = shape_table[idx].percentage;
1384     mch_set_cursor_shape(thickness);
1385 }
1386 #endif
1387
1388 #ifndef FEAT_GUI_W32        /* this isn't used for the GUI */
1389 /*
1390  * Handle FOCUS_EVENT.
1391  */
1392     static void
1393 handle_focus_event(INPUT_RECORD ir)
1394 {
1395     g_fJustGotFocus = ir.Event.FocusEvent.bSetFocus;
1396     ui_focus_change((int)g_fJustGotFocus);
1397 }
1398
1399 /*
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.
1403  */
1404     static int
1405 WaitForChar(long msec)
1406 {
1407     DWORD           dwNow = 0, dwEndTime = 0;
1408     INPUT_RECORD    ir;
1409     DWORD           cRecords;
1410     WCHAR           ch, ch2;
1411 #ifdef FEAT_TIMERS
1412     int             tb_change_cnt = typebuf.tb_change_cnt;
1413 #endif
1414
1415     if (msec > 0)
1416         /* Wait until the specified time has elapsed. */
1417         dwEndTime = GetTickCount() + msec;
1418     else if (msec < 0)
1419         /* Wait forever. */
1420         dwEndTime = INFINITE;
1421
1422     /* We need to loop until the end of the time period, because
1423      * we might get multiple unusable mouse events in that time.
1424      */
1425     for (;;)
1426     {
1427 #ifdef MESSAGE_QUEUE
1428         parse_queued_messages();
1429 #endif
1430 #ifdef FEAT_MZSCHEME
1431         mzvim_check_threads();
1432 #endif
1433 #ifdef FEAT_CLIENTSERVER
1434         serverProcessPendingMessages();
1435 #endif
1436
1437         if (0
1438 #ifdef FEAT_MOUSE
1439                 || g_nMouseClick != -1
1440 #endif
1441 #ifdef FEAT_CLIENTSERVER
1442                 || input_available()
1443 #endif
1444            )
1445             return TRUE;
1446
1447         if (msec > 0)
1448         {
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)
1453                 break;
1454         }
1455         if (msec != 0)
1456         {
1457             DWORD dwWaitTime = dwEndTime - dwNow;
1458
1459 #ifdef FEAT_JOB_CHANNEL
1460             /* Check channel while waiting for input. */
1461             if (dwWaitTime > 100)
1462             {
1463                 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())
1467                     dwWaitTime = 10;
1468             }
1469 #endif
1470 #ifdef FEAT_BEVAL
1471             if (p_beval && dwWaitTime > 100)
1472                 /* The 'balloonexpr' may indirectly invoke a callback while
1473                  * waiting for a character, need to check often. */
1474                 dwWaitTime = 100;
1475 #endif
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' */
1480 #endif
1481 #ifdef FEAT_TIMERS
1482             {
1483                 long    due_time;
1484
1485                 /* When waiting very briefly don't trigger timers. */
1486                 if (dwWaitTime > 10)
1487                 {
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)
1492                     {
1493                         /* timer may have used feedkeys() */
1494                         return FALSE;
1495                     }
1496                     if (due_time > 0 && dwWaitTime > (DWORD)due_time)
1497                         dwWaitTime = due_time;
1498                 }
1499             }
1500 #endif
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)
1506 #else
1507             if (wait_for_single_object(g_hConIn, dwWaitTime) != WAIT_OBJECT_0)
1508 #endif
1509                     continue;
1510         }
1511
1512         cRecords = 0;
1513         peek_console_input(g_hConIn, &ir, 1, &cRecords);
1514
1515 #ifdef FEAT_MBYTE_IME
1516         if (State & CMDLINE && msg_row == Rows - 1)
1517         {
1518             CONSOLE_SCREEN_BUFFER_INFO csbi;
1519
1520             if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
1521             {
1522                 if (csbi.dwCursorPosition.Y != msg_row)
1523                 {
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);
1528                     redrawcmd();
1529                 }
1530             }
1531         }
1532 #endif
1533
1534         if (cRecords > 0)
1535         {
1536             if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
1537             {
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)
1543                 {
1544                     read_console_input(g_hConIn, &ir, 1, &cRecords);
1545                     continue;
1546                 }
1547 #endif
1548                 if (decode_key_event(&ir.Event.KeyEvent, &ch, &ch2,
1549                                                                  NULL, FALSE))
1550                     return TRUE;
1551             }
1552
1553             read_console_input(g_hConIn, &ir, 1, &cRecords);
1554
1555             if (ir.EventType == FOCUS_EVENT)
1556                 handle_focus_event(ir);
1557             else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
1558                 shell_resized();
1559 #ifdef FEAT_MOUSE
1560             else if (ir.EventType == MOUSE_EVENT
1561                     && decode_mouse_event(&ir.Event.MouseEvent))
1562                 return TRUE;
1563 #endif
1564         }
1565         else if (msec == 0)
1566             break;
1567     }
1568
1569 #ifdef FEAT_CLIENTSERVER
1570     /* Something might have been received while we were waiting. */
1571     if (input_available())
1572         return TRUE;
1573 #endif
1574
1575     return FALSE;
1576 }
1577
1578 #ifndef FEAT_GUI_MSWIN
1579 /*
1580  * return non-zero if a character is available
1581  */
1582     int
1583 mch_char_avail(void)
1584 {
1585     return WaitForChar(0L);
1586 }
1587 #endif
1588
1589 /*
1590  * Create the console input.  Used when reading stdin doesn't work.
1591  */
1592     static void
1593 create_conin(void)
1594 {
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;
1600 }
1601
1602 /*
1603  * Get a keystroke or a mouse event, use a blocking wait.
1604  */
1605     static WCHAR
1606 tgetch(int *pmodifiers, WCHAR *pch2)
1607 {
1608     WCHAR ch;
1609
1610     for (;;)
1611     {
1612         INPUT_RECORD ir;
1613         DWORD cRecords = 0;
1614
1615 #ifdef FEAT_CLIENTSERVER
1616         (void)WaitForChar(-1L);
1617         if (input_available())
1618             return 0;
1619 # ifdef FEAT_MOUSE
1620         if (g_nMouseClick != -1)
1621             return 0;
1622 # endif
1623 #endif
1624         if (read_console_input(g_hConIn, &ir, 1, &cRecords) == 0)
1625         {
1626             if (did_create_conin)
1627                 read_error_exit();
1628             create_conin();
1629             continue;
1630         }
1631
1632         if (ir.EventType == KEY_EVENT)
1633         {
1634             if (decode_key_event(&ir.Event.KeyEvent, &ch, pch2,
1635                                                             pmodifiers, TRUE))
1636                 return ch;
1637         }
1638         else if (ir.EventType == FOCUS_EVENT)
1639             handle_focus_event(ir);
1640         else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
1641             shell_resized();
1642 #ifdef FEAT_MOUSE
1643         else if (ir.EventType == MOUSE_EVENT)
1644         {
1645             if (decode_mouse_event(&ir.Event.MouseEvent))
1646                 return 0;
1647         }
1648 #endif
1649     }
1650 }
1651 #endif /* !FEAT_GUI_W32 */
1652
1653
1654 /*
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.
1661  */
1662     int
1663 mch_inchar(
1664     char_u      *buf UNUSED,
1665     int         maxlen UNUSED,
1666     long        time UNUSED,
1667     int         tb_change_cnt UNUSED)
1668 {
1669 #ifndef FEAT_GUI_W32        /* this isn't used for the GUI */
1670
1671     int         len;
1672     int         c;
1673 #define TYPEAHEADLEN 20
1674     static char_u   typeahead[TYPEAHEADLEN];    /* previously typed bytes. */
1675     static int      typeaheadlen = 0;
1676
1677     /* First use any typeahead that was kept because "buf" was too small. */
1678     if (typeaheadlen > 0)
1679         goto theend;
1680
1681     if (time >= 0)
1682     {
1683         if (!WaitForChar(time))     /* no character available */
1684             return 0;
1685     }
1686     else    /* time == -1, wait forever */
1687     {
1688         mch_set_winsize_now();  /* Allow winsize changes from now on */
1689
1690         /*
1691          * If there is no character available within 2 seconds (default)
1692          * write the autoscript file to disk.  Or cause the CursorHold event
1693          * to be triggered.
1694          */
1695         if (!WaitForChar(p_ut))
1696         {
1697 #ifdef FEAT_AUTOCMD
1698             if (trigger_cursorhold() && maxlen >= 3)
1699             {
1700                 buf[0] = K_SPECIAL;
1701                 buf[1] = KS_EXTRA;
1702                 buf[2] = (int)KE_CURSORHOLD;
1703                 return 3;
1704             }
1705 #endif
1706             before_blocking();
1707         }
1708     }
1709
1710     /*
1711      * Try to read as many characters as there are, until the buffer is full.
1712      */
1713
1714     /* we will get at least one key. Get more if they are available. */
1715     g_fCBrkPressed = FALSE;
1716
1717 #ifdef MCH_WRITE_DUMP
1718     if (fdDump)
1719         fputc('[', fdDump);
1720 #endif
1721
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)
1727     {
1728         if (typebuf_changed(tb_change_cnt))
1729         {
1730             /* "buf" may be invalid now if a client put something in the
1731              * typeahead buffer and "buf" is in the typeahead buffer. */
1732             typeaheadlen = 0;
1733             break;
1734         }
1735 #ifdef FEAT_MOUSE
1736         if (g_nMouseClick != -1)
1737         {
1738 # ifdef MCH_WRITE_DUMP
1739             if (fdDump)
1740                 fprintf(fdDump, "{%02x @ %d, %d}",
1741                         g_nMouseClick, g_xMouse, g_yMouse);
1742 # endif
1743             typeahead[typeaheadlen++] = ESC + 128;
1744             typeahead[typeaheadlen++] = 'M';
1745             typeahead[typeaheadlen++] = g_nMouseClick;
1746             typeahead[typeaheadlen++] = g_xMouse + '!';
1747             typeahead[typeaheadlen++] = g_yMouse + '!';
1748             g_nMouseClick = -1;
1749         }
1750         else
1751 #endif
1752         {
1753             WCHAR       ch2 = NUL;
1754             int         modifiers = 0;
1755
1756             c = tgetch(&modifiers, &ch2);
1757
1758             if (typebuf_changed(tb_change_cnt))
1759             {
1760                 /* "buf" may be invalid now if a client put something in the
1761                  * typeahead buffer and "buf" is in the typeahead buffer. */
1762                 typeaheadlen = 0;
1763                 break;
1764             }
1765
1766             if (c == Ctrl_C && ctrl_c_interrupts)
1767             {
1768 #if defined(FEAT_CLIENTSERVER)
1769                 trash_input_buf();
1770 #endif
1771                 got_int = TRUE;
1772             }
1773
1774 #ifdef FEAT_MOUSE
1775             if (g_nMouseClick == -1)
1776 #endif
1777             {
1778                 int     n = 1;
1779                 int     conv = FALSE;
1780
1781 #ifdef FEAT_MBYTE
1782                 if (ch2 == NUL)
1783                 {
1784                     int     i;
1785                     char_u  *p;
1786                     WCHAR   ch[2];
1787
1788                     ch[0] = c;
1789                     if (c >= 0xD800 && c <= 0xDBFF)     /* High surrogate */
1790                     {
1791                         ch[1] = tgetch(&modifiers, &ch2);
1792                         n++;
1793                     }
1794                     p = utf16_to_enc(ch, &n);
1795                     if (p != NULL)
1796                     {
1797                         for (i = 0; i < n; i++)
1798                             typeahead[typeaheadlen + i] = p[i];
1799                         vim_free(p);
1800                     }
1801                 }
1802                 else
1803 #endif
1804                     typeahead[typeaheadlen] = c;
1805                 if (ch2 != NUL)
1806                 {
1807                     typeahead[typeaheadlen + n] = 3;
1808                     typeahead[typeaheadlen + n + 1] = (char_u)ch2;
1809                     n += 2;
1810                 }
1811
1812                 if (conv)
1813                 {
1814                     char_u *p = typeahead + typeaheadlen;
1815
1816                     if (*p != K_NUL)
1817                     {
1818                         char_u *e = typeahead + TYPEAHEADLEN;
1819
1820                         while (*p && p < e)
1821                         {
1822                             if (*p == K_NUL)
1823                             {
1824                                 ++p;
1825                                 mch_memmove(p + 1, p, ((size_t)(e - p)) - 1);
1826                                 *p = 3;
1827                                 ++n;
1828                             }
1829                             ++p;
1830                         }
1831                     }
1832                 }
1833
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
1837                  * byte). */
1838                 if ((modifiers & MOD_MASK_ALT)
1839                         && n == 1
1840                         && (typeahead[typeaheadlen] & 0x80) == 0
1841 #ifdef FEAT_MBYTE
1842                         && !enc_dbcs
1843 #endif
1844                    )
1845                 {
1846 #ifdef FEAT_MBYTE
1847                     n = (*mb_char2bytes)(typeahead[typeaheadlen] | 0x80,
1848                                                     typeahead + typeaheadlen);
1849 #else
1850                     typeahead[typeaheadlen] |= 0x80;
1851 #endif
1852                     modifiers &= ~MOD_MASK_ALT;
1853                 }
1854
1855                 if (modifiers != 0)
1856                 {
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;
1863                 }
1864
1865                 typeaheadlen += n;
1866
1867 #ifdef MCH_WRITE_DUMP
1868                 if (fdDump)
1869                     fputc(c, fdDump);
1870 #endif
1871             }
1872         }
1873     }
1874
1875 #ifdef MCH_WRITE_DUMP
1876     if (fdDump)
1877     {
1878         fputs("]\n", fdDump);
1879         fflush(fdDump);
1880     }
1881 #endif
1882
1883 theend:
1884     /* Move typeahead to "buf", as much as fits. */
1885     len = 0;
1886     while (len < maxlen && typeaheadlen > 0)
1887     {
1888         buf[len++] = typeahead[0];
1889         mch_memmove(typeahead, typeahead + 1, --typeaheadlen);
1890     }
1891     return len;
1892
1893 #else /* FEAT_GUI_W32 */
1894     return 0;
1895 #endif /* FEAT_GUI_W32 */
1896 }
1897
1898 #ifndef PROTO
1899 # ifndef __MINGW32__
1900 #  include <shellapi.h> /* required for FindExecutable() */
1901 # endif
1902 #endif
1903
1904 /*
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.
1910  */
1911     static int
1912 executable_exists(char *name, char_u **path, int use_path)
1913 {
1914     char        *dum;
1915     char        fname[_MAX_PATH];
1916     char        *curpath, *newpath;
1917     long        n;
1918
1919     if (!use_path)
1920     {
1921         if (mch_getperm((char_u *)name) != -1 && !mch_isdir((char_u *)name))
1922         {
1923             if (path != NULL)
1924             {
1925                 if (mch_isFullName((char_u *)name))
1926                     *path = vim_strsave((char_u *)name);
1927                 else
1928                     *path = FullName_save((char_u *)name, FALSE);
1929             }
1930             return TRUE;
1931         }
1932         return FALSE;
1933     }
1934
1935 #ifdef FEAT_MBYTE
1936     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
1937     {
1938         WCHAR   *p = enc_to_utf16((char_u *)name, NULL);
1939         WCHAR   fnamew[_MAX_PATH];
1940         WCHAR   *dumw;
1941         WCHAR   *wcurpath, *wnewpath;
1942
1943         if (p != NULL)
1944         {
1945             wcurpath = _wgetenv(L"PATH");
1946             wnewpath = (WCHAR*)alloc((unsigned)(wcslen(wcurpath) + 3)
1947                                                             * sizeof(WCHAR));
1948             if (wnewpath == NULL)
1949                 return FALSE;
1950             wcscpy(wnewpath, L".;");
1951             wcscat(wnewpath, wcurpath);
1952             n = (long)SearchPathW(wnewpath, p, NULL, _MAX_PATH, fnamew, &dumw);
1953             vim_free(wnewpath);
1954             vim_free(p);
1955             if (n == 0)
1956                 return FALSE;
1957             if (GetFileAttributesW(fnamew) & FILE_ATTRIBUTE_DIRECTORY)
1958                 return FALSE;
1959             if (path != NULL)
1960                 *path = utf16_to_enc(fnamew, NULL);
1961             return TRUE;
1962         }
1963     }
1964 #endif
1965
1966     curpath = getenv("PATH");
1967     newpath = (char*)alloc((unsigned)(STRLEN(curpath) + 3));
1968     if (newpath == NULL)
1969         return FALSE;
1970     STRCPY(newpath, ".;");
1971     STRCAT(newpath, curpath);
1972     n = (long)SearchPath(newpath, name, NULL, _MAX_PATH, fname, &dum);
1973     vim_free(newpath);
1974     if (n == 0)
1975         return FALSE;
1976     if (mch_isdir((char_u *)fname))
1977         return FALSE;
1978     if (path != NULL)
1979         *path = vim_strsave((char_u *)fname);
1980     return TRUE;
1981 }
1982
1983 #if ((defined(__MINGW32__) || defined (__CYGWIN32__)) && \
1984        __MSVCRT_VERSION__ >= 0x800) || (defined(_MSC_VER) && _MSC_VER >= 1400)
1985 /*
1986  * Bad parameter handler.
1987  *
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.
1991  *
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.
1996  */
1997     static void
1998 bad_param_handler(const wchar_t *expression,
1999     const wchar_t *function,
2000     const wchar_t *file,
2001     unsigned int line,
2002     uintptr_t pReserved)
2003 {
2004 }
2005
2006 # define SET_INVALID_PARAM_HANDLER \
2007         ((void)_set_invalid_parameter_handler(bad_param_handler))
2008 #else
2009 # define SET_INVALID_PARAM_HANDLER
2010 #endif
2011
2012 #ifdef FEAT_GUI_W32
2013
2014 /*
2015  * GUI version of mch_init().
2016  */
2017     void
2018 mch_init(void)
2019 {
2020 #ifndef __MINGW32__
2021     extern int _fmode;
2022 #endif
2023
2024     /* Silently handle invalid parameters to CRT functions */
2025     SET_INVALID_PARAM_HANDLER;
2026
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);
2030
2031     _fmode = O_BINARY;          /* we do our own CR-LF translation */
2032
2033     /* Specify window size.  Is there a place to get the default from? */
2034     Rows = 25;
2035     Columns = 80;
2036
2037     /* Look for 'vimrun' */
2038     {
2039         char_u vimrun_location[_MAX_PATH + 4];
2040
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)
2045         {
2046             if (*skiptowhite(vimrun_location) != NUL)
2047             {
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\" ");
2053             }
2054             else
2055                 STRCPY(gettail(vimrun_location), "vimrun ");
2056
2057             vimrun_path = (char *)vim_strsave(vimrun_location);
2058             s_dont_use_vimrun = FALSE;
2059         }
2060         else if (executable_exists("vimrun.exe", NULL, TRUE))
2061             s_dont_use_vimrun = FALSE;
2062
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;
2068     }
2069
2070     /*
2071      * If "finstr.exe" doesn't exist, use "grep -n" for 'grepprg'.
2072      * Otherwise the default "findstr /n" is used.
2073      */
2074     if (!executable_exists("findstr.exe", NULL, TRUE))
2075         set_option_value((char_u *)"grepprg", 0, (char_u *)"grep -n", 0);
2076
2077 #ifdef FEAT_CLIPBOARD
2078     win_clip_init();
2079 #endif
2080 }
2081
2082
2083 #else /* FEAT_GUI_W32 */
2084
2085 #define SRWIDTH(sr) ((sr).Right - (sr).Left + 1)
2086 #define SRHEIGHT(sr) ((sr).Bottom - (sr).Top + 1)
2087
2088 /*
2089  * ClearConsoleBuffer()
2090  * Description:
2091  *  Clears the entire contents of the console screen buffer, using the
2092  *  specified attribute.
2093  * Returns:
2094  *  TRUE on success
2095  */
2096     static BOOL
2097 ClearConsoleBuffer(WORD wAttribute)
2098 {
2099     CONSOLE_SCREEN_BUFFER_INFO csbi;
2100     COORD coord;
2101     DWORD NumCells, dummy;
2102
2103     if (!GetConsoleScreenBufferInfo(g_hConOut, &csbi))
2104         return FALSE;
2105
2106     NumCells = csbi.dwSize.X * csbi.dwSize.Y;
2107     coord.X = 0;
2108     coord.Y = 0;
2109     if (!FillConsoleOutputCharacter(g_hConOut, ' ', NumCells,
2110             coord, &dummy))
2111     {
2112         return FALSE;
2113     }
2114     if (!FillConsoleOutputAttribute(g_hConOut, wAttribute, NumCells,
2115             coord, &dummy))
2116     {
2117         return FALSE;
2118     }
2119
2120     return TRUE;
2121 }
2122
2123 /*
2124  * FitConsoleWindow()
2125  * Description:
2126  *  Checks if the console window will fit within given buffer dimensions.
2127  *  Also, if requested, will shrink the window to fit.
2128  * Returns:
2129  *  TRUE on success
2130  */
2131     static BOOL
2132 FitConsoleWindow(
2133     COORD dwBufferSize,
2134     BOOL WantAdjust)
2135 {
2136     CONSOLE_SCREEN_BUFFER_INFO csbi;
2137     COORD dwWindowSize;
2138     BOOL NeedAdjust = FALSE;
2139
2140     if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
2141     {
2142         /*
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.
2146          */
2147         if (csbi.srWindow.Right >= dwBufferSize.X)
2148         {
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;
2154             NeedAdjust = TRUE;
2155         }
2156         if (csbi.srWindow.Bottom >= dwBufferSize.Y)
2157         {
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;
2163             NeedAdjust = TRUE;
2164         }
2165         if (NeedAdjust && WantAdjust)
2166         {
2167             if (!SetConsoleWindowInfo(g_hConOut, TRUE, &csbi.srWindow))
2168                 return FALSE;
2169         }
2170         return TRUE;
2171     }
2172
2173     return FALSE;
2174 }
2175
2176 typedef struct ConsoleBufferStruct
2177 {
2178     BOOL                        IsValid;
2179     CONSOLE_SCREEN_BUFFER_INFO  Info;
2180     PCHAR_INFO                  Buffer;
2181     COORD                       BufferSize;
2182 } ConsoleBuffer;
2183
2184 /*
2185  * SaveConsoleBuffer()
2186  * Description:
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().
2190  * Returns:
2191  *  TRUE if all information was saved; FALSE otherwise
2192  *  If FALSE, still sets cb->IsValid if buffer characteristics were saved.
2193  */
2194     static BOOL
2195 SaveConsoleBuffer(
2196     ConsoleBuffer *cb)
2197 {
2198     DWORD NumCells;
2199     COORD BufferCoord;
2200     SMALL_RECT ReadRegion;
2201     WORD Y, Y_incr;
2202
2203     if (cb == NULL)
2204         return FALSE;
2205
2206     if (!GetConsoleScreenBufferInfo(g_hConOut, &cb->Info))
2207     {
2208         cb->IsValid = FALSE;
2209         return FALSE;
2210     }
2211     cb->IsValid = TRUE;
2212
2213     /*
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.
2217      */
2218     if (!cb->IsValid || cb->Buffer == NULL ||
2219             cb->BufferSize.X != cb->Info.dwSize.X ||
2220             cb->BufferSize.Y != cb->Info.dwSize.Y)
2221     {
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)
2228             return FALSE;
2229     }
2230
2231     /*
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).
2239      */
2240     BufferCoord.X = 0;
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)
2245     {
2246         /*
2247          * Read into position (0, Y) in our buffer.
2248          */
2249         BufferCoord.Y = Y;
2250         /*
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.
2255          */
2256         ReadRegion.Top = Y;
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 */
2263         {
2264             vim_free(cb->Buffer);
2265             cb->Buffer = NULL;
2266             return FALSE;
2267         }
2268     }
2269
2270     return TRUE;
2271 }
2272
2273 /*
2274  * RestoreConsoleBuffer()
2275  * Description:
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().
2279  * Returns:
2280  *  TRUE on success
2281  */
2282     static BOOL
2283 RestoreConsoleBuffer(
2284     ConsoleBuffer   *cb,
2285     BOOL            RestoreScreen)
2286 {
2287     COORD BufferCoord;
2288     SMALL_RECT WriteRegion;
2289
2290     if (cb == NULL || !cb->IsValid)
2291         return FALSE;
2292
2293     /*
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.
2297      */
2298     if (RestoreScreen)
2299         ClearConsoleBuffer(cb->Info.wAttributes);
2300
2301     FitConsoleWindow(cb->Info.dwSize, TRUE);
2302     if (!SetConsoleScreenBufferSize(g_hConOut, cb->Info.dwSize))
2303         return FALSE;
2304     if (!SetConsoleTextAttribute(g_hConOut, cb->Info.wAttributes))
2305         return FALSE;
2306
2307     if (!RestoreScreen)
2308     {
2309         /*
2310          * No need to restore the screen buffer contents, so we're done.
2311          */
2312         return TRUE;
2313     }
2314
2315     if (!SetConsoleCursorPosition(g_hConOut, cb->Info.dwCursorPosition))
2316         return FALSE;
2317     if (!SetConsoleWindowInfo(g_hConOut, TRUE, &cb->Info.srWindow))
2318         return FALSE;
2319
2320     /*
2321      * Restore the screen buffer contents.
2322      */
2323     if (cb->Buffer != NULL)
2324     {
2325         BufferCoord.X = 0;
2326         BufferCoord.Y = 0;
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 */
2336         {
2337             return FALSE;
2338         }
2339     }
2340
2341     return TRUE;
2342 }
2343
2344 #define FEAT_RESTORE_ORIG_SCREEN
2345 #ifdef FEAT_RESTORE_ORIG_SCREEN
2346 static ConsoleBuffer g_cbOrig = { 0 };
2347 #endif
2348 static ConsoleBuffer g_cbNonTermcap = { 0 };
2349 static ConsoleBuffer g_cbTermcap = { 0 };
2350
2351 #ifdef FEAT_TITLE
2352 #ifdef __BORLANDC__
2353 typedef HWND (__stdcall *GETCONSOLEWINDOWPROC)(VOID);
2354 #else
2355 typedef HWND (WINAPI *GETCONSOLEWINDOWPROC)(VOID);
2356 #endif
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;
2363
2364 /* ICON* are not defined in VC++ 4.0 */
2365 #ifndef ICON_SMALL
2366 #define ICON_SMALL 0
2367 #endif
2368 #ifndef ICON_BIG
2369 #define ICON_BIG 1
2370 #endif
2371 /*
2372  * GetConsoleIcon()
2373  * Description:
2374  *  Attempts to retrieve the small icon and/or the big icon currently in
2375  *  use by a given window.
2376  * Returns:
2377  *  TRUE on success
2378  */
2379     static BOOL
2380 GetConsoleIcon(
2381     HWND        hWnd,
2382     HICON       *phIconSmall,
2383     HICON       *phIcon)
2384 {
2385     if (hWnd == NULL)
2386         return FALSE;
2387
2388     if (phIconSmall != NULL)
2389         *phIconSmall = (HICON)SendMessage(hWnd, WM_GETICON,
2390                                                (WPARAM)ICON_SMALL, (LPARAM)0);
2391     if (phIcon != NULL)
2392         *phIcon = (HICON)SendMessage(hWnd, WM_GETICON,
2393                                                  (WPARAM)ICON_BIG, (LPARAM)0);
2394     return TRUE;
2395 }
2396
2397 /*
2398  * SetConsoleIcon()
2399  * Description:
2400  *  Attempts to change the small icon and/or the big icon currently in
2401  *  use by a given window.
2402  * Returns:
2403  *  TRUE on success
2404  */
2405     static BOOL
2406 SetConsoleIcon(
2407     HWND    hWnd,
2408     HICON   hIconSmall,
2409     HICON   hIcon)
2410 {
2411     if (hWnd == NULL)
2412         return FALSE;
2413
2414     if (hIconSmall != NULL)
2415         SendMessage(hWnd, WM_SETICON,
2416                             (WPARAM)ICON_SMALL, (LPARAM)hIconSmall);
2417     if (hIcon != NULL)
2418         SendMessage(hWnd, WM_SETICON,
2419                             (WPARAM)ICON_BIG, (LPARAM) hIcon);
2420     return TRUE;
2421 }
2422
2423 /*
2424  * SaveConsoleTitleAndIcon()
2425  * Description:
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).
2432  */
2433     static void
2434 SaveConsoleTitleAndIcon(void)
2435 {
2436     /* Save the original title. */
2437     if (!GetConsoleTitle(g_szOrigTitle, sizeof(g_szOrigTitle)))
2438         return;
2439
2440     /*
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
2445      * anyway.
2446      */
2447     g_hWnd = GetConsoleWindow();
2448     if (g_hWnd == NULL)
2449         return;
2450
2451     /* Save the original console window icon. */
2452     GetConsoleIcon(g_hWnd, &g_hOrigIconSmall, &g_hOrigIcon);
2453     if (g_hOrigIconSmall == NULL || g_hOrigIcon == NULL)
2454         return;
2455
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;
2461 }
2462 #endif
2463
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;
2469
2470 /*
2471  * non-GUI version of mch_init().
2472  */
2473     void
2474 mch_init(void)
2475 {
2476 #ifndef FEAT_RESTORE_ORIG_SCREEN
2477     CONSOLE_SCREEN_BUFFER_INFO csbi;
2478 #endif
2479 #ifndef __MINGW32__
2480     extern int _fmode;
2481 #endif
2482
2483     /* Silently handle invalid parameters to CRT functions */
2484     SET_INVALID_PARAM_HANDLER;
2485
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);
2489
2490     _fmode = O_BINARY;          /* we do our own CR-LF translation */
2491     out_flush();
2492
2493     /* Obtain handles for the standard Console I/O devices */
2494     if (read_cmd_fd == 0)
2495         g_hConIn =  GetStdHandle(STD_INPUT_HANDLE);
2496     else
2497         create_conin();
2498     g_hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
2499
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;
2504 #else
2505     /* Get current text attributes */
2506     GetConsoleScreenBufferInfo(g_hConOut, &csbi);
2507     g_attrCurrent = g_attrDefault = csbi.wAttributes;
2508 #endif
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;
2513
2514     /* set termcap codes to current text attributes */
2515     update_tcap(g_attrCurrent);
2516
2517     GetConsoleCursorInfo(g_hConOut, &g_cci);
2518     GetConsoleMode(g_hConIn,  &g_cmodein);
2519     GetConsoleMode(g_hConOut, &g_cmodeout);
2520
2521 #ifdef FEAT_TITLE
2522     SaveConsoleTitleAndIcon();
2523     /*
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.
2527      */
2528     if (g_fCanChangeIcon)
2529         SetConsoleIcon(g_hWnd, g_hVimIcon, g_hVimIcon);
2530 #endif
2531
2532     ui_get_shellsize();
2533
2534 #ifdef MCH_WRITE_DUMP
2535     fdDump = fopen("dump", "wt");
2536
2537     if (fdDump)
2538     {
2539         time_t t;
2540
2541         time(&t);
2542         fputs(ctime(&t), fdDump);
2543         fflush(fdDump);
2544     }
2545 #endif
2546
2547     g_fWindInitCalled = TRUE;
2548
2549 #ifdef FEAT_MOUSE
2550     g_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT);
2551 #endif
2552
2553 #ifdef FEAT_CLIPBOARD
2554     win_clip_init();
2555 #endif
2556 }
2557
2558 /*
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()!
2562  */
2563     void
2564 mch_exit(int r)
2565 {
2566     exiting = TRUE;
2567
2568     stoptermcap();
2569     if (g_fWindInitCalled)
2570         settmode(TMODE_COOK);
2571
2572     ml_close_all(TRUE);         /* remove all memfiles */
2573
2574     if (g_fWindInitCalled)
2575     {
2576 #ifdef FEAT_TITLE
2577         mch_restore_title(3);
2578         /*
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.
2582          */
2583         if (g_fCanChangeIcon && !g_fForceExit)
2584             SetConsoleIcon(g_hWnd, g_hOrigIconSmall, g_hOrigIcon);
2585 #endif
2586
2587 #ifdef MCH_WRITE_DUMP
2588         if (fdDump)
2589         {
2590             time_t t;
2591
2592             time(&t);
2593             fputs(ctime(&t), fdDump);
2594             fclose(fdDump);
2595         }
2596         fdDump = NULL;
2597 #endif
2598     }
2599
2600     SetConsoleCursorInfo(g_hConOut, &g_cci);
2601     SetConsoleMode(g_hConIn,  g_cmodein);
2602     SetConsoleMode(g_hConOut, g_cmodeout);
2603
2604 #ifdef DYNAMIC_GETTEXT
2605     dyn_libintl_end();
2606 #endif
2607
2608     exit(r);
2609 }
2610 #endif /* !FEAT_GUI_W32 */
2611
2612 /*
2613  * Do we have an interactive window?
2614  */
2615     int
2616 mch_check_win(
2617     int argc UNUSED,
2618     char **argv UNUSED)
2619 {
2620     get_exe_name();
2621
2622 #ifdef FEAT_GUI_W32
2623     return OK;      /* GUI always has a tty */
2624 #else
2625     if (isatty(1))
2626         return OK;
2627     return FAIL;
2628 #endif
2629 }
2630
2631
2632 #ifdef FEAT_MBYTE
2633 /*
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
2636  * filenames.
2637  * Return FAIL if wide functions are not available, OK otherwise.
2638  * NOTE: much of this is identical to fname_case(), keep in sync!
2639  */
2640     static int
2641 fname_casew(
2642     WCHAR       *name,
2643     int         len)
2644 {
2645     WCHAR               szTrueName[_MAX_PATH + 2];
2646     WCHAR               szTrueNameTemp[_MAX_PATH + 2];
2647     WCHAR               *ptrue, *ptruePrev;
2648     WCHAR               *porig, *porigPrev;
2649     int                 flen;
2650     WIN32_FIND_DATAW    fb;
2651     HANDLE              hFind = INVALID_HANDLE_VALUE;
2652     int                 c;
2653     int                 slen;
2654
2655     flen = (int)wcslen(name);
2656     if (flen > _MAX_PATH)
2657         return OK;
2658
2659     /* slash_adjust(name) not needed, already adjusted by fname_case(). */
2660
2661     /* Build the new name in szTrueName[] one component at a time. */
2662     porig = name;
2663     ptrue = szTrueName;
2664
2665     if (iswalpha(porig[0]) && porig[1] == L':')
2666     {
2667         /* copy leading drive letter */
2668         *ptrue++ = *porig++;
2669         *ptrue++ = *porig++;
2670     }
2671     *ptrue = NUL;           /* in case nothing follows */
2672
2673     while (*porig != NUL)
2674     {
2675         /* copy \ characters */
2676         while (*porig == psepc)
2677             *ptrue++ = *porig++;
2678
2679         ptruePrev = ptrue;
2680         porigPrev = porig;
2681         while (*porig != NUL && *porig != psepc)
2682         {
2683             *ptrue++ = *porig++;
2684         }
2685         *ptrue = NUL;
2686
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"\\*");
2693
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)
2701         {
2702             c = *porig;
2703             *porig = NUL;
2704
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
2709                     || (len > 0
2710                         && (_wcsicoll(porigPrev, fb.cAlternateFileName) == 0
2711                             && (int)(ptruePrev - szTrueName)
2712                                            + (int)wcslen(fb.cFileName) < len)))
2713             {
2714                 wcscpy(ptruePrev, fb.cFileName);
2715
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))
2719                 {
2720                     if (*fb.cAlternateFileName != NUL
2721                             && (wcscoll(porigPrev, fb.cFileName) == 0
2722                                 || (len > 0
2723                                     && (_wcsicoll(porigPrev,
2724                                                    fb.cAlternateFileName) == 0
2725                                     && (int)(ptruePrev - szTrueName)
2726                                          + (int)wcslen(fb.cFileName) < len))))
2727                     {
2728                         wcscpy(ptruePrev, fb.cFileName);
2729                         break;
2730                     }
2731                 }
2732             }
2733             FindClose(hFind);
2734             *porig = c;
2735             ptrue = ptruePrev + wcslen(ptruePrev);
2736         }
2737     }
2738
2739     wcscpy(name, szTrueName);
2740     return OK;
2741 }
2742 #endif
2743
2744 /*
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!
2748  */
2749     void
2750 fname_case(
2751     char_u      *name,
2752     int         len)
2753 {
2754     char                szTrueName[_MAX_PATH + 2];
2755     char                szTrueNameTemp[_MAX_PATH + 2];
2756     char                *ptrue, *ptruePrev;
2757     char                *porig, *porigPrev;
2758     int                 flen;
2759     WIN32_FIND_DATA     fb;
2760     HANDLE              hFind;
2761     int                 c;
2762     int                 slen;
2763
2764     flen = (int)STRLEN(name);
2765     if (flen == 0)
2766         return;
2767
2768     slash_adjust(name);
2769
2770 #ifdef FEAT_MBYTE
2771     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2772     {
2773         WCHAR   *p = enc_to_utf16(name, NULL);
2774
2775         if (p != NULL)
2776         {
2777             char_u      *q;
2778             WCHAR       buf[_MAX_PATH + 1];
2779
2780             wcsncpy(buf, p, _MAX_PATH);
2781             buf[_MAX_PATH] = L'\0';
2782             vim_free(p);
2783
2784             if (fname_casew(buf, (len > 0) ? _MAX_PATH : 0) == OK)
2785             {
2786                 q = utf16_to_enc(buf, NULL);
2787                 if (q != NULL)
2788                 {
2789                     vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
2790                     vim_free(q);
2791                     return;
2792                 }
2793             }
2794         }
2795         return;
2796     }
2797 #endif
2798
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)
2802         return;
2803
2804     /* Build the new name in szTrueName[] one component at a time. */
2805     porig = (char *)name;
2806     ptrue = szTrueName;
2807
2808     if (isalpha(porig[0]) && porig[1] == ':')
2809     {
2810         /* copy leading drive letter */
2811         *ptrue++ = *porig++;
2812         *ptrue++ = *porig++;
2813     }
2814     *ptrue = NUL;           /* in case nothing follows */
2815
2816     while (*porig != NUL)
2817     {
2818         /* copy \ characters */
2819         while (*porig == psepc)
2820             *ptrue++ = *porig++;
2821
2822         ptruePrev = ptrue;
2823         porigPrev = porig;
2824         while (*porig != NUL && *porig != psepc)
2825         {
2826 #ifdef FEAT_MBYTE
2827             int l;
2828
2829             if (enc_dbcs)
2830             {
2831                 l = (*mb_ptr2len)((char_u *)porig);
2832                 while (--l >= 0)
2833                     *ptrue++ = *porig++;
2834             }
2835             else
2836 #endif
2837                 *ptrue++ = *porig++;
2838         }
2839         *ptrue = NUL;
2840
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, "\\*");
2847
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)
2855         {
2856             c = *porig;
2857             *porig = NUL;
2858
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
2863                     || (len > 0
2864                         && (_stricoll(porigPrev, fb.cAlternateFileName) == 0
2865                             && (int)(ptruePrev - szTrueName)
2866                                            + (int)strlen(fb.cFileName) < len)))
2867             {
2868                 STRCPY(ptruePrev, fb.cFileName);
2869
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))
2873                 {
2874                     if (*fb.cAlternateFileName != NUL
2875                             && (strcoll(porigPrev, fb.cFileName) == 0
2876                                 || (len > 0
2877                                     && (_stricoll(porigPrev,
2878                                                    fb.cAlternateFileName) == 0
2879                                     && (int)(ptruePrev - szTrueName)
2880                                          + (int)strlen(fb.cFileName) < len))))
2881                     {
2882                         STRCPY(ptruePrev, fb.cFileName);
2883                         break;
2884                     }
2885                 }
2886             }
2887             FindClose(hFind);
2888             *porig = c;
2889             ptrue = ptruePrev + strlen(ptruePrev);
2890         }
2891     }
2892
2893     STRCPY(name, szTrueName);
2894 }
2895
2896
2897 /*
2898  * Insert user name in s[len].
2899  */
2900     int
2901 mch_get_user_name(
2902     char_u  *s,
2903     int     len)
2904 {
2905     char szUserName[256 + 1];   /* UNLEN is 256 */
2906     DWORD cch = sizeof szUserName;
2907
2908 #ifdef FEAT_MBYTE
2909     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2910     {
2911         WCHAR wszUserName[256 + 1];     /* UNLEN is 256 */
2912         DWORD wcch = sizeof(wszUserName) / sizeof(WCHAR);
2913
2914         if (GetUserNameW(wszUserName, &wcch))
2915         {
2916             char_u  *p = utf16_to_enc(wszUserName, NULL);
2917
2918             if (p != NULL)
2919             {
2920                 vim_strncpy(s, p, len - 1);
2921                 vim_free(p);
2922                 return OK;
2923             }
2924         }
2925     }
2926 #endif
2927     if (GetUserName(szUserName, &cch))
2928     {
2929         vim_strncpy(s, (char_u *)szUserName, len - 1);
2930         return OK;
2931     }
2932     s[0] = NUL;
2933     return FAIL;
2934 }
2935
2936
2937 /*
2938  * Insert host name in s[len].
2939  */
2940     void
2941 mch_get_host_name(
2942     char_u      *s,
2943     int         len)
2944 {
2945     DWORD cch = len;
2946
2947 #ifdef FEAT_MBYTE
2948     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2949     {
2950         WCHAR wszHostName[256 + 1];
2951         DWORD wcch = sizeof(wszHostName) / sizeof(WCHAR);
2952
2953         if (GetComputerNameW(wszHostName, &wcch))
2954         {
2955             char_u  *p = utf16_to_enc(wszHostName, NULL);
2956
2957             if (p != NULL)
2958             {
2959                 vim_strncpy(s, p, len - 1);
2960                 vim_free(p);
2961                 return;
2962             }
2963         }
2964     }
2965 #endif
2966     if (!GetComputerName((LPSTR)s, &cch))
2967         vim_strncpy(s, (char_u *)"PC (Win32 Vim)", len - 1);
2968 }
2969
2970
2971 /*
2972  * return process ID
2973  */
2974     long
2975 mch_get_pid(void)
2976 {
2977     return (long)GetCurrentProcessId();
2978 }
2979
2980
2981 /*
2982  * Get name of current directory into buffer 'buf' of length 'len' bytes.
2983  * Return OK for success, FAIL for failure.
2984  */
2985     int
2986 mch_dirname(
2987     char_u      *buf,
2988     int         len)
2989 {
2990     /*
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>
2995      */
2996 #ifdef FEAT_MBYTE
2997     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2998     {
2999         WCHAR   wbuf[_MAX_PATH + 1];
3000
3001         if (GetCurrentDirectoryW(_MAX_PATH, wbuf) != 0)
3002         {
3003             char_u  *p = utf16_to_enc(wbuf, NULL);
3004
3005             if (p != NULL)
3006             {
3007                 vim_strncpy(buf, p, len - 1);
3008                 vim_free(p);
3009                 return OK;
3010             }
3011         }
3012         return FAIL;
3013     }
3014 #endif
3015     return (GetCurrentDirectory(len, (LPSTR)buf) != 0 ? OK : FAIL);
3016 }
3017
3018 /*
3019  * Get file permissions for "name".
3020  * Return mode_t or -1 for error.
3021  */
3022     long
3023 mch_getperm(char_u *name)
3024 {
3025     stat_T      st;
3026     int         n;
3027
3028     n = mch_stat((char *)name, &st);
3029     return n == 0 ? (long)(unsigned short)st.st_mode : -1L;
3030 }
3031
3032
3033 /*
3034  * Set file permission for "name" to "perm".
3035  *
3036  * Return FAIL for failure, OK otherwise.
3037  */
3038     int
3039 mch_setperm(char_u *name, long perm)
3040 {
3041     long        n = -1;
3042
3043 #ifdef FEAT_MBYTE
3044     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3045     {
3046         WCHAR *p = enc_to_utf16(name, NULL);
3047
3048         if (p != NULL)
3049         {
3050             n = _wchmod(p, perm);
3051             vim_free(p);
3052             if (n == -1)
3053                 return FAIL;
3054         }
3055     }
3056     if (n == -1)
3057 #endif
3058         n = _chmod((const char *)name, perm);
3059     if (n == -1)
3060         return FAIL;
3061
3062     win32_set_archive(name);
3063
3064     return OK;
3065 }
3066
3067 /*
3068  * Set hidden flag for "name".
3069  */
3070     void
3071 mch_hide(char_u *name)
3072 {
3073     int attrs = win32_getattrs(name);
3074     if (attrs == -1)
3075         return;
3076
3077     attrs |= FILE_ATTRIBUTE_HIDDEN;
3078     win32_setattrs(name, attrs);
3079 }
3080
3081 /*
3082  * Return TRUE if file "name" exists and is hidden.
3083  */
3084     int
3085 mch_ishidden(char_u *name)
3086 {
3087     int f = win32_getattrs(name);
3088
3089     if (f == -1)
3090         return FALSE;               /* file does not exist at all */
3091
3092     return (f & FILE_ATTRIBUTE_HIDDEN) != 0;
3093 }
3094
3095 /*
3096  * return TRUE if "name" is a directory
3097  * return FALSE if "name" is not a directory or upon error
3098  */
3099     int
3100 mch_isdir(char_u *name)
3101 {
3102     int f = win32_getattrs(name);
3103
3104     if (f == -1)
3105         return FALSE;               /* file does not exist at all */
3106
3107     return (f & FILE_ATTRIBUTE_DIRECTORY) != 0;
3108 }
3109
3110 /*
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
3114  */
3115     int
3116 mch_isrealdir(char_u *name)
3117 {
3118     return mch_isdir(name) && !mch_is_symbolic_link(name);
3119 }
3120
3121 /*
3122  * Create directory "name".
3123  * Return 0 on success, -1 on error.
3124  */
3125     int
3126 mch_mkdir(char_u *name)
3127 {
3128 #ifdef FEAT_MBYTE
3129     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3130     {
3131         WCHAR   *p;
3132         int     retval;
3133
3134         p = enc_to_utf16(name, NULL);
3135         if (p == NULL)
3136             return -1;
3137         retval = _wmkdir(p);
3138         vim_free(p);
3139         return retval;
3140     }
3141 #endif
3142     return _mkdir((const char *)name);
3143 }
3144
3145 /*
3146  * Delete directory "name".
3147  * Return 0 on success, -1 on error.
3148  */
3149     int
3150 mch_rmdir(char_u *name)
3151 {
3152 #ifdef FEAT_MBYTE
3153     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3154     {
3155         WCHAR   *p;
3156         int     retval;
3157
3158         p = enc_to_utf16(name, NULL);
3159         if (p == NULL)
3160             return -1;
3161         retval = _wrmdir(p);
3162         vim_free(p);
3163         return retval;
3164     }
3165 #endif
3166     return _rmdir((const char *)name);
3167 }
3168
3169 /*
3170  * Return TRUE if file "fname" has more than one link.
3171  */
3172     int
3173 mch_is_hard_link(char_u *fname)
3174 {
3175     BY_HANDLE_FILE_INFORMATION info;
3176
3177     return win32_fileinfo(fname, &info) == FILEINFO_OK
3178                                                    && info.nNumberOfLinks > 1;
3179 }
3180
3181 /*
3182  * Return TRUE if "name" is a symbolic link (or a junction).
3183  */
3184     int
3185 mch_is_symbolic_link(char_u *name)
3186 {
3187     HANDLE              hFind;
3188     int                 res = FALSE;
3189     WIN32_FIND_DATAA    findDataA;
3190     DWORD               fileFlags = 0, reparseTag = 0;
3191 #ifdef FEAT_MBYTE
3192     WCHAR               *wn = NULL;
3193     WIN32_FIND_DATAW    findDataW;
3194
3195     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3196         wn = enc_to_utf16(name, NULL);
3197     if (wn != NULL)
3198     {
3199         hFind = FindFirstFileW(wn, &findDataW);
3200         vim_free(wn);
3201         if (hFind != INVALID_HANDLE_VALUE)
3202         {
3203             fileFlags = findDataW.dwFileAttributes;
3204             reparseTag = findDataW.dwReserved0;
3205         }
3206     }
3207     else
3208 #endif
3209     {
3210         hFind = FindFirstFile((LPCSTR)name, &findDataA);
3211         if (hFind != INVALID_HANDLE_VALUE)
3212         {
3213             fileFlags = findDataA.dwFileAttributes;
3214             reparseTag = findDataA.dwReserved0;
3215         }
3216     }
3217
3218     if (hFind != INVALID_HANDLE_VALUE)
3219         FindClose(hFind);
3220
3221     if ((fileFlags & FILE_ATTRIBUTE_REPARSE_POINT)
3222             && (reparseTag == IO_REPARSE_TAG_SYMLINK
3223                 || reparseTag == IO_REPARSE_TAG_MOUNT_POINT))
3224         res = TRUE;
3225
3226     return res;
3227 }
3228
3229 /*
3230  * Return TRUE if file "fname" has more than one link or if it is a symbolic
3231  * link.
3232  */
3233     int
3234 mch_is_linked(char_u *fname)
3235 {
3236     if (mch_is_hard_link(fname) || mch_is_symbolic_link(fname))
3237         return TRUE;
3238     return FALSE;
3239 }
3240
3241 /*
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.
3247  */
3248     int
3249 win32_fileinfo(char_u *fname, BY_HANDLE_FILE_INFORMATION *info)
3250 {
3251     HANDLE      hFile;
3252     int         res = FILEINFO_READ_FAIL;
3253 #ifdef FEAT_MBYTE
3254     WCHAR       *wn = NULL;
3255
3256     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3257     {
3258         wn = enc_to_utf16(fname, NULL);
3259         if (wn == NULL)
3260             return FILEINFO_ENC_FAIL;
3261     }
3262     if (wn != NULL)
3263     {
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 */
3271         vim_free(wn);
3272     }
3273     else
3274 #endif
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 */
3282
3283     if (hFile != INVALID_HANDLE_VALUE)
3284     {
3285         if (GetFileInformationByHandle(hFile, info) != 0)
3286             res = FILEINFO_OK;
3287         else
3288             res = FILEINFO_INFO_FAIL;
3289         CloseHandle(hFile);
3290     }
3291
3292     return res;
3293 }
3294
3295 /*
3296  * get file attributes for `name'
3297  * -1 : error
3298  * else FILE_ATTRIBUTE_* defined in winnt.h
3299  */
3300     static int
3301 win32_getattrs(char_u *name)
3302 {
3303     int         attr;
3304 #ifdef FEAT_MBYTE
3305     WCHAR       *p = NULL;
3306
3307     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3308         p = enc_to_utf16(name, NULL);
3309
3310     if (p != NULL)
3311     {
3312         attr = GetFileAttributesW(p);
3313         vim_free(p);
3314     }
3315     else
3316 #endif
3317         attr = GetFileAttributes((char *)name);
3318
3319     return attr;
3320 }
3321
3322 /*
3323  * set file attributes for `name' to `attrs'
3324  *
3325  * return -1 for failure, 0 otherwise
3326  */
3327     static
3328     int
3329 win32_setattrs(char_u *name, int attrs)
3330 {
3331     int res;
3332 #ifdef FEAT_MBYTE
3333     WCHAR       *p = NULL;
3334
3335     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3336         p = enc_to_utf16(name, NULL);
3337
3338     if (p != NULL)
3339     {
3340         res = SetFileAttributesW(p, attrs);
3341         vim_free(p);
3342     }
3343     else
3344 #endif
3345         res = SetFileAttributes((char *)name, attrs);
3346
3347     return res ? 0 : -1;
3348 }
3349
3350 /*
3351  * Set archive flag for "name".
3352  */
3353     static
3354     int
3355 win32_set_archive(char_u *name)
3356 {
3357     int attrs = win32_getattrs(name);
3358     if (attrs == -1)
3359         return -1;
3360
3361     attrs |= FILE_ATTRIBUTE_ARCHIVE;
3362     return win32_setattrs(name, attrs);
3363 }
3364
3365 /*
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.
3369  */
3370     int
3371 mch_writable(char_u *name)
3372 {
3373     int attrs = win32_getattrs(name);
3374
3375     return (attrs != -1 && (!(attrs & FILE_ATTRIBUTE_READONLY)
3376                           || (attrs & FILE_ATTRIBUTE_DIRECTORY)));
3377 }
3378
3379 /*
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.
3384  */
3385     int
3386 mch_can_exe(char_u *name, char_u **path, int use_path)
3387 {
3388     char_u      buf[_MAX_PATH];
3389     int         len = (int)STRLEN(name);
3390     char_u      *p;
3391
3392     if (len >= _MAX_PATH)       /* safety check */
3393         return FALSE;
3394
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))
3400             return TRUE;
3401
3402     /*
3403      * Loop over all extensions in $PATHEXT.
3404      */
3405     vim_strncpy(buf, name, _MAX_PATH - 1);
3406     p = mch_getenv("PATHEXT");
3407     if (p == NULL)
3408         p = (char_u *)".com;.exe;.bat;.cmd";
3409     while (*p)
3410     {
3411         if (p[0] == '.' && (p[1] == NUL || p[1] == ';'))
3412         {
3413             /* A single "." means no extension is added. */
3414             buf[len] = NUL;
3415             ++p;
3416             if (*p)
3417                 ++p;
3418         }
3419         else
3420             copy_option_part(&p, buf + len, _MAX_PATH - len, ";");
3421         if (executable_exists((char *)buf, path, use_path))
3422             return TRUE;
3423     }
3424     return FALSE;
3425 }
3426
3427 /*
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
3432  */
3433     int
3434 mch_nodetype(char_u *name)
3435 {
3436     HANDLE      hFile;
3437     int         type;
3438 #ifdef FEAT_MBYTE
3439     WCHAR       *wn = NULL;
3440 #endif
3441
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
3444      * here. */
3445     if (STRNCMP(name, "\\\\.\\", 4) == 0)
3446         return NODE_WRITABLE;
3447
3448 #ifdef FEAT_MBYTE
3449     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3450         wn = enc_to_utf16(name, NULL);
3451
3452     if (wn != NULL)
3453     {
3454         hFile = CreateFileW(wn,             /* file name */
3455                     GENERIC_WRITE,          /* access mode */
3456                     0,                      /* share mode */
3457                     NULL,                   /* security descriptor */
3458                     OPEN_EXISTING,          /* creation disposition */
3459                     0,                      /* file attributes */
3460                     NULL);                  /* handle to template file */
3461         vim_free(wn);
3462     }
3463     else
3464 #endif
3465         hFile = CreateFile((LPCSTR)name,    /* file name */
3466                     GENERIC_WRITE,          /* access mode */
3467                     0,                      /* share mode */
3468                     NULL,                   /* security descriptor */
3469                     OPEN_EXISTING,          /* creation disposition */
3470                     0,                      /* file attributes */
3471                     NULL);                  /* handle to template file */
3472
3473     if (hFile == INVALID_HANDLE_VALUE)
3474         return NODE_NORMAL;
3475
3476     type = GetFileType(hFile);
3477     CloseHandle(hFile);
3478     if (type == FILE_TYPE_CHAR)
3479         return NODE_WRITABLE;
3480     if (type == FILE_TYPE_DISK)
3481         return NODE_NORMAL;
3482     return NODE_OTHER;
3483 }
3484
3485 #ifdef HAVE_ACL
3486 struct my_acl
3487 {
3488     PSECURITY_DESCRIPTOR    pSecurityDescriptor;
3489     PSID                    pSidOwner;
3490     PSID                    pSidGroup;
3491     PACL                    pDacl;
3492     PACL                    pSacl;
3493 };
3494 #endif
3495
3496 /*
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.
3499  */
3500     vim_acl_T
3501 mch_get_acl(char_u *fname)
3502 {
3503 #ifndef HAVE_ACL
3504     return (vim_acl_T)NULL;
3505 #else
3506     struct my_acl   *p = NULL;
3507     DWORD   err;
3508
3509     p = (struct my_acl *)alloc_clear((unsigned)sizeof(struct my_acl));
3510     if (p != NULL)
3511     {
3512 # ifdef FEAT_MBYTE
3513         WCHAR   *wn = NULL;
3514
3515         if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3516             wn = enc_to_utf16(fname, NULL);
3517         if (wn != NULL)
3518         {
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)
3534             {
3535                 /* Retrieve only DACL. */
3536                 (void)GetNamedSecurityInfoW(
3537                         wn,
3538                         SE_FILE_OBJECT,
3539                         DACL_SECURITY_INFORMATION,
3540                         NULL,
3541                         NULL,
3542                         &p->pDacl,
3543                         NULL,
3544                         &p->pSecurityDescriptor);
3545             }
3546             if (p->pSecurityDescriptor == NULL)
3547             {
3548                 mch_free_acl((vim_acl_T)p);
3549                 p = NULL;
3550             }
3551             vim_free(wn);
3552         }
3553         else
3554 # endif
3555         {
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)
3571             {
3572                 /* Retrieve only DACL. */
3573                 (void)GetNamedSecurityInfo(
3574                         (LPSTR)fname,
3575                         SE_FILE_OBJECT,
3576                         DACL_SECURITY_INFORMATION,
3577                         NULL,
3578                         NULL,
3579                         &p->pDacl,
3580                         NULL,
3581                         &p->pSecurityDescriptor);
3582             }
3583             if (p->pSecurityDescriptor == NULL)
3584             {
3585                 mch_free_acl((vim_acl_T)p);
3586                 p = NULL;
3587             }
3588         }
3589     }
3590
3591     return (vim_acl_T)p;
3592 #endif
3593 }
3594
3595 #ifdef HAVE_ACL
3596 /*
3597  * Check if "acl" contains inherited ACE.
3598  */
3599     static BOOL
3600 is_acl_inherited(PACL acl)
3601 {
3602     DWORD   i;
3603     ACL_SIZE_INFORMATION    acl_info;
3604     PACCESS_ALLOWED_ACE     ace;
3605
3606     acl_info.AceCount = 0;
3607     GetAclInformation(acl, &acl_info, sizeof(acl_info), AclSizeInformation);
3608     for (i = 0; i < acl_info.AceCount; i++)
3609     {
3610         GetAce(acl, i, (LPVOID *)&ace);
3611         if (ace->Header.AceFlags & INHERITED_ACE)
3612             return TRUE;
3613     }
3614     return FALSE;
3615 }
3616 #endif
3617
3618 /*
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.
3622  */
3623     void
3624 mch_set_acl(char_u *fname, vim_acl_T acl)
3625 {
3626 #ifdef HAVE_ACL
3627     struct my_acl   *p = (struct my_acl *)acl;
3628     SECURITY_INFORMATION    sec_info = 0;
3629
3630     if (p != NULL)
3631     {
3632 # ifdef FEAT_MBYTE
3633         WCHAR   *wn = NULL;
3634 # endif
3635
3636         /* Set security flags */
3637         if (p->pSidOwner)
3638             sec_info |= OWNER_SECURITY_INFORMATION;
3639         if (p->pSidGroup)
3640             sec_info |= GROUP_SECURITY_INFORMATION;
3641         if (p->pDacl)
3642         {
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.
3646              */
3647             if (!is_acl_inherited(p->pDacl))
3648                 sec_info |= PROTECTED_DACL_SECURITY_INFORMATION;
3649         }
3650         if (p->pSacl)
3651             sec_info |= SACL_SECURITY_INFORMATION;
3652
3653 # ifdef FEAT_MBYTE
3654         if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3655             wn = enc_to_utf16(fname, NULL);
3656         if (wn != NULL)
3657         {
3658             (void)SetNamedSecurityInfoW(
3659                         wn,                     // Abstract filename
3660                         SE_FILE_OBJECT,         // File Object
3661                         sec_info,
3662                         p->pSidOwner,           // Ownership information.
3663                         p->pSidGroup,           // Group membership.
3664                         p->pDacl,               // Discretionary information.
3665                         p->pSacl                // For auditing purposes.
3666                         );
3667             vim_free(wn);
3668         }
3669         else
3670 # endif
3671         {
3672             (void)SetNamedSecurityInfo(
3673                         (LPSTR)fname,           // Abstract filename
3674                         SE_FILE_OBJECT,         // File Object
3675                         sec_info,
3676                         p->pSidOwner,           // Ownership information.
3677                         p->pSidGroup,           // Group membership.
3678                         p->pDacl,               // Discretionary information.
3679                         p->pSacl                // For auditing purposes.
3680                         );
3681         }
3682     }
3683 #endif
3684 }
3685
3686     void
3687 mch_free_acl(vim_acl_T acl)
3688 {
3689 #ifdef HAVE_ACL
3690     struct my_acl   *p = (struct my_acl *)acl;
3691
3692     if (p != NULL)
3693     {
3694         LocalFree(p->pSecurityDescriptor);      // Free the memory just in case
3695         vim_free(p);
3696     }
3697 #endif
3698 }
3699
3700 #ifndef FEAT_GUI_W32
3701
3702 /*
3703  * handler for ctrl-break, ctrl-c interrupts, and fatal events.
3704  */
3705     static BOOL WINAPI
3706 handler_routine(
3707     DWORD dwCtrlType)
3708 {
3709     switch (dwCtrlType)
3710     {
3711     case CTRL_C_EVENT:
3712         if (ctrl_c_interrupts)
3713             g_fCtrlCPressed = TRUE;
3714         return TRUE;
3715
3716     case CTRL_BREAK_EVENT:
3717         g_fCBrkPressed  = TRUE;
3718         return TRUE;
3719
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;
3726
3727         vim_snprintf((char *)IObuff, IOSIZE, _("Vim: Caught %s event\n"),
3728                 (dwCtrlType == CTRL_CLOSE_EVENT
3729                      ? _("close")
3730                      : dwCtrlType == CTRL_LOGOFF_EVENT
3731                          ? _("logoff")
3732                          : _("shutdown")));
3733 #ifdef DEBUG
3734         OutputDebugString(IObuff);
3735 #endif
3736
3737         preserve_exit();        /* output IObuff, preserve files and exit */
3738
3739         return TRUE;            /* not reached */
3740
3741     default:
3742         return FALSE;
3743     }
3744 }
3745
3746
3747 /*
3748  * set the tty in (raw) ? "raw" : "cooked" mode
3749  */
3750     void
3751 mch_settmode(int tmode)
3752 {
3753     DWORD cmodein;
3754     DWORD cmodeout;
3755     BOOL bEnableHandler;
3756
3757     GetConsoleMode(g_hConIn, &cmodein);
3758     GetConsoleMode(g_hConOut, &cmodeout);
3759     if (tmode == TMODE_RAW)
3760     {
3761         cmodein &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
3762                      ENABLE_ECHO_INPUT);
3763 #ifdef FEAT_MOUSE
3764         if (g_fMouseActive)
3765             cmodein |= ENABLE_MOUSE_INPUT;
3766 #endif
3767         cmodeout &= ~(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
3768         bEnableHandler = TRUE;
3769     }
3770     else /* cooked */
3771     {
3772         cmodein |= (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
3773                     ENABLE_ECHO_INPUT);
3774         cmodeout |= (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
3775         bEnableHandler = FALSE;
3776     }
3777     SetConsoleMode(g_hConIn, cmodein);
3778     SetConsoleMode(g_hConOut, cmodeout);
3779     SetConsoleCtrlHandler(handler_routine, bEnableHandler);
3780
3781 #ifdef MCH_WRITE_DUMP
3782     if (fdDump)
3783     {
3784         fprintf(fdDump, "mch_settmode(%s, in = %x, out = %x)\n",
3785                 tmode == TMODE_RAW ? "raw" :
3786                                     tmode == TMODE_COOK ? "cooked" : "normal",
3787                 cmodein, cmodeout);
3788         fflush(fdDump);
3789     }
3790 #endif
3791 }
3792
3793
3794 /*
3795  * Get the size of the current window in `Rows' and `Columns'
3796  * Return OK when size could be determined, FAIL otherwise.
3797  */
3798     int
3799 mch_get_shellsize(void)
3800 {
3801     CONSOLE_SCREEN_BUFFER_INFO csbi;
3802
3803     if (!g_fTermcapMode && g_cbTermcap.IsValid)
3804     {
3805         /*
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.
3810          */
3811         Rows = g_cbTermcap.Info.dwSize.Y;
3812         Columns = g_cbTermcap.Info.dwSize.X;
3813     }
3814     else if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
3815     {
3816         Rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3817         Columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3818     }
3819     else
3820     {
3821         Rows = 25;
3822         Columns = 80;
3823     }
3824     return OK;
3825 }
3826
3827 /*
3828  * Set a console window to `xSize' * `ySize'
3829  */
3830     static void
3831 ResizeConBufAndWindow(
3832     HANDLE  hConsole,
3833     int     xSize,
3834     int     ySize)
3835 {
3836     CONSOLE_SCREEN_BUFFER_INFO csbi;    /* hold current console buffer info */
3837     SMALL_RECT      srWindowRect;       /* hold the new console size */
3838     COORD           coordScreen;
3839
3840 #ifdef MCH_WRITE_DUMP
3841     if (fdDump)
3842     {
3843         fprintf(fdDump, "ResizeConBufAndWindow(%d, %d)\n", xSize, ySize);
3844         fflush(fdDump);
3845     }
3846 #endif
3847
3848     /* get the largest size we can size the console window to */
3849     coordScreen = GetLargestConsoleWindowSize(hConsole);
3850
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);
3855
3856     if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
3857     {
3858         int sx, sy;
3859
3860         sx = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3861         sy = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3862         if (sy < ySize || sx < xSize)
3863         {
3864             /*
3865              * Increasing number of lines/columns, do buffer first.
3866              * Use the maximal size in x and y direction.
3867              */
3868             if (sy < ySize)
3869                 coordScreen.Y = ySize;
3870             else
3871                 coordScreen.Y = sy;
3872             if (sx < xSize)
3873                 coordScreen.X = xSize;
3874             else
3875                 coordScreen.X = sx;
3876             SetConsoleScreenBufferSize(hConsole, coordScreen);
3877         }
3878     }
3879
3880     if (!SetConsoleWindowInfo(g_hConOut, TRUE, &srWindowRect))
3881     {
3882 #ifdef MCH_WRITE_DUMP
3883         if (fdDump)
3884         {
3885             fprintf(fdDump, "SetConsoleWindowInfo failed: %lx\n",
3886                     GetLastError());
3887             fflush(fdDump);
3888         }
3889 #endif
3890     }
3891
3892     /* define the new console buffer size */
3893     coordScreen.X = xSize;
3894     coordScreen.Y = ySize;
3895
3896     if (!SetConsoleScreenBufferSize(hConsole, coordScreen))
3897     {
3898 #ifdef MCH_WRITE_DUMP
3899         if (fdDump)
3900         {
3901             fprintf(fdDump, "SetConsoleScreenBufferSize failed: %lx\n",
3902                     GetLastError());
3903             fflush(fdDump);
3904         }
3905 #endif
3906     }
3907 }
3908
3909
3910 /*
3911  * Set the console window to `Rows' * `Columns'
3912  */
3913     void
3914 mch_set_shellsize(void)
3915 {
3916     COORD coordScreen;
3917
3918     /* Don't change window size while still starting up */
3919     if (suppress_winsize != 0)
3920     {
3921         suppress_winsize = 2;
3922         return;
3923     }
3924
3925     if (term_console)
3926     {
3927         coordScreen = GetLargestConsoleWindowSize(g_hConOut);
3928
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;
3934
3935         ResizeConBufAndWindow(g_hConOut, Columns, Rows);
3936     }
3937 }
3938
3939 /*
3940  * Rows and/or Columns has changed.
3941  */
3942     void
3943 mch_new_shellsize(void)
3944 {
3945     set_scroll_region(0, 0, Columns - 1, Rows - 1);
3946 }
3947
3948
3949 /*
3950  * Called when started up, to set the winsize that was delayed.
3951  */
3952     void
3953 mch_set_winsize_now(void)
3954 {
3955     if (suppress_winsize == 2)
3956     {
3957         suppress_winsize = 0;
3958         mch_set_shellsize();
3959         shell_resized();
3960     }
3961     suppress_winsize = 0;
3962 }
3963 #endif /* FEAT_GUI_W32 */
3964
3965     static BOOL
3966 vim_create_process(
3967     char                *cmd,
3968     BOOL                inherit_handles,
3969     DWORD               flags,
3970     STARTUPINFO         *si,
3971     PROCESS_INFORMATION *pi)
3972 {
3973 #ifdef FEAT_MBYTE
3974     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3975     {
3976         WCHAR   *wcmd = enc_to_utf16((char_u *)cmd, NULL);
3977
3978         if (wcmd != NULL)
3979         {
3980             BOOL ret;
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 */
3992             vim_free(wcmd);
3993             return ret;
3994         }
3995     }
3996 #endif
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 */
4008 }
4009
4010
4011     static HINSTANCE
4012 vim_shell_execute(
4013     char *cmd,
4014     INT  n_show_cmd)
4015 {
4016 #ifdef FEAT_MBYTE
4017     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4018     {
4019         WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL);
4020         if (wcmd != NULL)
4021         {
4022             HINSTANCE ret;
4023             ret = ShellExecuteW(NULL, NULL, wcmd, NULL, NULL, n_show_cmd);
4024             vim_free(wcmd);
4025             return ret;
4026         }
4027     }
4028 #endif
4029     return ShellExecute(NULL, NULL, cmd, NULL, NULL, n_show_cmd);
4030 }
4031
4032
4033 #if defined(FEAT_GUI_W32) || defined(PROTO)
4034
4035 /*
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
4042  */
4043     static int
4044 mch_system_classic(char *cmd, int options)
4045 {
4046     STARTUPINFO         si;
4047     PROCESS_INFORMATION pi;
4048     DWORD               ret = 0;
4049     HWND                hwnd = GetFocus();
4050
4051     si.cb = sizeof(si);
4052     si.lpReserved = NULL;
4053     si.lpDesktop = NULL;
4054     si.lpTitle = NULL;
4055     si.dwFlags = STARTF_USESHOWWINDOW;
4056     /*
4057      * It's nicer to run a filter command in a minimized window.
4058      * Don't activate the window to keep focus on Vim.
4059      */
4060     if (options & SHELL_DOOUT)
4061         si.wShowWindow = SW_SHOWMINNOACTIVE;
4062     else
4063         si.wShowWindow = SW_SHOWNORMAL;
4064     si.cbReserved2 = 0;
4065     si.lpReserved2 = NULL;
4066
4067     /* Now, run the command */
4068     vim_create_process(cmd, FALSE,
4069             CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE, &si, &pi);
4070
4071     /* Wait for the command to terminate before continuing */
4072     {
4073 #ifdef FEAT_GUI
4074         int         delay = 1;
4075
4076         /* Keep updating the window while waiting for the shell to finish. */
4077         for (;;)
4078         {
4079             MSG msg;
4080
4081             if (pPeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
4082             {
4083                 TranslateMessage(&msg);
4084                 pDispatchMessage(&msg);
4085                 delay = 1;
4086                 continue;
4087             }
4088             if (WaitForSingleObject(pi.hProcess, delay) != WAIT_TIMEOUT)
4089                 break;
4090
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. */
4094             if (delay < 50)
4095                 delay += 10;
4096         }
4097 #else
4098         WaitForSingleObject(pi.hProcess, INFINITE);
4099 #endif
4100
4101         /* Get the command exit code */
4102         GetExitCodeProcess(pi.hProcess, &ret);
4103     }
4104
4105     /* Close the handles to the subprocess, so that it goes away */
4106     CloseHandle(pi.hThread);
4107     CloseHandle(pi.hProcess);
4108
4109     /* Try to get input focus back.  Doesn't always work though. */
4110     PostMessage(hwnd, WM_SETFOCUS, 0, 0);
4111
4112     return ret;
4113 }
4114
4115 /*
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.
4119  */
4120     static unsigned int __stdcall
4121 sub_process_writer(LPVOID param)
4122 {
4123     HANDLE          g_hChildStd_IN_Wr = param;
4124     linenr_T        lnum = curbuf->b_op_start.lnum;
4125     DWORD           len = 0;
4126     DWORD           l;
4127     char_u          *lp = ml_get(lnum);
4128     char_u          *s;
4129     int             written = 0;
4130
4131     for (;;)
4132     {
4133         l = (DWORD)STRLEN(lp + written);
4134         if (l == 0)
4135             len = 0;
4136         else if (lp[written] == NL)
4137         {
4138             /* NL -> NUL translation */
4139             WriteFile(g_hChildStd_IN_Wr, "", 1, &len, NULL);
4140         }
4141         else
4142         {
4143             s = vim_strchr(lp + written, NL);
4144             WriteFile(g_hChildStd_IN_Wr, (char *)lp + written,
4145                       s == NULL ? l : (DWORD)(s - (lp + written)),
4146                       &len, NULL);
4147         }
4148         if (len == (int)l)
4149         {
4150             /* Finished a line, add a NL, unless this line should not have
4151              * one. */
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)))
4158             {
4159                 WriteFile(g_hChildStd_IN_Wr, "\n", 1, (LPDWORD)&ignored, NULL);
4160             }
4161
4162             ++lnum;
4163             if (lnum > curbuf->b_op_end.lnum)
4164                 break;
4165
4166             lp = ml_get(lnum);
4167             written = 0;
4168         }
4169         else if (len > 0)
4170             written += len;
4171     }
4172
4173     /* finished all the lines, close pipe */
4174     CloseHandle(g_hChildStd_IN_Wr);
4175     return 0;
4176 }
4177
4178
4179 # define BUFLEN 100     /* length for buffer, stolen from unix version */
4180
4181 /*
4182  * This function read from the children's stdout and write the
4183  * data on screen or in the buffer accordingly.
4184  */
4185     static void
4186 dump_pipe(int       options,
4187           HANDLE    g_hChildStd_OUT_Rd,
4188           garray_T  *ga,
4189           char_u    buffer[],
4190           DWORD     *buffer_off)
4191 {
4192     DWORD       availableBytes = 0;
4193     DWORD       i;
4194     int         ret;
4195     DWORD       len;
4196     DWORD       toRead;
4197     int         repeatCount;
4198
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 */
4207
4208     repeatCount = 0;
4209     /* We got real data in the pipe, read it */
4210     while (ret != 0 && availableBytes > 0)
4211     {
4212         repeatCount++;
4213         toRead =
4214 # ifdef FEAT_MBYTE
4215                  (DWORD)(BUFLEN - *buffer_off);
4216 # else
4217                  (DWORD)BUFLEN;
4218 # endif
4219         toRead = availableBytes < toRead ? availableBytes : toRead;
4220         ReadFile(g_hChildStd_OUT_Rd, buffer
4221 # ifdef FEAT_MBYTE
4222                  + *buffer_off, toRead
4223 # else
4224                  , toRead
4225 # endif
4226                  , &len, NULL);
4227
4228         /* If we haven't read anything, there is a problem */
4229         if (len == 0)
4230             break;
4231
4232         availableBytes -= len;
4233
4234         if (options & SHELL_READ)
4235         {
4236             /* Do NUL -> NL translation, append NL separated
4237              * lines to the current buffer. */
4238             for (i = 0; i < len; ++i)
4239             {
4240                 if (buffer[i] == NL)
4241                     append_ga_line(ga);
4242                 else if (buffer[i] == NUL)
4243                     ga_append(ga, NL);
4244                 else
4245                     ga_append(ga, buffer[i]);
4246             }
4247         }
4248 # ifdef FEAT_MBYTE
4249         else if (has_mbyte)
4250         {
4251             int         l;
4252             int         c;
4253             char_u      *p;
4254
4255             len += *buffer_off;
4256             buffer[len] = NUL;
4257
4258             /* Check if the last character in buffer[] is
4259              * incomplete, keep these bytes for the next
4260              * round. */
4261             for (p = buffer; p < buffer + len; p += l)
4262             {
4263                 l = MB_CPTR2LEN(p);
4264                 if (l == 0)
4265                     l = 1;  /* NUL byte? */
4266                 else if (MB_BYTE2LEN(*p) != l)
4267                     break;
4268             }
4269             if (p == buffer)    /* no complete character */
4270             {
4271                 /* avoid getting stuck at an illegal byte */
4272                 if (len >= 12)
4273                     ++p;
4274                 else
4275                 {
4276                     *buffer_off = len;
4277                     return;
4278                 }
4279             }
4280             c = *p;
4281             *p = NUL;
4282             msg_puts(buffer);
4283             if (p < buffer + len)
4284             {
4285                 *p = c;
4286                 *buffer_off = (DWORD)((buffer + len) - p);
4287                 mch_memmove(buffer, p, *buffer_off);
4288                 return;
4289             }
4290             *buffer_off = 0;
4291         }
4292 # endif /* FEAT_MBYTE */
4293         else
4294         {
4295             buffer[len] = NUL;
4296             msg_puts(buffer);
4297         }
4298
4299         windgoto(msg_row, msg_col);
4300         cursor_on();
4301         out_flush();
4302     }
4303 }
4304
4305 /*
4306  * Version of system to use for windows NT > 5.0 (Win2K), use pipe
4307  * for communication and doesn't open any new window.
4308  */
4309     static int
4310 mch_system_piped(char *cmd, int options)
4311 {
4312     STARTUPINFO         si;
4313     PROCESS_INFORMATION pi;
4314     DWORD               ret = 0;
4315
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;
4320
4321     char_u      buffer[BUFLEN + 1]; /* reading buffer + size */
4322     DWORD       len;
4323
4324     /* buffer used to receive keys */
4325     char_u      ta_buf[BUFLEN + 1];     /* TypeAHead */
4326     int         ta_len = 0;             /* valid bytes in ta_buf[] */
4327
4328     DWORD       i;
4329     int         c;
4330     int         noread_cnt = 0;
4331     garray_T    ga;
4332     int     delay = 1;
4333     DWORD       buffer_off = 0; /* valid bytes in buffer[] */
4334     char        *p = NULL;
4335
4336     SECURITY_ATTRIBUTES saAttr;
4337
4338     /* Set the bInheritHandle flag so pipe handles are inherited. */
4339     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
4340     saAttr.bInheritHandle = TRUE;
4341     saAttr.lpSecurityDescriptor = NULL;
4342
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) )
4350     {
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"));
4356     }
4357
4358     si.cb = sizeof(si);
4359     si.lpReserved = NULL;
4360     si.lpDesktop = NULL;
4361     si.lpTitle = NULL;
4362     si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
4363
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;
4369     si.cbReserved2 = 0;
4370     si.lpReserved2 = NULL;
4371
4372     if (options & SHELL_READ)
4373         ga_init2(&ga, 1, BUFLEN);
4374
4375     if (cmd != NULL)
4376     {
4377         p = (char *)vim_strsave((char_u *)cmd);
4378         if (p != NULL)
4379             unescape_shellxquote((char_u *)p, p_sxe);
4380         else
4381             p = cmd;
4382     }
4383
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);
4389
4390     if (p != cmd)
4391         vim_free(p);
4392
4393     /* Close our unused side of the pipes */
4394     CloseHandle(g_hChildStd_IN_Rd);
4395     CloseHandle(g_hChildStd_OUT_Wr);
4396
4397     if (options & SHELL_WRITE)
4398     {
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;
4408     }
4409
4410     /* Keep updating the window while waiting for the shell to finish. */
4411     for (;;)
4412     {
4413         MSG     msg;
4414
4415         if (pPeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
4416         {
4417             TranslateMessage(&msg);
4418             pDispatchMessage(&msg);
4419         }
4420
4421         /* write pipe information in the window */
4422         if ((options & (SHELL_READ|SHELL_WRITE))
4423 # ifdef FEAT_GUI
4424                 || gui.in_use
4425 # endif
4426             )
4427         {
4428             len = 0;
4429             if (!(options & SHELL_EXPAND)
4430                 && ((options &
4431                         (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4432                     != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4433 # ifdef FEAT_GUI
4434                     || gui.in_use
4435 # endif
4436                     )
4437                 && (ta_len > 0 || noread_cnt > 4))
4438             {
4439                 if (ta_len == 0)
4440                 {
4441                     /* Get extra characters when we don't have any.  Reset the
4442                      * counter and timer. */
4443                     noread_cnt = 0;
4444                     len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4445                 }
4446                 if (ta_len > 0 || len > 0)
4447                 {
4448                     /*
4449                      * For pipes: Check for CTRL-C: send interrupt signal to
4450                      * child.  Check for CTRL-D: EOF, close pipe to child.
4451                      */
4452                     if (len == 1 && cmd != NULL)
4453                     {
4454                         if (ta_buf[ta_len] == Ctrl_C)
4455                         {
4456                             /* Learn what exit code is expected, for
4457                                 * now put 9 as SIGKILL */
4458                             TerminateProcess(pi.hProcess, 9);
4459                         }
4460                         if (ta_buf[ta_len] == Ctrl_D)
4461                         {
4462                             CloseHandle(g_hChildStd_IN_Wr);
4463                             g_hChildStd_IN_Wr = NULL;
4464                         }
4465                     }
4466
4467                     /* replace K_BS by <BS> and K_DEL by <DEL> */
4468                     for (i = ta_len; i < ta_len + len; ++i)
4469                     {
4470                         if (ta_buf[i] == CSI && len - i > 2)
4471                         {
4472                             c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4473                             if (c == K_DEL || c == K_KDEL || c == K_BS)
4474                             {
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)
4478                                     ta_buf[i] = DEL;
4479                                 else
4480                                     ta_buf[i] = Ctrl_H;
4481                                 len -= 2;
4482                             }
4483                         }
4484                         else if (ta_buf[i] == '\r')
4485                             ta_buf[i] = '\n';
4486 # ifdef FEAT_MBYTE
4487                         if (has_mbyte)
4488                             i += (*mb_ptr2len_len)(ta_buf + i,
4489                                                     ta_len + len - i) - 1;
4490 # endif
4491                     }
4492
4493                     /*
4494                      * For pipes: echo the typed characters.  For a pty this
4495                      * does not seem to work.
4496                      */
4497                     for (i = ta_len; i < ta_len + len; ++i)
4498                     {
4499                         if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4500                             msg_putchar(ta_buf[i]);
4501 # ifdef FEAT_MBYTE
4502                         else if (has_mbyte)
4503                         {
4504                             int l = (*mb_ptr2len)(ta_buf + i);
4505
4506                             msg_outtrans_len(ta_buf + i, l);
4507                             i += l - 1;
4508                         }
4509 # endif
4510                         else
4511                             msg_outtrans_len(ta_buf + i, 1);
4512                     }
4513                     windgoto(msg_row, msg_col);
4514                     out_flush();
4515
4516                     ta_len += len;
4517
4518                     /*
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
4523                      * CTRL-C).
4524                      */
4525                     if (options & SHELL_WRITE)
4526                         ta_len = 0;
4527                     else if (g_hChildStd_IN_Wr != NULL)
4528                     {
4529                         WriteFile(g_hChildStd_IN_Wr, (char*)ta_buf,
4530                                     1, &len, NULL);
4531                         // if we are typing in, we want to keep things reactive
4532                         delay = 1;
4533                         if (len > 0)
4534                         {
4535                             ta_len -= len;
4536                             mch_memmove(ta_buf, ta_buf + len, ta_len);
4537                         }
4538                     }
4539                 }
4540             }
4541         }
4542
4543         if (ta_len)
4544             ui_inchar_undo(ta_buf, ta_len);
4545
4546         if (WaitForSingleObject(pi.hProcess, delay) != WAIT_TIMEOUT)
4547         {
4548             dump_pipe(options, g_hChildStd_OUT_Rd, &ga, buffer, &buffer_off);
4549             break;
4550         }
4551
4552         ++noread_cnt;
4553         dump_pipe(options, g_hChildStd_OUT_Rd, &ga, buffer, &buffer_off);
4554
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. */
4558         if (delay < 50)
4559             delay += 10;
4560     }
4561
4562     /* Close the pipe */
4563     CloseHandle(g_hChildStd_OUT_Rd);
4564     if (g_hChildStd_IN_Wr != NULL)
4565         CloseHandle(g_hChildStd_IN_Wr);
4566
4567     WaitForSingleObject(pi.hProcess, INFINITE);
4568
4569     /* Get the command exit code */
4570     GetExitCodeProcess(pi.hProcess, &ret);
4571
4572     if (options & SHELL_READ)
4573     {
4574         if (ga.ga_len > 0)
4575         {
4576             append_ga_line(&ga);
4577             /* remember that the NL was missing */
4578             curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
4579         }
4580         else
4581             curbuf->b_no_eol_lnum = 0;
4582         ga_clear(&ga);
4583     }
4584
4585     /* Close the handles to the subprocess, so that it goes away */
4586     CloseHandle(pi.hThread);
4587     CloseHandle(pi.hProcess);
4588
4589     return ret;
4590 }
4591
4592     static int
4593 mch_system(char *cmd, int options)
4594 {
4595     /* if we can pipe and the shelltemp option is off */
4596     if (!p_stmp)
4597         return mch_system_piped(cmd, options);
4598     else
4599         return mch_system_classic(cmd, options);
4600 }
4601 #else
4602
4603 # ifdef FEAT_MBYTE
4604     static int
4605 mch_system(char *cmd, int options)
4606 {
4607     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4608     {
4609         WCHAR   *wcmd = enc_to_utf16((char_u *)cmd, NULL);
4610         if (wcmd != NULL)
4611         {
4612             int ret = _wsystem(wcmd);
4613             vim_free(wcmd);
4614             return ret;
4615         }
4616     }
4617     return system(cmd);
4618 }
4619 # else
4620 #  define mch_system(c, o) system(c)
4621 # endif
4622
4623 #endif
4624
4625 /*
4626  * Either execute a command by calling the shell or start a new shell
4627  */
4628     int
4629 mch_call_shell(
4630     char_u  *cmd,
4631     int     options)    /* SHELL_*, see vim.h */
4632 {
4633     int         x = 0;
4634     int         tmode = cur_tmode;
4635 #ifdef FEAT_TITLE
4636     char        szShellTitle[512];
4637 # ifdef FEAT_MBYTE
4638     int         did_set_title = FALSE;
4639
4640     /* Change the title to reflect that we are in a subshell. */
4641     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4642     {
4643         WCHAR szShellTitle[512];
4644
4645         if (GetConsoleTitleW(szShellTitle,
4646                                   sizeof(szShellTitle)/sizeof(WCHAR) - 4) > 0)
4647         {
4648             if (cmd == NULL)
4649                 wcscat(szShellTitle, L" :sh");
4650             else
4651             {
4652                 WCHAR *wn = enc_to_utf16((char_u *)cmd, NULL);
4653
4654                 if (wn != NULL)
4655                 {
4656                     wcscat(szShellTitle, L" - !");
4657                     if ((wcslen(szShellTitle) + wcslen(wn) <
4658                                           sizeof(szShellTitle)/sizeof(WCHAR)))
4659                         wcscat(szShellTitle, wn);
4660                     SetConsoleTitleW(szShellTitle);
4661                     vim_free(wn);
4662                     did_set_title = TRUE;
4663                 }
4664             }
4665         }
4666     }
4667     if (!did_set_title)
4668 # endif
4669         /* Change the title to reflect that we are in a subshell. */
4670         if (GetConsoleTitle(szShellTitle, sizeof(szShellTitle) - 4) > 0)
4671         {
4672             if (cmd == NULL)
4673                 strcat(szShellTitle, " :sh");
4674             else
4675             {
4676                 strcat(szShellTitle, " - !");
4677                 if ((strlen(szShellTitle) + strlen((char *)cmd)
4678                             < sizeof(szShellTitle)))
4679                     strcat(szShellTitle, (char *)cmd);
4680             }
4681             SetConsoleTitle(szShellTitle);
4682         }
4683 #endif
4684
4685     out_flush();
4686
4687 #ifdef MCH_WRITE_DUMP
4688     if (fdDump)
4689     {
4690         fprintf(fdDump, "mch_call_shell(\"%s\", %d)\n", cmd, options);
4691         fflush(fdDump);
4692     }
4693 #endif
4694
4695     /*
4696      * Catch all deadly signals while running the external command, because a
4697      * CTRL-C, Ctrl-Break or illegal instruction  might otherwise kill us.
4698      */
4699     signal(SIGINT, SIG_IGN);
4700 #if defined(__GNUC__) && !defined(__MINGW32__)
4701     signal(SIGKILL, SIG_IGN);
4702 #else
4703     signal(SIGBREAK, SIG_IGN);
4704 #endif
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);
4710
4711     if (options & SHELL_COOKED)
4712         settmode(TMODE_COOK);   /* set to normal mode */
4713
4714     if (cmd == NULL)
4715     {
4716         x = mch_system((char *)p_sh, options);
4717     }
4718     else
4719     {
4720         /* we use "command" or "cmd" to start the shell; slow but easy */
4721         char_u  *newcmd = NULL;
4722         char_u  *cmdbase = cmd;
4723         long_u  cmdlen;
4724
4725         /* Skip a leading ", ( and "(. */
4726         if (*cmdbase == '"' )
4727             ++cmdbase;
4728         if (*cmdbase == '(')
4729             ++cmdbase;
4730
4731         if ((STRNICMP(cmdbase, "start", 5) == 0) && VIM_ISWHITE(cmdbase[5]))
4732         {
4733             STARTUPINFO         si;
4734             PROCESS_INFORMATION pi;
4735             DWORD               flags = CREATE_NEW_CONSOLE;
4736             INT                 n_show_cmd = SW_SHOWNORMAL;
4737             char_u              *p;
4738
4739             ZeroMemory(&si, sizeof(si));
4740             si.cb = sizeof(si);
4741             si.lpReserved = NULL;
4742             si.lpDesktop = NULL;
4743             si.lpTitle = NULL;
4744             si.dwFlags = 0;
4745             si.cbReserved2 = 0;
4746             si.lpReserved2 = NULL;
4747
4748             cmdbase = skipwhite(cmdbase + 5);
4749             if ((STRNICMP(cmdbase, "/min", 4) == 0)
4750                     && VIM_ISWHITE(cmdbase[4]))
4751             {
4752                 cmdbase = skipwhite(cmdbase + 4);
4753                 si.dwFlags = STARTF_USESHOWWINDOW;
4754                 si.wShowWindow = SW_SHOWMINNOACTIVE;
4755                 n_show_cmd = SW_SHOWMINNOACTIVE;
4756             }
4757             else if ((STRNICMP(cmdbase, "/b", 2) == 0)
4758                     && VIM_ISWHITE(cmdbase[2]))
4759             {
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
4765                     0,                                  // Share flags
4766                     NULL,                               // Security att.
4767                     OPEN_EXISTING,                      // Open flags
4768                     FILE_ATTRIBUTE_NORMAL,              // File att.
4769                     NULL);                              // Temp file
4770                 si.hStdOutput = si.hStdInput;
4771                 si.hStdError = si.hStdInput;
4772             }
4773
4774             /* Remove a trailing ", ) and )" if they have a match
4775              * at the start of the command. */
4776             if (cmdbase > cmd)
4777             {
4778                 p = cmdbase + STRLEN(cmdbase);
4779                 if (p > cmdbase && p[-1] == '"' && *cmd == '"')
4780                     *--p = NUL;
4781                 if (p > cmdbase && p[-1] == ')'
4782                         && (*cmd =='(' || cmd[1] == '('))
4783                     *--p = NUL;
4784             }
4785
4786             newcmd = cmdbase;
4787             unescape_shellxquote(cmdbase, p_sxe);
4788
4789             /*
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.
4795              */
4796             if (flags != CREATE_NEW_CONSOLE)
4797             {
4798                 char_u  *subcmd;
4799                 char_u  *cmd_shell = mch_getenv("COMSPEC");
4800
4801                 if (cmd_shell == NULL || *cmd_shell == NUL)
4802                     cmd_shell = (char_u *)default_shell();
4803
4804                 subcmd = vim_strsave_escaped_ext(cmdbase,
4805                         (char_u *)"|", '^', FALSE);
4806                 if (subcmd != NULL)
4807                 {
4808                     /* make "cmd.exe /c arguments" */
4809                     cmdlen = STRLEN(cmd_shell) + STRLEN(subcmd) + 5;
4810                     newcmd = lalloc(cmdlen, TRUE);
4811                     if (newcmd != NULL)
4812                         vim_snprintf((char *)newcmd, cmdlen, "%s /c %s",
4813                                                        cmd_shell, subcmd);
4814                     else
4815                         newcmd = cmdbase;
4816                     vim_free(subcmd);
4817                 }
4818             }
4819
4820             /*
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
4824              */
4825             if (vim_create_process((char *)newcmd, FALSE, flags, &si, &pi))
4826                 x = 0;
4827             else if (vim_shell_execute((char *)newcmd, n_show_cmd)
4828                                                                > (HINSTANCE)32)
4829                 x = 0;
4830             else
4831             {
4832                 x = -1;
4833 #ifdef FEAT_GUI_W32
4834                 EMSG(_("E371: Command not found"));
4835 #endif
4836             }
4837
4838             if (newcmd != cmdbase)
4839                 vim_free(newcmd);
4840
4841             if (si.dwFlags == STARTF_USESTDHANDLES && si.hStdInput != NULL)
4842             {
4843                 /* Close the handle to \\.\NUL created above. */
4844                 CloseHandle(si.hStdInput);
4845             }
4846             /* Close the handles to the subprocess, so that it goes away */
4847             CloseHandle(pi.hThread);
4848             CloseHandle(pi.hProcess);
4849         }
4850         else
4851         {
4852             cmdlen = (
4853 #ifdef FEAT_GUI_W32
4854                 (!p_stmp ? 0 : STRLEN(vimrun_path)) +
4855 #endif
4856                 STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10);
4857
4858             newcmd = lalloc(cmdlen, TRUE);
4859             if (newcmd != NULL)
4860             {
4861 #if defined(FEAT_GUI_W32)
4862                 if (need_vimrun_warning)
4863                 {
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");
4868 # ifdef FEAT_MBYTE
4869                     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4870                     {
4871                         WCHAR *wmsg = enc_to_utf16((char_u *)msg, NULL);
4872                         WCHAR *wtitle = enc_to_utf16((char_u *)title, NULL);
4873
4874                         if (wmsg != NULL && wtitle != NULL)
4875                             MessageBoxW(NULL, wmsg, wtitle, MB_ICONWARNING);
4876                         vim_free(wmsg);
4877                         vim_free(wtitle);
4878                     }
4879                     else
4880 # endif
4881                         MessageBox(NULL, msg, title, MB_ICONWARNING);
4882                     need_vimrun_warning = FALSE;
4883                 }
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",
4888                             vimrun_path,
4889                             (msg_silent != 0 || (options & SHELL_DOOUT))
4890                                                                  ? "-s " : "",
4891                             p_sh, p_shcf, cmd);
4892                 else
4893 #endif
4894                     vim_snprintf((char *)newcmd, cmdlen, "%s %s %s",
4895                                                            p_sh, p_shcf, cmd);
4896                 x = mch_system((char *)newcmd, options);
4897                 vim_free(newcmd);
4898             }
4899         }
4900     }
4901
4902     if (tmode == TMODE_RAW)
4903         settmode(TMODE_RAW);    /* set to raw mode */
4904
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)
4909 #endif
4910             )
4911     {
4912         smsg((char_u *)_("shell returned %d"), x);
4913         msg_putchar('\n');
4914     }
4915 #ifdef FEAT_TITLE
4916     resettitle();
4917 #endif
4918
4919     signal(SIGINT, SIG_DFL);
4920 #if defined(__GNUC__) && !defined(__MINGW32__)
4921     signal(SIGKILL, SIG_DFL);
4922 #else
4923     signal(SIGBREAK, SIG_DFL);
4924 #endif
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);
4930
4931     return x;
4932 }
4933
4934 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
4935     static HANDLE
4936 job_io_file_open(
4937         char_u *fname,
4938         DWORD dwDesiredAccess,
4939         DWORD dwShareMode,
4940         LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4941         DWORD dwCreationDisposition,
4942         DWORD dwFlagsAndAttributes)
4943 {
4944     HANDLE h;
4945 # ifdef FEAT_MBYTE
4946     WCHAR *wn = NULL;
4947     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
4948     {
4949         wn = enc_to_utf16(fname, NULL);
4950         if (wn != NULL)
4951         {
4952             h = CreateFileW(wn, dwDesiredAccess, dwShareMode,
4953                     lpSecurityAttributes, dwCreationDisposition,
4954                     dwFlagsAndAttributes, NULL);
4955             vim_free(wn);
4956         }
4957     }
4958     if (wn == NULL)
4959 # endif
4960         h = CreateFile((LPCSTR)fname, dwDesiredAccess, dwShareMode,
4961                 lpSecurityAttributes, dwCreationDisposition,
4962                 dwFlagsAndAttributes, NULL);
4963     return h;
4964 }
4965
4966     void
4967 mch_start_job(char *cmd, job_T *job, jobopt_T *options)
4968 {
4969     STARTUPINFO         si;
4970     PROCESS_INFORMATION pi;
4971     HANDLE              jo;
4972     SECURITY_ATTRIBUTES saAttr;
4973     channel_T           *channel = NULL;
4974     HANDLE              ifd[2];
4975     HANDLE              ofd[2];
4976     HANDLE              efd[2];
4977
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;
4985
4986     if (use_out_for_err && use_null_for_out)
4987         use_null_for_err = TRUE;
4988
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;
4995
4996     jo = CreateJobObject(NULL, NULL);
4997     if (jo == NULL)
4998     {
4999         job->jv_status = JOB_FAILED;
5000         goto failed;
5001     }
5002
5003     ZeroMemory(&pi, sizeof(pi));
5004     ZeroMemory(&si, sizeof(si));
5005     si.cb = sizeof(si);
5006     si.dwFlags |= STARTF_USESHOWWINDOW;
5007     si.wShowWindow = SW_HIDE;
5008
5009     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
5010     saAttr.bInheritHandle = TRUE;
5011     saAttr.lpSecurityDescriptor = NULL;
5012
5013     if (use_file_for_in)
5014     {
5015         char_u *fname = options->jo_io_name[PART_IN];
5016
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)
5021         {
5022             EMSG2(_(e_notopen), fname);
5023             goto failed;
5024         }
5025     }
5026     else if (!use_null_for_in &&
5027             (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
5028             || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)))
5029         goto failed;
5030
5031     if (use_file_for_out)
5032     {
5033         char_u *fname = options->jo_io_name[PART_OUT];
5034
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)
5039         {
5040             EMSG2(_(e_notopen), fname);
5041             goto failed;
5042         }
5043     }
5044     else if (!use_null_for_out &&
5045             (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
5046             || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)))
5047         goto failed;
5048
5049     if (use_file_for_err)
5050     {
5051         char_u *fname = options->jo_io_name[PART_ERR];
5052
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)
5057         {
5058             EMSG2(_(e_notopen), fname);
5059             goto failed;
5060         }
5061     }
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)))
5065         goto failed;
5066
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];
5071
5072     if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5073     {
5074         if (options->jo_set & JO_CHANNEL)
5075         {
5076             channel = options->jo_channel;
5077             if (channel != NULL)
5078                 ++channel->ch_refcount;
5079         }
5080         else
5081             channel = add_channel();
5082         if (channel == NULL)
5083             goto failed;
5084     }
5085
5086     if (!vim_create_process(cmd, TRUE,
5087             CREATE_SUSPENDED |
5088             CREATE_DEFAULT_ERROR_MODE |
5089             CREATE_NEW_PROCESS_GROUP |
5090             CREATE_NEW_CONSOLE,
5091             &si, &pi))
5092     {
5093         CloseHandle(jo);
5094         job->jv_status = JOB_FAILED;
5095         goto failed;
5096     }
5097
5098     if (!AssignProcessToJobObject(jo, pi.hProcess))
5099     {
5100         /* if failing, switch the way to terminate
5101          * process with TerminateProcess. */
5102         CloseHandle(jo);
5103         jo = NULL;
5104     }
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;
5110
5111     CloseHandle(ifd[0]);
5112     CloseHandle(ofd[1]);
5113     if (!use_out_for_err && !use_null_for_err)
5114         CloseHandle(efd[1]);
5115
5116     job->jv_channel = channel;
5117     if (channel != NULL)
5118     {
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);
5127     }
5128     return;
5129
5130 failed:
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);
5138 }
5139
5140     char *
5141 mch_job_status(job_T *job)
5142 {
5143     DWORD dwExitCode = 0;
5144
5145     if (!GetExitCodeProcess(job->jv_proc_info.hProcess, &dwExitCode)
5146             || dwExitCode != STILL_ACTIVE)
5147     {
5148         job->jv_exitval = (int)dwExitCode;
5149         if (job->jv_status < JOB_ENDED)
5150         {
5151             ch_log(job->jv_channel, "Job ended");
5152             job->jv_status = JOB_ENDED;
5153         }
5154         return "dead";
5155     }
5156     return "run";
5157 }
5158
5159     job_T *
5160 mch_detect_ended_job(job_T *job_list)
5161 {
5162     HANDLE jobHandles[MAXIMUM_WAIT_OBJECTS];
5163     job_T *jobArray[MAXIMUM_WAIT_OBJECTS];
5164     job_T *job = job_list;
5165
5166     while (job != NULL)
5167     {
5168         DWORD n;
5169         DWORD result;
5170
5171         for (n = 0; n < MAXIMUM_WAIT_OBJECTS
5172                                        && job != NULL; job = job->jv_next)
5173         {
5174             if (job->jv_status == JOB_STARTED)
5175             {
5176                 jobHandles[n] = job->jv_proc_info.hProcess;
5177                 jobArray[n] = job;
5178                 ++n;
5179             }
5180         }
5181         if (n == 0)
5182             continue;
5183         result = WaitForMultipleObjects(n, jobHandles, FALSE, 0);
5184         if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + n)
5185         {
5186             job_T *wait_job = jobArray[result - WAIT_OBJECT_0];
5187
5188             if (STRCMP(mch_job_status(wait_job), "dead") == 0)
5189                 return wait_job;
5190         }
5191     }
5192     return NULL;
5193 }
5194
5195     static BOOL
5196 terminate_all(HANDLE process, int code)
5197 {
5198     PROCESSENTRY32  pe;
5199     HANDLE          h = INVALID_HANDLE_VALUE;
5200     DWORD           pid = GetProcessId(process);
5201
5202     if (pid != 0)
5203     {
5204         h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
5205         if (h != INVALID_HANDLE_VALUE)
5206         {
5207             pe.dwSize = sizeof(PROCESSENTRY32);
5208             if (!Process32First(h, &pe))
5209                 goto theend;
5210
5211             do
5212             {
5213                 if (pe.th32ParentProcessID == pid)
5214                 {
5215                     HANDLE ph = OpenProcess(
5216                                   PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
5217                     if (ph != NULL)
5218                     {
5219                         terminate_all(ph, code);
5220                         CloseHandle(ph);
5221                     }
5222                 }
5223             } while (Process32Next(h, &pe));
5224
5225             CloseHandle(h);
5226         }
5227     }
5228
5229 theend:
5230     return TerminateProcess(process, code);
5231 }
5232
5233 /*
5234  * Send a (deadly) signal to "job".
5235  * Return FAIL if it didn't work.
5236  */
5237     int
5238 mch_stop_job(job_T *job, char_u *how)
5239 {
5240     int ret;
5241
5242     if (STRCMP(how, "term") == 0 || STRCMP(how, "kill") == 0 || *how == NUL)
5243     {
5244         /* deadly signal */
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;
5248     }
5249
5250     if (!AttachConsole(job->jv_proc_info.dwProcessId))
5251         return FAIL;
5252     ret = GenerateConsoleCtrlEvent(
5253                 STRCMP(how, "int") == 0 ? CTRL_C_EVENT : CTRL_BREAK_EVENT,
5254                 job->jv_proc_info.dwProcessId)
5255             ? OK : FAIL;
5256     FreeConsole();
5257     return ret;
5258 }
5259
5260 /*
5261  * Clear the data related to "job".
5262  */
5263     void
5264 mch_clear_job(job_T *job)
5265 {
5266     if (job->jv_status != JOB_FAILED)
5267     {
5268         if (job->jv_job_object != NULL)
5269             CloseHandle(job->jv_job_object);
5270         CloseHandle(job->jv_proc_info.hProcess);
5271     }
5272 }
5273 #endif
5274
5275
5276 #ifndef FEAT_GUI_W32
5277
5278 /*
5279  * Start termcap mode
5280  */
5281     static void
5282 termcap_mode_start(void)
5283 {
5284     DWORD cmodein;
5285
5286     if (g_fTermcapMode)
5287         return;
5288
5289     SaveConsoleBuffer(&g_cbNonTermcap);
5290
5291     if (g_cbTermcap.IsValid)
5292     {
5293         /*
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.
5298          */
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;
5303     }
5304     else
5305     {
5306         /*
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.
5310          */
5311         ClearConsoleBuffer(g_attrCurrent);
5312         ResizeConBufAndWindow(g_hConOut, Columns, Rows);
5313     }
5314
5315 #ifdef FEAT_TITLE
5316     resettitle();
5317 #endif
5318
5319     GetConsoleMode(g_hConIn, &cmodein);
5320 #ifdef FEAT_MOUSE
5321     if (g_fMouseActive)
5322         cmodein |= ENABLE_MOUSE_INPUT;
5323     else
5324         cmodein &= ~ENABLE_MOUSE_INPUT;
5325 #endif
5326     cmodein |= ENABLE_WINDOW_INPUT;
5327     SetConsoleMode(g_hConIn, cmodein);
5328
5329     redraw_later_clear();
5330     g_fTermcapMode = TRUE;
5331 }
5332
5333
5334 /*
5335  * End termcap mode
5336  */
5337     static void
5338 termcap_mode_end(void)
5339 {
5340     DWORD cmodein;
5341     ConsoleBuffer *cb;
5342     COORD coord;
5343     DWORD dwDummy;
5344
5345     if (!g_fTermcapMode)
5346         return;
5347
5348     SaveConsoleBuffer(&g_cbTermcap);
5349
5350     GetConsoleMode(g_hConIn, &cmodein);
5351     cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
5352     SetConsoleMode(g_hConIn, cmodein);
5353
5354 #ifdef FEAT_RESTORE_ORIG_SCREEN
5355     cb = exiting ? &g_cbOrig : &g_cbNonTermcap;
5356 #else
5357     cb = &g_cbNonTermcap;
5358 #endif
5359     RestoreConsoleBuffer(cb, p_rs);
5360     SetConsoleCursorInfo(g_hConOut, &g_cci);
5361
5362     if (p_rs || exiting)
5363     {
5364         /*
5365          * Clear anything that happens to be on the current line.
5366          */
5367         coord.X = 0;
5368         coord.Y = (SHORT) (p_rs ? cb->Info.dwCursorPosition.Y : (Rows - 1));
5369         FillConsoleOutputCharacter(g_hConOut, ' ',
5370                 cb->Info.dwSize.X, coord, &dwDummy);
5371         /*
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.
5378          */
5379         if (exiting && !p_rs)
5380             coord.Y--;
5381         /*
5382          * Position the cursor at the leftmost column of the desired row.
5383          */
5384         SetConsoleCursorPosition(g_hConOut, coord);
5385     }
5386
5387     g_fTermcapMode = FALSE;
5388 }
5389 #endif /* FEAT_GUI_W32 */
5390
5391
5392 #ifdef FEAT_GUI_W32
5393     void
5394 mch_write(
5395     char_u  *s UNUSED,
5396     int     len UNUSED)
5397 {
5398     /* never used */
5399 }
5400
5401 #else
5402
5403 /*
5404  * clear `n' chars, starting from `coord'
5405  */
5406     static void
5407 clear_chars(
5408     COORD coord,
5409     DWORD n)
5410 {
5411     DWORD dwDummy;
5412
5413     FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
5414     FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy);
5415 }
5416
5417
5418 /*
5419  * Clear the screen
5420  */
5421     static void
5422 clear_screen(void)
5423 {
5424     g_coord.X = g_coord.Y = 0;
5425     clear_chars(g_coord, Rows * Columns);
5426 }
5427
5428
5429 /*
5430  * Clear to end of display
5431  */
5432     static void
5433 clear_to_end_of_display(void)
5434 {
5435     clear_chars(g_coord, (Rows - g_coord.Y - 1)
5436                                            * Columns + (Columns - g_coord.X));
5437 }
5438
5439
5440 /*
5441  * Clear to end of line
5442  */
5443     static void
5444 clear_to_end_of_line(void)
5445 {
5446     clear_chars(g_coord, Columns - g_coord.X);
5447 }
5448
5449
5450 /*
5451  * Scroll the scroll region up by `cLines' lines
5452  */
5453     static void
5454 scroll(unsigned cLines)
5455 {
5456     COORD oldcoord = g_coord;
5457
5458     gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Top + 1);
5459     delete_lines(cLines);
5460
5461     g_coord = oldcoord;
5462 }
5463
5464
5465 /*
5466  * Set the scroll region
5467  */
5468     static void
5469 set_scroll_region(
5470     unsigned left,
5471     unsigned top,
5472     unsigned right,
5473     unsigned bottom)
5474 {
5475     if (left >= right
5476             || top >= bottom
5477             || right > (unsigned) Columns - 1
5478             || bottom > (unsigned) Rows - 1)
5479         return;
5480
5481     g_srScrollRegion.Left =   left;
5482     g_srScrollRegion.Top =    top;
5483     g_srScrollRegion.Right =  right;
5484     g_srScrollRegion.Bottom = bottom;
5485 }
5486
5487
5488 /*
5489  * Insert `cLines' lines at the current cursor position
5490  */
5491     static void
5492 insert_lines(unsigned cLines)
5493 {
5494     SMALL_RECT      source;
5495     COORD           dest;
5496     CHAR_INFO       fill;
5497
5498     dest.X = 0;
5499     dest.Y = g_coord.Y + cLines;
5500
5501     source.Left   = 0;
5502     source.Top    = g_coord.Y;
5503     source.Right  = g_srScrollRegion.Right;
5504     source.Bottom = g_srScrollRegion.Bottom - cLines;
5505
5506     fill.Char.AsciiChar = ' ';
5507     fill.Attributes = g_attrCurrent;
5508
5509     ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
5510
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
5516      * direction).  */
5517
5518     if (source.Bottom < dest.Y)
5519     {
5520         COORD coord;
5521
5522         coord.X = 0;
5523         coord.Y = source.Bottom;
5524         clear_chars(coord, Columns * (dest.Y - source.Bottom));
5525     }
5526 }
5527
5528
5529 /*
5530  * Delete `cLines' lines at the current cursor position
5531  */
5532     static void
5533 delete_lines(unsigned cLines)
5534 {
5535     SMALL_RECT      source;
5536     COORD           dest;
5537     CHAR_INFO       fill;
5538     int             nb;
5539
5540     dest.X = 0;
5541     dest.Y = g_coord.Y;
5542
5543     source.Left   = 0;
5544     source.Top    = g_coord.Y + cLines;
5545     source.Right  = g_srScrollRegion.Right;
5546     source.Bottom = g_srScrollRegion.Bottom;
5547
5548     fill.Char.AsciiChar = ' ';
5549     fill.Attributes = g_attrCurrent;
5550
5551     ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
5552
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
5558      * direction).  */
5559
5560     nb = dest.Y + (source.Bottom - source.Top) + 1;
5561
5562     if (nb < source.Top)
5563     {
5564         COORD coord;
5565
5566         coord.X = 0;
5567         coord.Y = nb;
5568         clear_chars(coord, Columns * (source.Top - nb));
5569     }
5570 }
5571
5572
5573 /*
5574  * Set the cursor position
5575  */
5576     static void
5577 gotoxy(
5578     unsigned x,
5579     unsigned y)
5580 {
5581     if (x < 1 || x > (unsigned)Columns || y < 1 || y > (unsigned)Rows)
5582         return;
5583
5584     /* external cursor coords are 1-based; internal are 0-based */
5585     g_coord.X = x - 1;
5586     g_coord.Y = y - 1;
5587     SetConsoleCursorPosition(g_hConOut, g_coord);
5588 }
5589
5590
5591 /*
5592  * Set the current text attribute = (foreground | background)
5593  * See ../doc/os_win32.txt for the numbers.
5594  */
5595     static void
5596 textattr(WORD wAttr)
5597 {
5598     g_attrCurrent = wAttr & 0xff;
5599
5600     SetConsoleTextAttribute(g_hConOut, wAttr);
5601 }
5602
5603
5604     static void
5605 textcolor(WORD wAttr)
5606 {
5607     g_attrCurrent = (g_attrCurrent & 0xf0) + (wAttr & 0x0f);
5608
5609     SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
5610 }
5611
5612
5613     static void
5614 textbackground(WORD wAttr)
5615 {
5616     g_attrCurrent = (g_attrCurrent & 0x0f) + ((wAttr & 0x0f) << 4);
5617
5618     SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
5619 }
5620
5621
5622 /*
5623  * restore the default text attribute (whatever we started with)
5624  */
5625     static void
5626 normvideo(void)
5627 {
5628     textattr(g_attrDefault);
5629 }
5630
5631
5632 static WORD g_attrPreStandout = 0;
5633
5634 /*
5635  * Make the text standout, by brightening it
5636  */
5637     static void
5638 standout(void)
5639 {
5640     g_attrPreStandout = g_attrCurrent;
5641     textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY));
5642 }
5643
5644
5645 /*
5646  * Turn off standout mode
5647  */
5648     static void
5649 standend(void)
5650 {
5651     if (g_attrPreStandout)
5652     {
5653         textattr(g_attrPreStandout);
5654         g_attrPreStandout = 0;
5655     }
5656 }
5657
5658
5659 /*
5660  * Set normal fg/bg color, based on T_ME.  Called when t_me has been set.
5661  */
5662     void
5663 mch_set_normal_colors(void)
5664 {
5665     char_u      *p;
5666     int         n;
5667
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] == '|')
5671     {
5672         p = T_ME + 2;
5673         n = getdigits(&p);
5674         if (*p == 'm' && n > 0)
5675         {
5676             cterm_normal_fg_color = (n & 0xf) + 1;
5677             cterm_normal_bg_color = ((n >> 4) & 0xf) + 1;
5678         }
5679     }
5680 }
5681
5682
5683 /*
5684  * visual bell: flash the screen
5685  */
5686     static void
5687 visual_bell(void)
5688 {
5689     COORD   coordOrigin = {0, 0};
5690     WORD    attrFlash = ~g_attrCurrent & 0xff;
5691
5692     DWORD   dwDummy;
5693     LPWORD  oldattrs = (LPWORD)alloc(Rows * Columns * sizeof(WORD));
5694
5695     if (oldattrs == NULL)
5696         return;
5697     ReadConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
5698                                coordOrigin, &dwDummy);
5699     FillConsoleOutputAttribute(g_hConOut, attrFlash, Rows * Columns,
5700                                coordOrigin, &dwDummy);
5701
5702     Sleep(15);      /* wait for 15 msec */
5703     WriteConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
5704                                 coordOrigin, &dwDummy);
5705     vim_free(oldattrs);
5706 }
5707
5708
5709 /*
5710  * Make the cursor visible or invisible
5711  */
5712     static void
5713 cursor_visible(BOOL fVisible)
5714 {
5715     s_cursor_visible = fVisible;
5716 #ifdef MCH_CURSOR_SHAPE
5717     mch_update_cursor();
5718 #endif
5719 }
5720
5721
5722 /*
5723  * write `cbToWrite' bytes in `pchBuf' to the screen
5724  * Returns the number of bytes actually written (at least one).
5725  */
5726     static DWORD
5727 write_chars(
5728     char_u *pchBuf,
5729     DWORD  cbToWrite)
5730 {
5731     COORD coord = g_coord;
5732     DWORD written;
5733
5734 #ifdef FEAT_MBYTE
5735     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
5736     {
5737         static WCHAR    *unicodebuf = NULL;
5738         static int      unibuflen = 0;
5739         int             length;
5740         DWORD           n, cchwritten, cells;
5741
5742         length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0);
5743         if (unicodebuf == NULL || length > unibuflen)
5744         {
5745             vim_free(unicodebuf);
5746             unicodebuf = (WCHAR *)lalloc(length * sizeof(WCHAR), FALSE);
5747             unibuflen = length;
5748         }
5749         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite,
5750                             unicodebuf, unibuflen);
5751
5752         cells = mb_string2cells(pchBuf, cbToWrite);
5753         FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells,
5754                                     coord, &written);
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
5759                 || cchwritten == 0)
5760             cchwritten = 1;
5761
5762         if (cchwritten == length)
5763         {
5764             written = cbToWrite;
5765             g_coord.X += (SHORT)cells;
5766         }
5767         else
5768         {
5769             char_u *p = pchBuf;
5770             for (n = 0; n < cchwritten; n++)
5771                 MB_CPTR_ADV(p);
5772             written = p - pchBuf;
5773             g_coord.X += (SHORT)mb_string2cells(pchBuf, written);
5774         }
5775     }
5776     else
5777 #endif
5778     {
5779         FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite,
5780                                     coord, &written);
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
5785                 || written == 0)
5786             written = 1;
5787
5788         g_coord.X += (SHORT) written;
5789     }
5790
5791     while (g_coord.X > g_srScrollRegion.Right)
5792     {
5793         g_coord.X -= (SHORT) Columns;
5794         if (g_coord.Y < g_srScrollRegion.Bottom)
5795             g_coord.Y++;
5796     }
5797
5798     gotoxy(g_coord.X + 1, g_coord.Y + 1);
5799
5800     return written;
5801 }
5802
5803
5804 /*
5805  * mch_write(): write the output buffer to the screen, translating ESC
5806  * sequences into calls to console output routines.
5807  */
5808     void
5809 mch_write(
5810     char_u  *s,
5811     int     len)
5812 {
5813     s[len] = NUL;
5814
5815     if (!term_console)
5816     {
5817         write(1, s, (unsigned)len);
5818         return;
5819     }
5820
5821     /* translate ESC | sequences into faked bios calls */
5822     while (len--)
5823     {
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");
5827
5828         if (p_wd)
5829         {
5830             WaitForChar(p_wd);
5831             if (prefix != 0)
5832                 prefix = 1;
5833         }
5834
5835         if (prefix != 0)
5836         {
5837             DWORD nWritten;
5838
5839             nWritten = write_chars(s, prefix);
5840 #ifdef MCH_WRITE_DUMP
5841             if (fdDump)
5842             {
5843                 fputc('>', fdDump);
5844                 fwrite(s, sizeof(char_u), nWritten, fdDump);
5845                 fputs("<\n", fdDump);
5846             }
5847 #endif
5848             len -= (nWritten - 1);
5849             s += nWritten;
5850         }
5851         else if (s[0] == '\n')
5852         {
5853             /* \n, newline: go to the beginning of the next line or scroll */
5854             if (g_coord.Y == g_srScrollRegion.Bottom)
5855             {
5856                 scroll(1);
5857                 gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Bottom + 1);
5858             }
5859             else
5860             {
5861                 gotoxy(g_srScrollRegion.Left + 1, g_coord.Y + 2);
5862             }
5863 #ifdef MCH_WRITE_DUMP
5864             if (fdDump)
5865                 fputs("\\n\n", fdDump);
5866 #endif
5867             s++;
5868         }
5869         else if (s[0] == '\r')
5870         {
5871             /* \r, carriage return: go to beginning of line */
5872             gotoxy(g_srScrollRegion.Left+1, g_coord.Y + 1);
5873 #ifdef MCH_WRITE_DUMP
5874             if (fdDump)
5875                 fputs("\\r\n", fdDump);
5876 #endif
5877             s++;
5878         }
5879         else if (s[0] == '\b')
5880         {
5881             /* \b, backspace: move cursor one position left */
5882             if (g_coord.X > g_srScrollRegion.Left)
5883                 g_coord.X--;
5884             else if (g_coord.Y > g_srScrollRegion.Top)
5885             {
5886                 g_coord.X = g_srScrollRegion.Right;
5887                 g_coord.Y--;
5888             }
5889             gotoxy(g_coord.X + 1, g_coord.Y + 1);
5890 #ifdef MCH_WRITE_DUMP
5891             if (fdDump)
5892                 fputs("\\b\n", fdDump);
5893 #endif
5894             s++;
5895         }
5896         else if (s[0] == '\a')
5897         {
5898             /* \a, bell */
5899             MessageBeep(0xFFFFFFFF);
5900 #ifdef MCH_WRITE_DUMP
5901             if (fdDump)
5902                 fputs("\\a\n", fdDump);
5903 #endif
5904             s++;
5905         }
5906         else if (s[0] == ESC && len >= 3-1 && s[1] == '|')
5907         {
5908 #ifdef MCH_WRITE_DUMP
5909             char_u  *old_s = s;
5910 #endif
5911             char_u  *p;
5912             int     arg1 = 0, arg2 = 0;
5913
5914             switch (s[2])
5915             {
5916             /* one or two numeric arguments, separated by ';' */
5917
5918             case '0': case '1': case '2': case '3': case '4':
5919             case '5': case '6': case '7': case '8': case '9':
5920                 p = s + 2;
5921                 arg1 = getdigits(&p);       /* no check for length! */
5922                 if (p > s + len)
5923                     break;
5924
5925                 if (*p == ';')
5926                 {
5927                     ++p;
5928                     arg2 = getdigits(&p);   /* no check for length! */
5929                     if (p > s + len)
5930                         break;
5931
5932                     if (*p == 'H')
5933                         gotoxy(arg2, arg1);
5934                     else if (*p == 'r')
5935                         set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1);
5936                 }
5937                 else if (*p == 'A')
5938                 {
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);
5942                 }
5943                 else if (*p == 'C')
5944                 {
5945                     /* move cursor right arg1 columns in same line */
5946                     gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1,
5947                            g_coord.Y + 1);
5948                 }
5949                 else if (*p == 'H')
5950                 {
5951                     gotoxy(1, arg1);
5952                 }
5953                 else if (*p == 'L')
5954                 {
5955                     insert_lines(arg1);
5956                 }
5957                 else if (*p == 'm')
5958                 {
5959                     if (arg1 == 0)
5960                         normvideo();
5961                     else
5962                         textattr((WORD) arg1);
5963                 }
5964                 else if (*p == 'f')
5965                 {
5966                     textcolor((WORD) arg1);
5967                 }
5968                 else if (*p == 'b')
5969                 {
5970                     textbackground((WORD) arg1);
5971                 }
5972                 else if (*p == 'M')
5973                 {
5974                     delete_lines(arg1);
5975                 }
5976
5977                 len -= (int)(p - s);
5978                 s = p + 1;
5979                 break;
5980
5981
5982             /* Three-character escape sequences */
5983
5984             case 'A':
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);
5988                 goto got3;
5989
5990             case 'B':
5991                 visual_bell();
5992                 goto got3;
5993
5994             case 'C':
5995                 /* move cursor right one column in same line */
5996                 gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1,
5997                        g_coord.Y + 1);
5998                 goto got3;
5999
6000             case 'E':
6001                 termcap_mode_end();
6002                 goto got3;
6003
6004             case 'F':
6005                 standout();
6006                 goto got3;
6007
6008             case 'f':
6009                 standend();
6010                 goto got3;
6011
6012             case 'H':
6013                 gotoxy(1, 1);
6014                 goto got3;
6015
6016             case 'j':
6017                 clear_to_end_of_display();
6018                 goto got3;
6019
6020             case 'J':
6021                 clear_screen();
6022                 goto got3;
6023
6024             case 'K':
6025                 clear_to_end_of_line();
6026                 goto got3;
6027
6028             case 'L':
6029                 insert_lines(1);
6030                 goto got3;
6031
6032             case 'M':
6033                 delete_lines(1);
6034                 goto got3;
6035
6036             case 'S':
6037                 termcap_mode_start();
6038                 goto got3;
6039
6040             case 'V':
6041                 cursor_visible(TRUE);
6042                 goto got3;
6043
6044             case 'v':
6045                 cursor_visible(FALSE);
6046                 goto got3;
6047
6048             got3:
6049                 s += 3;
6050                 len -= 2;
6051             }
6052
6053 #ifdef MCH_WRITE_DUMP
6054             if (fdDump)
6055             {
6056                 fputs("ESC | ", fdDump);
6057                 fwrite(old_s + 2, sizeof(char_u), s - old_s - 2, fdDump);
6058                 fputc('\n', fdDump);
6059             }
6060 #endif
6061         }
6062         else
6063         {
6064             /* Write a single character */
6065             DWORD nWritten;
6066
6067             nWritten = write_chars(s, 1);
6068 #ifdef MCH_WRITE_DUMP
6069             if (fdDump)
6070             {
6071                 fputc('>', fdDump);
6072                 fwrite(s, sizeof(char_u), nWritten, fdDump);
6073                 fputs("<\n", fdDump);
6074             }
6075 #endif
6076
6077             len -= (nWritten - 1);
6078             s += nWritten;
6079         }
6080     }
6081
6082 #ifdef MCH_WRITE_DUMP
6083     if (fdDump)
6084         fflush(fdDump);
6085 #endif
6086 }
6087
6088 #endif /* FEAT_GUI_W32 */
6089
6090
6091 /*
6092  * Delay for "msec" milliseconds.
6093  */
6094     void
6095 mch_delay(
6096     long    msec,
6097     int     ignoreinput UNUSED)
6098 {
6099 #ifdef FEAT_GUI_W32
6100     Sleep((int)msec);       /* never wait for input */
6101 #else /* Console */
6102     if (ignoreinput)
6103 # ifdef FEAT_MZSCHEME
6104         if (mzthreads_allowed() && p_mzq > 0 && msec > p_mzq)
6105         {
6106             int towait = p_mzq;
6107
6108             /* if msec is large enough, wait by portions in p_mzq */
6109             while (msec > 0)
6110             {
6111                 mzvim_check_threads();
6112                 if (msec < towait)
6113                     towait = msec;
6114                 Sleep(towait);
6115                 msec -= towait;
6116             }
6117         }
6118         else
6119 # endif
6120             Sleep((int)msec);
6121     else
6122         WaitForChar(msec);
6123 #endif
6124 }
6125
6126
6127 /*
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.
6131  */
6132     int
6133 mch_remove(char_u *name)
6134 {
6135 #ifdef FEAT_MBYTE
6136     WCHAR       *wn = NULL;
6137     int         n;
6138 #endif
6139
6140     /*
6141      * On Windows, deleting a directory's symbolic link is done by
6142      * RemoveDirectory(): mch_rmdir.  It seems unnatural, but it is fact.
6143      */
6144     if (mch_isdir(name) && mch_is_symbolic_link(name))
6145         return mch_rmdir(name);
6146
6147     win32_setattrs(name, FILE_ATTRIBUTE_NORMAL);
6148
6149 #ifdef FEAT_MBYTE
6150     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6151     {
6152         wn = enc_to_utf16(name, NULL);
6153         if (wn != NULL)
6154         {
6155             n = DeleteFileW(wn) ? 0 : -1;
6156             vim_free(wn);
6157             return n;
6158         }
6159     }
6160 #endif
6161     return DeleteFile((LPCSTR)name) ? 0 : -1;
6162 }
6163
6164
6165 /*
6166  * Check for an "interrupt signal": CTRL-break or CTRL-C.
6167  */
6168     void
6169 mch_breakcheck(int force)
6170 {
6171 #ifndef FEAT_GUI_W32        /* never used */
6172     if (g_fCtrlCPressed || g_fCBrkPressed)
6173     {
6174         g_fCtrlCPressed = g_fCBrkPressed = FALSE;
6175         got_int = TRUE;
6176     }
6177 #endif
6178 }
6179
6180 /* physical RAM to leave for the OS */
6181 #define WINNT_RESERVE_BYTES     (256*1024*1024)
6182
6183 /*
6184  * How much main memory in KiB that can be used by VIM.
6185  */
6186     long_u
6187 mch_total_mem(int special UNUSED)
6188 {
6189     MEMORYSTATUSEX  ms;
6190
6191     PlatformId();
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)
6197     {
6198         /* Process address space fits in physical RAM, use all of it. */
6199         return (long_u)(ms.ullAvailVirtual / 1024);
6200     }
6201     if (ms.ullTotalPhys <= WINNT_RESERVE_BYTES)
6202     {
6203         /* Catch old NT box or perverse hardware setup. */
6204         return (long_u)((ms.ullTotalPhys / 2) / 1024);
6205     }
6206     /* Use physical RAM less reserve for OS + data. */
6207     return (long_u)((ms.ullTotalPhys - WINNT_RESERVE_BYTES) / 1024);
6208 }
6209
6210 #ifdef FEAT_MBYTE
6211 /*
6212  * Same code as below, but with wide functions and no comments.
6213  * Return 0 for success, non-zero for failure.
6214  */
6215     int
6216 mch_wrename(WCHAR *wold, WCHAR *wnew)
6217 {
6218     WCHAR       *p;
6219     int         i;
6220     WCHAR       szTempFile[_MAX_PATH + 1];
6221     WCHAR       szNewPath[_MAX_PATH + 1];
6222     HANDLE      hf;
6223
6224     p = wold;
6225     for (i = 0; wold[i] != NUL; ++i)
6226         if ((wold[i] == '/' || wold[i] == '\\' || wold[i] == ':')
6227                 && wold[i + 1] != 0)
6228             p = wold + i + 1;
6229     if ((int)(wold + i - p) < 8 || p[6] != '~')
6230         return (MoveFileW(wold, wnew) == 0);
6231
6232     if (GetFullPathNameW(wnew, _MAX_PATH, szNewPath, &p) == 0 || p == NULL)
6233         return -1;
6234     *p = NUL;
6235
6236     if (GetTempFileNameW(szNewPath, L"VIM", 0, szTempFile) == 0)
6237         return -2;
6238
6239     if (!DeleteFileW(szTempFile))
6240         return -3;
6241
6242     if (!MoveFileW(wold, szTempFile))
6243         return -4;
6244
6245     if ((hf = CreateFileW(wold, GENERIC_WRITE, 0, NULL, CREATE_NEW,
6246                     FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
6247         return -5;
6248     if (!CloseHandle(hf))
6249         return -6;
6250
6251     if (!MoveFileW(szTempFile, wnew))
6252     {
6253         (void)MoveFileW(szTempFile, wold);
6254         return -7;
6255     }
6256
6257     DeleteFileW(szTempFile);
6258
6259     if (!DeleteFileW(wold))
6260         return -8;
6261
6262     return 0;
6263 }
6264 #endif
6265
6266
6267 /*
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".
6277  *
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.
6282  *
6283  * Like rename(), returns 0 upon success, non-zero upon failure.
6284  * Should probably set errno appropriately when errors occur.
6285  */
6286     int
6287 mch_rename(
6288     const char  *pszOldFile,
6289     const char  *pszNewFile)
6290 {
6291     char        szTempFile[_MAX_PATH+1];
6292     char        szNewPath[_MAX_PATH+1];
6293     char        *pszFilePart;
6294     HANDLE      hf;
6295 #ifdef FEAT_MBYTE
6296     WCHAR       *wold = NULL;
6297     WCHAR       *wnew = NULL;
6298     int         retval = -1;
6299
6300     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6301     {
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);
6306         vim_free(wold);
6307         vim_free(wnew);
6308         return retval;
6309     }
6310 #endif
6311
6312     /*
6313      * No need to play tricks unless the file name contains a "~" as the
6314      * seventh character.
6315      */
6316     pszFilePart = (char *)gettail((char_u *)pszOldFile);
6317     if (STRLEN(pszFilePart) < 8 || pszFilePart[6] != '~')
6318         return rename(pszOldFile, pszNewFile);
6319
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)
6324         return -1;
6325     *pszFilePart = NUL;
6326
6327     /* Get (and create) a unique temporary file name in directory of new file */
6328     if (GetTempFileName(szNewPath, "VIM", 0, szTempFile) == 0)
6329         return -2;
6330
6331     /* blow the temp file away */
6332     if (!DeleteFile(szTempFile))
6333         return -3;
6334
6335     /* rename old file to the temp file */
6336     if (!MoveFile(pszOldFile, szTempFile))
6337         return -4;
6338
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
6348      */
6349     if ((hf = CreateFile(pszOldFile, GENERIC_WRITE, 0, NULL, CREATE_NEW,
6350                     FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
6351         return -5;
6352     if (!CloseHandle(hf))
6353         return -6;
6354
6355     /* rename the temp file to the new file */
6356     if (!MoveFile(szTempFile, pszNewFile))
6357     {
6358         /* Renaming failed.  Rename the file back to its old name, so that it
6359          * looks like nothing happened. */
6360         (void)MoveFile(szTempFile, pszOldFile);
6361
6362         return -7;
6363     }
6364
6365     /* Seems to be left around on Novell filesystems */
6366     DeleteFile(szTempFile);
6367
6368     /* finally, remove the empty old file */
6369     if (!DeleteFile(pszOldFile))
6370         return -8;
6371
6372     return 0;   /* success */
6373 }
6374
6375 /*
6376  * Get the default shell for the current hardware platform
6377  */
6378     char *
6379 default_shell(void)
6380 {
6381     PlatformId();
6382
6383     return "cmd.exe";
6384 }
6385
6386 /*
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.
6389  */
6390     int
6391 mch_access(char *n, int p)
6392 {
6393     HANDLE      hFile;
6394     DWORD       am;
6395     int         retval = -1;        /* default: fail */
6396 #ifdef FEAT_MBYTE
6397     WCHAR       *wn = NULL;
6398
6399     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6400         wn = enc_to_utf16((char_u *)n, NULL);
6401 #endif
6402
6403     if (mch_isdir((char_u *)n))
6404     {
6405         char TempName[_MAX_PATH + 16] = "";
6406 #ifdef FEAT_MBYTE
6407         WCHAR TempNameW[_MAX_PATH + 16] = L"";
6408 #endif
6409
6410         if (p & R_OK)
6411         {
6412             /* Read check is performed by seeing if we can do a find file on
6413              * the directory for any file. */
6414 #ifdef FEAT_MBYTE
6415             if (wn != NULL)
6416             {
6417                 int                 i;
6418                 WIN32_FIND_DATAW    d;
6419
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++] = '*';
6425                 TempNameW[i++] = 0;
6426
6427                 hFile = FindFirstFileW(TempNameW, &d);
6428                 if (hFile == INVALID_HANDLE_VALUE)
6429                     goto getout;
6430                 else
6431                     (void)FindClose(hFile);
6432             }
6433             else
6434 #endif
6435             {
6436                 char                *pch;
6437                 WIN32_FIND_DATA     d;
6438
6439                 vim_strncpy((char_u *)TempName, (char_u *)n, _MAX_PATH);
6440                 pch = TempName + STRLEN(TempName) - 1;
6441                 if (*pch != '\\' && *pch != '/')
6442                     *++pch = '\\';
6443                 *++pch = '*';
6444                 *++pch = NUL;
6445
6446                 hFile = FindFirstFile(TempName, &d);
6447                 if (hFile == INVALID_HANDLE_VALUE)
6448                     goto getout;
6449                 (void)FindClose(hFile);
6450             }
6451         }
6452
6453         if (p & W_OK)
6454         {
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 :-(. */
6459 #ifdef FEAT_MBYTE
6460             if (wn != NULL)
6461             {
6462                 if (!GetTempFileNameW(wn, L"VIM", 0, TempNameW))
6463                     goto getout;
6464                 else
6465                     DeleteFileW(TempNameW);
6466             }
6467             else
6468 #endif
6469             {
6470                 if (!GetTempFileName(n, "VIM", 0, TempName))
6471                     goto getout;
6472                 mch_remove((char_u *)TempName);
6473             }
6474         }
6475     }
6476     else
6477     {
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);
6482 #ifdef FEAT_MBYTE
6483         if (wn != NULL)
6484             hFile = CreateFileW(wn, am, 0, NULL, OPEN_EXISTING, 0, NULL);
6485         else
6486 #endif
6487             hFile = CreateFile(n, am, 0, NULL, OPEN_EXISTING, 0, NULL);
6488         if (hFile == INVALID_HANDLE_VALUE)
6489             goto getout;
6490         CloseHandle(hFile);
6491     }
6492
6493     retval = 0;     /* success */
6494 getout:
6495 #ifdef FEAT_MBYTE
6496     vim_free(wn);
6497 #endif
6498     return retval;
6499 }
6500
6501 #if defined(FEAT_MBYTE) || defined(PROTO)
6502 /*
6503  * Version of open() that may use UTF-16 file name.
6504  */
6505     int
6506 mch_open(char *name, int flags, int mode)
6507 {
6508     /* _wopen() does not work with Borland C 5.5: creates a read-only file. */
6509 # ifndef __BORLANDC__
6510     WCHAR       *wn;
6511     int         f;
6512
6513     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6514     {
6515         wn = enc_to_utf16((char_u *)name, NULL);
6516         if (wn != NULL)
6517         {
6518             f = _wopen(wn, flags, mode);
6519             vim_free(wn);
6520             return f;
6521         }
6522     }
6523 # endif
6524
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
6528      * here. */
6529     if (strlen(name) >= _MAX_PATH)
6530         return -1;
6531
6532     return open(name, flags, mode);
6533 }
6534
6535 /*
6536  * Version of fopen() that may use UTF-16 file name.
6537  */
6538     FILE *
6539 mch_fopen(char *name, char *mode)
6540 {
6541     WCHAR       *wn, *wm;
6542     FILE        *f = NULL;
6543
6544     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6545     {
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];
6550         int oldMode = 0;
6551
6552         _get_fmode(&oldMode);
6553         if (newMode == 't')
6554             _set_fmode(_O_TEXT);
6555         else if (newMode == 'b')
6556             _set_fmode(_O_BINARY);
6557 # endif
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);
6562         vim_free(wn);
6563         vim_free(wm);
6564
6565 # if defined(DEBUG) && _MSC_VER >= 1400
6566         _set_fmode(oldMode);
6567 # endif
6568         return f;
6569     }
6570
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
6574      * here. */
6575     if (strlen(name) >= _MAX_PATH)
6576         return NULL;
6577
6578     return fopen(name, mode);
6579 }
6580 #endif
6581
6582 #ifdef FEAT_MBYTE
6583 /*
6584  * SUB STREAM (aka info stream) handling:
6585  *
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
6592  * streams.
6593  *
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
6598  */
6599
6600 /*
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.
6604  */
6605     static void
6606 copy_substream(HANDLE sh, void *context, WCHAR *to, WCHAR *substream, long len)
6607 {
6608     HANDLE  hTo;
6609     WCHAR   *to_name;
6610
6611     to_name = malloc((wcslen(to) + wcslen(substream) + 1) * sizeof(WCHAR));
6612     wcscpy(to_name, to);
6613     wcscat(to_name, substream);
6614
6615     hTo = CreateFileW(to_name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
6616                                                  FILE_ATTRIBUTE_NORMAL, NULL);
6617     if (hTo != INVALID_HANDLE_VALUE)
6618     {
6619         long    done;
6620         DWORD   todo;
6621         DWORD   readcnt, written;
6622         char    buf[4096];
6623
6624         /* Copy block of bytes at a time.  Abort when something goes wrong. */
6625         for (done = 0; done < len; done += written)
6626         {
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)
6632                     || readcnt != todo
6633                     || !WriteFile(hTo, buf, todo, &written, NULL)
6634                     || written != todo)
6635                 break;
6636         }
6637         CloseHandle(hTo);
6638     }
6639
6640     free(to_name);
6641 }
6642
6643 /*
6644  * Copy info streams from file "from" to file "to".
6645  */
6646     static void
6647 copy_infostreams(char_u *from, char_u *to)
6648 {
6649     WCHAR               *fromw;
6650     WCHAR               *tow;
6651     HANDLE              sh;
6652     WIN32_STREAM_ID     sid;
6653     int                 headersize;
6654     WCHAR               streamname[_MAX_PATH];
6655     DWORD               readcount;
6656     void                *context = NULL;
6657     DWORD               lo, hi;
6658     int                 len;
6659
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)
6664     {
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)
6669         {
6670             /* Use BackupRead() to find the info streams.  Repeat until we
6671              * have done them all.*/
6672             for (;;)
6673             {
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)
6680                         || readcount == 0)
6681                     break;
6682
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)
6687                 {
6688                     /* Read the stream name. */
6689                     if (!BackupRead(sh, (LPBYTE)streamname,
6690                                                          sid.dwStreamNameSize,
6691                                           &readcount, FALSE, FALSE, &context))
6692                         break;
6693
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,
6702                                                               L":$DATA") == 0)
6703                     {
6704                         streamname[len - 6] = 0;
6705                         copy_substream(sh, &context, tow, streamname,
6706                                                     (long)sid.Size.u.LowPart);
6707                     }
6708                 }
6709
6710                 /* Advance to the next stream.  We might try seeking too far,
6711                  * but BackupSeek() doesn't skip over stream borders, thus
6712                  * that's OK. */
6713                 (void)BackupSeek(sh, sid.Size.u.LowPart, sid.Size.u.HighPart,
6714                                                           &lo, &hi, &context);
6715             }
6716
6717             /* Clear the context. */
6718             (void)BackupRead(sh, NULL, 0, &readcount, TRUE, FALSE, &context);
6719
6720             CloseHandle(sh);
6721         }
6722     }
6723     vim_free(fromw);
6724     vim_free(tow);
6725 }
6726 #endif
6727
6728 /*
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.
6732  */
6733     int
6734 mch_copy_file_attribute(char_u *from, char_u *to)
6735 {
6736 #ifdef FEAT_MBYTE
6737     /* File streams only work on Windows NT and later. */
6738     PlatformId();
6739     copy_infostreams(from, to);
6740 #endif
6741     return 0;
6742 }
6743
6744 #if defined(MYRESETSTKOFLW) || defined(PROTO)
6745 /*
6746  * Recreate a destroyed stack guard page in win32.
6747  * Written by Benjamin Peterson.
6748  */
6749
6750 /* These magic numbers are from the MS header files */
6751 #define MIN_STACK_WINNT 2
6752
6753 /*
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.
6757  */
6758     int
6759 myresetstkoflw(void)
6760 {
6761     BYTE        *pStackPtr;
6762     BYTE        *pGuardPage;
6763     BYTE        *pStackBase;
6764     BYTE        *pLowestPossiblePage;
6765     MEMORY_BASIC_INFORMATION mbi;
6766     SYSTEM_INFO si;
6767     DWORD       nPageSize;
6768     DWORD       dummy;
6769
6770     PlatformId();
6771
6772     /* We need to know the system page size. */
6773     GetSystemInfo(&si);
6774     nPageSize = si.dwPageSize;
6775
6776     /* ...and the current stack pointer */
6777     pStackPtr = (BYTE*)_alloca(1);
6778
6779     /* ...and the base of the stack. */
6780     if (VirtualQuery(pStackPtr, &mbi, sizeof mbi) == 0)
6781         return 0;
6782     pStackBase = (BYTE*)mbi.AllocationBase;
6783
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;
6787
6788     {
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.
6791          */
6792         BYTE *pBlock = pStackBase;
6793
6794         for (;;)
6795         {
6796             if (VirtualQuery(pBlock, &mbi, sizeof mbi) == 0)
6797                 return 0;
6798
6799             pBlock += mbi.RegionSize;
6800
6801             if (mbi.State & MEM_COMMIT)
6802                 break;
6803         }
6804
6805         /* mbi now describes the first committed block in the stack. */
6806         if (mbi.Protect & PAGE_GUARD)
6807             return 1;
6808
6809         /* decide where the guard page should start */
6810         if ((long_u)(mbi.BaseAddress) < (long_u)pLowestPossiblePage)
6811             pGuardPage = pLowestPossiblePage;
6812         else
6813             pGuardPage = (BYTE*)mbi.BaseAddress;
6814
6815         /* allocate the guard page */
6816         if (!VirtualAlloc(pGuardPage, nPageSize, MEM_COMMIT, PAGE_READWRITE))
6817             return 0;
6818
6819         /* apply the guard attribute to the page */
6820         if (!VirtualProtect(pGuardPage, nPageSize, PAGE_READWRITE | PAGE_GUARD,
6821                                                                       &dummy))
6822             return 0;
6823     }
6824
6825     return 1;
6826 }
6827 #endif
6828
6829
6830 #if defined(FEAT_MBYTE) || defined(PROTO)
6831 /*
6832  * The command line arguments in UCS2
6833  */
6834 static int      nArgsW = 0;
6835 static LPWSTR   *ArglistW = NULL;
6836 static int      global_argc = 0;
6837 static char     **global_argv;
6838
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;
6849
6850
6851 /*
6852  * Get the command line arguments.  Unicode version.
6853  * Returns argc.  Zero when something fails.
6854  */
6855     int
6856 get_cmd_argsW(char ***argvp)
6857 {
6858     char        **argv = NULL;
6859     int         argc = 0;
6860     int         i;
6861
6862     free_cmd_argsW();
6863     ArglistW = CommandLineToArgvW(GetCommandLineW(), &nArgsW);
6864     if (ArglistW != NULL)
6865     {
6866         argv = malloc((nArgsW + 1) * sizeof(char *));
6867         if (argv != NULL)
6868         {
6869             argc = nArgsW;
6870             argv[argc] = NULL;
6871             for (i = 0; i < argc; ++i)
6872             {
6873                 int     len;
6874
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)
6880                 {
6881                     /* Out of memory, clear everything. */
6882                     while (i > 0)
6883                         free(argv[--i]);
6884                     free(argv);
6885                     argv = NULL;
6886                     argc = 0;
6887                 }
6888             }
6889         }
6890     }
6891
6892     global_argc = argc;
6893     global_argv = argv;
6894     if (argc > 0)
6895     {
6896         if (used_file_indexes != NULL)
6897             free(used_file_indexes);
6898         used_file_indexes = malloc(argc * sizeof(int));
6899     }
6900
6901     if (argvp != NULL)
6902         *argvp = argv;
6903     return argc;
6904 }
6905
6906     void
6907 free_cmd_argsW(void)
6908 {
6909     if (ArglistW != NULL)
6910     {
6911         GlobalFree(ArglistW);
6912         ArglistW = NULL;
6913     }
6914 }
6915
6916 /*
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()
6919  * is called.
6920  */
6921     void
6922 used_file_arg(char *name, int literal, int full_path, int diff_mode)
6923 {
6924     int         i;
6925
6926     if (used_file_indexes == NULL)
6927         return;
6928     for (i = used_file_argc + 1; i < global_argc; ++i)
6929         if (STRCMP(global_argv[i], name) == 0)
6930         {
6931             used_file_argc = i;
6932             used_file_indexes[used_file_count++] = i;
6933             break;
6934         }
6935     used_file_literal = literal;
6936     used_file_full_path = full_path;
6937     used_file_diff_mode = diff_mode;
6938 }
6939
6940 /*
6941  * Remember the length of the argument list as it was.  If it changes then we
6942  * leave it alone when 'encoding' is set.
6943  */
6944     void
6945 set_alist_count(void)
6946 {
6947     used_alist_count = GARGCOUNT;
6948 }
6949
6950 /*
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'.
6954  */
6955     void
6956 fix_arg_enc(void)
6957 {
6958     int         i;
6959     int         idx;
6960     char_u      *str;
6961     int         *fnum_list;
6962
6963     /* Safety checks:
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.
6968      */
6969     if (global_argc != nArgsW
6970             || ArglistW == NULL
6971             || used_file_indexes == NULL
6972             || used_file_count == 0
6973             || used_alist_count != GARGCOUNT)
6974         return;
6975
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;
6982
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 */
6987
6988     for (i = 0; i < used_file_count; ++i)
6989     {
6990         idx = used_file_indexes[i];
6991         str = utf16_to_enc(ArglistW[idx], NULL);
6992         if (str != NULL)
6993         {
6994 #ifdef FEAT_DIFF
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])))
6999             {
7000                 char_u      *r;
7001
7002                 r = concat_fnames(str, gettail(alist_name(&GARGLIST[0])), TRUE);
7003                 if (r != NULL)
7004                 {
7005                     vim_free(str);
7006                     str = r;
7007                 }
7008             }
7009 #endif
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);
7014
7015             alist_add(&global_alist, str, used_file_literal ? 2 : 0);
7016         }
7017     }
7018
7019     if (!used_file_literal)
7020     {
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");
7028     }
7029
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)
7033     {
7034         do_cmdline_cmd((char_u *)":rewind");
7035         if (GARGCOUNT == 1 && used_file_full_path)
7036             (void)vim_chdirfile(alist_name(&GARGLIST[0]));
7037     }
7038
7039     set_alist_count();
7040 }
7041 #endif
7042
7043     int
7044 mch_setenv(char *var, char *value, int x)
7045 {
7046     char_u      *envbuf;
7047
7048     envbuf = alloc((unsigned)(STRLEN(var) + STRLEN(value) + 2));
7049     if (envbuf == NULL)
7050         return -1;
7051
7052     sprintf((char *)envbuf, "%s=%s", var, value);
7053
7054 #ifdef FEAT_MBYTE
7055     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
7056     {
7057         WCHAR       *p = enc_to_utf16(envbuf, NULL);
7058
7059         vim_free(envbuf);
7060         if (p == NULL)
7061             return -1;
7062         _wputenv(p);
7063 # ifdef libintl_wputenv
7064         libintl_wputenv(p);
7065 # endif
7066         /* Unlike Un*x systems, we can free the string for _wputenv(). */
7067         vim_free(p);
7068     }
7069     else
7070 #endif
7071     {
7072         _putenv((char *)envbuf);
7073 # ifdef libintl_putenv
7074         libintl_putenv((char *)envbuf);
7075 # endif
7076         /* Unlike Un*x systems, we can free the string for _putenv(). */
7077         vim_free(envbuf);
7078     }
7079
7080     return 0;
7081 }