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

📄 cmd.c

📁 PocketCMD是与pocketconsole配合实用的命令行解释器(Shell)
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: cmd.c,v 1.3 2004/02/16 16:13:36 pfalcon Exp $ * *  CMD.C - command-line interface. * * *  History: * *    17 Jun 1994 (Tim Norman) *        started. * *    08 Aug 1995 (Matt Rains) *        I have cleaned up the source code. changes now bring this source *        into guidelines for recommended programming practice. * *        A added the the standard FreeDOS GNU licence test to the *        initialize() function. * *        Started to replace puts() with printf(). this will help *        standardize output. please follow my lead. * *        I have added some constants to help making changes easier. * *    15 Dec 1995 (Tim Norman) *        major rewrite of the code to make it more efficient and add *        redirection support (finally!) * *    06 Jan 1996 (Tim Norman) *        finished adding redirection support!  Changed to use our own *        exec code (MUCH thanks to Svante Frey!!) * *    29 Jan 1996 (Tim Norman) *        added support for CHDIR, RMDIR, MKDIR, and ERASE, as per *        suggestion of Steffan Kaiser * *        changed "file not found" error message to "bad command or *        filename" thanks to Dustin Norman for noticing that confusing *        message! * *        changed the format to call internal commands (again) so that if *        they want to split their commands, they can do it themselves  *        (none of the internal functions so far need that much power, anyway) * *    27 Aug 1996 (Tim Norman) *        added in support for Oliver Mueller's ALIAS command * *    14 Jun 1997 (Steffan Kaiser) *        added ctrl-break handling and error level * *    16 Jun 1998 (Rob Lake) *        Runs command.com if /P is specified in command line.  Command.com *        also stays permanent.  If /C is in the command line, starts the *        program next in the line. * *    21 Jun 1998 (Rob Lake) *        Fixed up /C so that arguments for the program * *    08-Jul-1998 (John P. Price) *        Now sets COMSPEC environment variable *        misc clean up and optimization *        added date and time commands *        changed to using spawnl instead of exec.  exec does not copy the *        environment to the child process! * *    14 Jul 1998 (Hans B Pufal) *        Reorganised source to be more efficient and to more closely *        follow MS-DOS conventions. (eg %..% environment variable *        replacement works form command line as well as batch file. * *        New organisation also properly support nested batch files. * *        New command table structure is half way towards providing a *        system in which COMMAND will find out what internal commands *        are loaded * *    24 Jul 1998 (Hans B Pufal) [HBP_003] *        Fixed return value when called with /C option * *    27 Jul 1998  John P. Price *        added config.h include * *    28 Jul 1998  John P. Price *        added showcmds function to show commands and options available * *    07-Aug-1998 (John P Price <linux-guru@gcfl.net>) *        Fixed carrage return output to better match MSDOS with echo *        on or off. (marked with "JPP 19980708") * *    07-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        First ReactOS release. *        Extended length of commandline buffers to 512. * *    13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        Added COMSPEC environment variable. *        Added "/t" support (color) on cmd command line. * *    07-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        Added help text ("cmd /?"). * *    25-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        Unicode and redirection safe! *        Fixed redirections and piping. *        Piping is based on temporary files, but basic support *        for anonymous pipes already exists. * *    27-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        Replaced spawnl() by CreateProcess(). * *    22-Oct-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        Added break handler. * *    15-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        Fixed current directory * *    28-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>) *        Restore window title after program/batch execution * *    03-Feb-2001 (Eric Kohl <ekohl@rz-online.de>) *        Workaround because argc[0] is NULL under ReactOS * *    23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>) *        %envvar% replacement conflicted with for. */#include "config.h"#include "cmd.h"#undef fileno#define fileno _filenoBOOL GetStdioPathW(DWORD id, PWSTR pwszBuf, LPDWORD lpdwLen);BOOL bExit = FALSE;       /* indicates EXIT was typed */BOOL bCanExit = TRUE;     /* indicates if this shell is exitable */BOOL bCtrlBreak = FALSE;  /* Ctrl-Break or Ctrl-C hit */BOOL bIgnoreEcho = FALSE; /* Ignore 'newline' before 'cls' */INT  nErrorLevel = 0;     /* Errorlevel of last launched external program */BOOL bChildProcessRunning = FALSE;DWORD dwChildProcessId = 0;OSVERSIONINFO osvi;#ifdef INCLUDE_CMD_COLORWORD wColor;              /* current color */WORD wDefColor;           /* default color */#endif/* *  is character a delimeter when used on first word? * */static BOOL IsDelimiter (TCHAR c){	return (c == _T('/') || c == _T('=') || c == _T('\0') || _istspace (c));}/* * This command (in first) was not found in the command table * * first - first word on command line * rest  - rest of command line */static VOIDExecute (LPTSTR first, LPTSTR rest){	TCHAR szFullName[MAX_PATH];	TCHAR szWindowTitle[MAX_PATH];	DWORD dwExitCode = 0;#ifdef _DEBUG	DebugPrintf (_T("Execute: \'%s\' \'%s\'\n"), first, rest);#endif	/* check for a drive change */	if ((_istalpha (first[0])) && (!_tcscmp (first + 1, _T(":"))))	{			BOOL working = TRUE;		if (!SetCurrentDirectory(first))		/* Guess they changed disc or something, handle that gracefully and get to root */		{			TCHAR str[4];			str[0]=first[0];			str[1]=_T(':');			str[2]=_T('\\');			str[3]=0;			working = SetCurrentDirectory(str);		}		if (!working) ConErrPuts (INVALIDDRIVE);		return;	}	/* get the PATH environment variable and parse it */	/* search the PATH environment variable for the binary */	if (!SearchForExecutable (first, szFullName))	{		error_bad_command ();		return;	}	GetConsoleTitle (szWindowTitle, MAX_PATH);	/* check if this is a .BAT or .CMD file */	if (!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".bat")) ||		!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".cmd")))	{#ifdef _DEBUG		DebugPrintf (_T("[BATCH: %s %s]\n"), szFullName, rest);#endif		Batch (szFullName, first, rest);	}	else	{		/* exec the program */		TCHAR szFullCmdLine [CMDLINE_LENGTH];		PROCESS_INFORMATION prci;#ifdef _DEBUG		DebugPrintf (_T("[EXEC: %s %s]\n"), szFullName, rest);#endif		/* build command line for CreateProcess() */		_tcscpy (szFullCmdLine, szFullName);		_tcscat (szFullCmdLine, _T(" "));		_tcscat (szFullCmdLine, rest);		if (CreateProcess (szFullName,		                   rest,		                   NULL,		                   NULL,		                   FALSE,		                   0,		                   NULL,		                   NULL,		                   NULL,		                   &prci))		{			/* FIXME: Protect this with critical section */			bChildProcessRunning = TRUE;			dwChildProcessId = prci.dwProcessId;			WaitForSingleObject (prci.hProcess, INFINITE);			/* FIXME: Protect this with critical section */			bChildProcessRunning = TRUE;			GetExitCodeProcess (prci.hProcess, &dwExitCode);			nErrorLevel = (INT)dwExitCode;			CloseHandle (prci.hThread);			CloseHandle (prci.hProcess);		}		else		{			ErrorMessage (GetLastError (),			              _T("Error executing CreateProcess()!!\n"));		}	}	SetConsoleTitle (szWindowTitle);}/* * look through the internal commands and determine whether or not this * command is one of them.  If it is, call the command.  If not, call * execute to run it as an external program. * * line - the command line of the program to run * */static VOIDDoCommand (LPTSTR line){	TCHAR com[MAX_PATH];  /* the first word in the command */	LPTSTR cp = com;	LPTSTR cstart;	LPTSTR rest = line;   /* pointer to the rest of the command line */	INT cl;	LPCOMMAND cmdptr;#ifdef _DEBUG	DebugPrintf (_T("DoCommand: (\'%s\')\n"), line);#endif /* DEBUG */	/* Skip over initial white space */	while (isspace (*rest))		rest++;	cstart = rest;	/* Anything to do ? */	if (*rest)	{		/* Copy over 1st word as lower case */		while (!IsDelimiter (*rest))			*cp++ = _totlower (*rest++);		/* Terminate first word */		*cp = _T('\0');		/* Skip over whitespace to rest of line */		while (_istspace (*rest))			rest++;		/* Scan internal command table */		for (cmdptr = cmds;; cmdptr++)		{			/* If end of table execute ext cmd */			if (cmdptr->name == NULL)			{				Execute (com, rest);				break;			}			if (!_tcscmp (com, cmdptr->name))			{				cmdptr->func (com, rest);				break;			}			/* The following code handles the case of commands like CD which			 * are recognised even when the command name and parameter are			 * not space separated.			 *			 * e.g dir..			 * cd\freda			 */			/* Get length of command name */			cl = _tcslen (cmdptr->name);			if ((cmdptr->flags & CMD_SPECIAL) &&			    (!_tcsncmp (cmdptr->name, com, cl)) &&			    (_tcschr (_T("\\.-"), *(com + cl))))			{				/* OK its one of the specials...*/				/* Terminate first word properly */				com[cl] = _T('\0');				/* Call with new rest */				cmdptr->func (com, cstart + cl);				break;			}		}	}}/* * process the command line and execute the appropriate functions * full input/output redirection and piping are supported */VOID ParseCommandLine (LPTSTR cmd){	TCHAR cmdline[CMDLINE_LENGTH];	LPTSTR s;#ifdef FEATURE_REDIRECTION	TCHAR in[CMDLINE_LENGTH] = _T("");	TCHAR out[CMDLINE_LENGTH] = _T("");	TCHAR err[CMDLINE_LENGTH] = _T("");	TCHAR szTempPath[MAX_PATH] = _T(".\\");	TCHAR szFileName[2][MAX_PATH] = {_T(""), _T("")};	HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};	LPTSTR t = NULL;	INT  num = 0;	INT  nRedirFlags = 0;	DWORD dwSize;	WCHAR  szOldConIn[MAX_PATH];	WCHAR  szOldConOut[MAX_PATH];	WCHAR  szOldConErr[MAX_PATH];#endif /* FEATURE_REDIRECTION */	_tcscpy (cmdline, cmd);	s = &cmdline[0];#ifdef _DEBUG	DebugPrintf (_T("ParseCommandLine: (\'%s\')\n"), s);#endif /* DEBUG */#ifdef FEATURE_ALIASES	/* expand all aliases */	ExpandAlias (s, CMDLINE_LENGTH);#endif /* FEATURE_ALIAS */#ifdef FEATURE_REDIRECTION		/* find the temp path to store temporary files */	GetTempPath (MAX_PATH, szTempPath);	if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\'))		_tcscat (szTempPath, _T("\\"));	/* get the redirections from the command line */	num = GetRedirection (s, in, out, err, &nRedirFlags);	/* more efficient, but do we really need to do this? */	for (t = in; _istspace (*t); t++)		;	_tcscpy (in, t);	for (t = out; _istspace (*t); t++)		;	_tcscpy (out, t);	for (t = err; _istspace (*t); t++)		;	_tcscpy (err, t);	/* Set up the initial conditions ... */	/* preserve STDIN, STDOUT and STDERR handles */		GetStdioPathW(0, szOldConIn, &dwSize);	GetStdioPathW(1, szOldConOut, &dwSize);	GetStdioPathW(2, szOldConErr, &dwSize);		/* redirect STDIN */	if (in[0])	{		HANDLE hFile = fileno(_wfreopen(in, L"rb", stdin));		if (hFile == INVALID_HANDLE_VALUE)		{			ConErrPrintf (_T("Can't redirect input from file %s\n"), in);			return;		}		#ifdef _DEBUG		DebugPrintf (_T("Input redirected from: %s\n"), in);#endif	}	/* Now do all but the last pipe command */	*szFileName[0] = '\0';	hFile[0] = INVALID_HANDLE_VALUE;	while (num-- > 1)	{		/* Create unique temporary file name */		GetTempFileName (szTempPath, _T("CMD"), 0, szFileName[1]);		/* Set current stdout to temporary file */		hFile[1] = fileno(_wfreopen(szFileName[1], L"wb", stdout));		DoCommand (s);		/* close stdout file */		_wfreopen(szOldConOut, L"wb", stdout);		hFile[1] = INVALID_HANDLE_VALUE;		/* close old stdin file */		_wfreopen(szOldConIn, L"rb", stdin);		if ((hFile[0] != INVALID_HANDLE_VALUE) && wcscmp(szFileName[0], szOldConIn))		{			/* delete old stdin file, if it is a real file */			hFile[0] = INVALID_HANDLE_VALUE;			DeleteFile (szFileName[0]);			*szFileName[0] = _T('\0');		}		/* copy stdout file name to stdin file name */		_tcscpy (szFileName[0], szFileName[1]);		*szFileName[1] = _T('\0');		/* open new stdin file */		hFile[0] = fileno(_wfreopen(szFileName[0], L"rb", stdin));		s = s + _tcslen (s) + 1;	}	/* Now set up the end conditions... */	/* redirect STDOUT */	if (out[0])	{		/* Final output to here */		FILE *file;		if (nRedirFlags & OUTPUT_APPEND) 		  file = _wfreopen(out, L"ab", stdout);		else		  file = _wfreopen(out, L"wb", stdout);		if (!file)		{			ConErrPrintf (_T("Can't redirect to file %s\n"), out);			return;		}#ifdef _DEBUG		DebugPrintf (_T("Output redirected to: %s\n"), out);#endif	}	else if (*szOldConOut)	{		/* Restore original stdout */		WCHAR szOut[MAX_PATH];		GetStdioPathW (STD_OUTPUT_HANDLE, szOut, &dwSize);		_wfreopen( szOldConOut, L"wb", stdout);	}	/* redirect STDERR */		if (err[0])	{		/* Final output to here */		FILE *file;		if (!_tcscmp (err, out))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -