⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_win32.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
#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 + -