📄 os_win32.c
字号:
#ifdef OLD_CONSOLE_STUFF
/* Create a console for the process. This lets us write a termination
* message at the end, and wait for the user to close the console
* window manually...
*/
if (fUseConsole)
{
mch_open_console();
/*
* Write the command to the console, so the user can see what is going
* on.
*/
{
HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
DWORD number;
WriteConsole(hStderr, cmd, STRLEN(cmd), &number, NULL);
WriteConsole(hStderr, "\n", 1, &number, NULL);
}
}
#else
/* There is a strange error on Windows 95 when using "c:\\command.com".
* When the "c:\\" is left out it works OK...? */
if (mch_windows95()
&& (STRNICMP(cmd, "c:/command.com", 14) == 0
|| STRNICMP(cmd, "c:\\command.com", 14) == 0))
cmd += 3;
#endif
/* Now, run the command */
CreateProcess(NULL, /* Executable name */
cmd, /* Command to execute */
NULL, /* Process security attributes */
NULL, /* Thread security attributes */
FALSE, /* Inherit handles */
CREATE_DEFAULT_ERROR_MODE | /* Creation flags */
#ifdef OLD_CONSOLE_STUFF
0,
#else
CREATE_NEW_CONSOLE,
#endif
NULL, /* Environment */
NULL, /* Current directory */
&si, /* Startup information */
&pi); /* Process information */
/* Wait for the command to terminate before continuing */
if (fUseConsole)
{
if (g_PlatformId != VER_PLATFORM_WIN32s)
{
WaitForSingleObject(pi.hProcess, INFINITE);
/* Get the command exit code */
GetExitCodeProcess(pi.hProcess, &ret);
}
else
{
/*
* This ugly code is the only quick way of performing
* a synchronous spawn under Win32s. Yuk.
*/
num_windows = 0;
EnumWindows(win32ssynch_cb, 0);
old_num_windows = num_windows;
do
{
Sleep(1000);
num_windows = 0;
EnumWindows(win32ssynch_cb, 0);
} while (num_windows == old_num_windows);
ret = 0;
}
}
/* Close the handles to the subprocess, so that it goes away */
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
/* Close the console window. If we are not redirecting output, wait for
* the user to press a key.
*/
#ifdef OLD_CONSOLE_STUFF
if (fUseConsole)
mch_close_console(!(options & SHELL_DOOUT), ret);
#endif
return ret;
}
#else
# define mch_system(c, o) system(c)
#endif
/*
* Either execute a command by calling the shell or start a new shell
*/
int
mch_call_shell(
char_u *cmd,
int options) /* SHELL_FILTER if called by do_filter() */
/* SHELL_COOKED if term needs cooked mode */
{
int x;
#ifndef USE_GUI_WIN32
int stopped_termcap_mode = FALSE;
#endif
out_flush();
#ifndef USE_GUI_WIN32
/*
* ALWAYS switch to non-termcap mode, otherwise ":r !ls" may crash.
*/
if (g_hCurOut == g_hConOut &&
((cmd == NULL) || STRNICMP(cmd, "start ", 6) != 0))
{
termcap_mode_end();
stopped_termcap_mode = TRUE;
}
#endif
#ifdef MCH_WRITE_DUMP
if (fdDump)
{
fprintf(fdDump, "mch_call_shell(\"%s\", %d)\n", cmd, options);
fflush(fdDump);
}
#endif
/*
* Catch all deadly signals while running the external command, because a
* CTRL-C, Ctrl-Break or illegal instruction might otherwise kill us.
*/
signal(SIGINT, SIG_IGN);
#ifdef __GNUC__
signal(SIGKILL, SIG_IGN);
#else
signal(SIGBREAK, SIG_IGN);
#endif
signal(SIGILL, SIG_IGN);
signal(SIGFPE, SIG_IGN);
signal(SIGSEGV, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGABRT, SIG_IGN);
if (options & SHELL_COOKED)
settmode(TMODE_COOK); /* set to normal mode */
if (cmd == NULL)
{
x = mch_system(p_sh, options);
}
else
{
/* we use "command" or "cmd" to start the shell; slow but easy */
char_u *newcmd;
newcmd = lalloc(
#ifdef USE_GUI_WIN32
STRLEN(vimrun_path) +
#endif
STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10, TRUE);
if (newcmd != NULL)
{
if (STRNICMP(cmd, "start ", 6) == 0)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
si.lpReserved = NULL;
si.lpDesktop = NULL;
si.lpTitle = NULL;
si.dwFlags = 0;
si.cbReserved2 = 0;
si.lpReserved2 = NULL;
sprintf((char *)newcmd, "%s\0", cmd+6);
/*
* Now, start the command as a process, so that it doesn't
* inherit our handles which causes unpleasant dangling swap
* files if we exit before the spawned process
*/
if (CreateProcess (NULL, // Executable name
newcmd, // Command to execute
NULL, // Process security attributes
NULL, // Thread security attributes
FALSE, // Inherit handles
CREATE_NEW_CONSOLE, // Creation flags
NULL, // Environment
NULL, // Current directory
&si, // Startup information
&pi)) // Process information
x = 0;
else
x = -1;
/* Close the handles to the subprocess, so that it goes away */
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
{
sprintf((char *)newcmd, "%s%s %s %s",
#if defined(OLD_CONSOLE_STUFF) || !defined(USE_GUI_WIN32)
"",
#else
/*
* Do we need to use "vimrun"?
*/
((options & SHELL_DOOUT) || s_dont_use_vimrun) ?
"" : vimrun_path,
#endif
p_sh,
p_shcf,
cmd);
x = mch_system((char *)newcmd, options);
}
vim_free(newcmd);
}
}
settmode(TMODE_RAW); /* set to raw mode */
#ifdef USE_GUI_WIN32
if (x && !expand_interactively && !fUseConsole)
#else
if (x && !expand_interactively)
#endif
{
smsg("%d returned", x);
msg_putchar('\n');
}
resettitle();
signal(SIGINT, SIG_DFL);
#ifdef __GNUC__
signal(SIGKILL, SIG_DFL);
#else
signal(SIGBREAK, SIG_DFL);
#endif
signal(SIGILL, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGABRT, SIG_DFL);
#ifndef USE_GUI_WIN32
if (stopped_termcap_mode)
termcap_mode_start();
#endif
return x;
}
/*
* Does `s' contain a wildcard?
*/
int
mch_has_wildcard(
char_u *s)
{
return (vim_strpbrk(s, (char_u *)"?*$~") != NULL);
}
/*
* comparison function for qsort in expandpath
*/
static int
#ifdef __BORLANDC__
_RTLENTRYF
#endif
pstrcmp(
const void *a,
const void *b)
{
return (_stricoll(* (char **)a, * (char **)b));
}
/*
* Recursively build up a list of files in "gap" matching the first wildcard
* in `path'. Called by expand_wildcards().
*/
int
mch_expandpath(
struct growarray *gap,
char_u *path,
int flags)
{
char buf[_MAX_PATH+1];
char *p, *s, *e;
int start_len, c = 1;
WIN32_FIND_DATA fb;
HANDLE hFind;
int matches;
int start_dot_ok;
start_len = gap->ga_len;
/*
* Find the first part in the path name that contains a wildcard.
* Copy it into `buf', including the preceding characters.
*/
p = buf;
s = NULL;
e = NULL;
while (*path)
{
if (*path == '\\' || *path == ':' || *path == '/')
{
if (e)
break;
else
s = p;
}
if (*path == '*' || *path == '?')
e = p;
*p++ = *path++;
}
e = p;
if (s)
s++;
else
s = buf;
#ifdef USE_GUI_WIN32
if (gui_is_win32s())
{
/* It appears the Win32s FindFirstFile() call doesn't like a pattern
* such as \sw\rel1.0\cod* because of the dot in the directory name.
* It doesn't match files with extensions.
* if the file name ends in "*" and does not contain a "." after the
* last \ , add ".*"
*/
if (e[-1] == '*' && vim_strchr(s, '.') == NULL)
{
*e++ = '.';
*e++ = '*';
}
}
#endif
/* now we have one wildcard component between `s' and `e' */
*e = NUL;
start_dot_ok = (buf[0] == '.' || buf[0] == '*');
/* If we are expanding wildcards, we try both files and directories */
if ((hFind = FindFirstFile(buf, &fb)) != INVALID_HANDLE_VALUE)
while (c)
{
STRCPY(s, fb.cFileName);
/*
* Ignore "." and "..". When more follows, this must be a
* directory.
* Find*File() returns matches that start with a '.', even though
* the pattern doesn't start with '.'. Filter them out manually.
*/
if ((s[0] != '.'
|| (start_dot_ok
&& s[1] != NUL
&& (s[1] != '.' || s[2] != NUL)))
&& (*path == NUL || mch_isdir(buf)))
{
STRCAT(buf, path);
if (mch_has_wildcard(path)) /* handle more wildcards */
(void)mch_expandpath(gap, buf, flags);
else if (mch_getperm(buf) >= 0) /* add existing file */
addfile(gap, buf, flags);
}
c = FindNextFile(hFind, &fb);
}
FindClose(hFind);
matches = gap->ga_len - start_len;
if (matches)
qsort(((char_u **)gap->ga_data) + start_len, matches,
sizeof(char *), pstrcmp);
return matches;
}
/*
* The normal _chdir() does not change the default drive. This one does.
* Returning 0 implies success; -1 implies failure.
*/
int
mch_chdir(char *path)
{
if (path[0] == NUL) /* just checking... */
return -1;
if (isalpha(path[0]) && path[1] == ':') /* has a drive name */
{
if (_chdrive(TO_LOWER(path[0]) - 'a' + 1) != 0)
return -1; /* invalid drive name */
path += 2;
}
if (*path == NUL) /* drive name only */
return 0;
return chdir(path); /* let the normal chdir() do the rest */
}
#ifndef USE_GUI_WIN32
/*
* Copy the contents of screen buffer hSrc to the bottom-left corner
* of screen buffer hDst.
*/
static void
copy_screen_buffer_text(
HANDLE hSrc,
HANDLE hDst)
{
int i, j, nSrcWidth, nSrcHeight, nDstWidth, nDstHeight;
COORD coordOrigin;
DWORD dwDummy;
LPSTR pszOldText;
CONSOLE_SCREEN_BUFFER_INFO csbiSrc, csbiDst;
#ifdef MCH_WRITE_DUMP
if (fdDump)
{
fprintf(fdDump, "copy_screen_buffer_text(%s, %s)\n",
(hSrc == g_hSavOut ? "Sav" : "Con"),
(hDst == g_hSavOut ? "Sav" : "Con"));
fflush(fdDump);
}
#endif
GetConsoleScreenBufferInfo(hSrc, &csbiSrc);
nSrcWidth = csbiSrc.srWindow.Right - csbiSrc.srWindow.Left + 1;
nSrcHeight = csbiSrc.srWindow.Bottom - csbiSrc.srWindow.Top + 1;
GetConsoleScreenBufferInfo(hDst, &csbiDst);
nDstWidth = csbiDst.srWindow.Right - csbiDst.srWindow.Left + 1;
nDstHeight = csbiDst.srWindow.Bottom - csbiDst.srWindow.Top + 1;
pszOldText = (LPSTR) alloc(nDstHeight * nDstWidth);
/* clear the top few lines if Src shorter than Dst */
for (i = 0; i < nDstHeight - nSrcHeight; i++)
{
for (j = 0; j < nDstWidth; j++)
pszOldText[i * nDstWidth + j] = ' ';
}
/* Grab text off source screen. */
coordOrigin.X = 0;
coordOrigin.Y = (SHORT) max(0, csbiSrc.srWindow.Bottom + 1 - nDstHeight);
for (i = 0; i < min(nSrcHeight, nDstHeight); i++)
{
LPSTR psz = pszOldText
+ (i + max(0, nDstHeight - nSrcHeight)) * nDstWidth;
ReadConsoleOutputCharacter(hSrc, psz, min(nDstWidth, nSrcWidth),
coordOrigin, &dwDummy);
coordOrigin.Y++;
/* clear the last few columns if Src narrower than Dst */
for (j = nSrcWidth; j < nDstWidth; j++)
psz[j] = ' ';
}
/* paste Src's text onto Dst */
coordOrigin.Y = csbiDst.srWindow.Top;
WriteConsoleOutputCharacter(hDst, pszOldText, nDstHeight * nDstWidth,
coordOrigin, &dwDummy);
vim_free(pszOldText);
}
/* keep track of state of original console window */
static SMALL_RECT g_srOrigWindowRect;
static COORD g_coordOrig;
static WORD g_attrSave = 0;
/*
* Start termcap mode by switching to our allocated screen buffer
*/
static void
termcap_mode_start(void)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD dwDummy;
COORD coord;
WORD wAttr = (WORD) (g_attrSave ? g_attrSave : g_attrCurrent);
GetConsoleScreenBufferInfo(g_hSavOut, &csbi);
g_srOrigWindowRect = csbi.srWindow;
g_coordOrig.X = 0;
g_coordOrig.Y = csbi.dwCursorPosition.Y;
if (g_hConOut == INVALID_HANDLE_VALUE)
/* Create a new screen buffer in which we do all of our editing.
* This means we can restore the original screen when we finish. */
g_hConOut = CreateConsoleScreenBuffer(GENERIC_WRITE | GENERIC_READ,
0, (LPSECURITY_ATTRIBUTES) NULL,
CONSOLE_TEXTMODE_BUFFER,
(LPVOID) NULL);
coord.X = coord.Y = 0;
FillConsoleOutputCharacter(g_hConOut, ' ', Rows * Columns, coord, &dwDummy);
FillConsoleOutputAttribute(g_hConOut, wAttr, Rows*Columns, coord, &dwDummy);
copy_screen_buffer_text(g_hSavOut, g_hConOut);
g_hCurOut = g_hConOut;
SetConsoleActiveScreenBuffer(g_hCurOut);
ResizeConBufAndWindow(g_hCurOut, Columns, Rows);
set_scroll_region(0, 0, Columns - 1, Rows - 1);
check_winsize();
resettitle();
textattr(wAttr);
}
/*
* Turn off termcap mode by restoring the screen buffer we had upon startup
*/
static void
termcap_mode_end()
{
g_attrSave = g_attrCurrent;
ResizeConBufAndWindow(g_hCurOut, g_nOldColumns, g_nOldRows);
/* This weird Sleep(0) is required to allow Windows to really resize the
* console window. Apparently it's done asynchronously, which may caus
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -