3 * CMD.C - command-line interface.
8 * 17 Jun 1994 (Tim Norman)
11 * 08 Aug 1995 (Matt Rains)
12 * I have cleaned up the source code. changes now bring this source
13 * into guidelines for recommended programming practice.
15 * A added the the standard FreeDOS GNU licence test to the
16 * initialize() function.
18 * Started to replace puts() with printf(). this will help
19 * standardize output. please follow my lead.
21 * I have added some constants to help making changes easier.
23 * 15 Dec 1995 (Tim Norman)
24 * major rewrite of the code to make it more efficient and add
25 * redirection support (finally!)
27 * 06 Jan 1996 (Tim Norman)
28 * finished adding redirection support! Changed to use our own
29 * exec code (MUCH thanks to Svante Frey!!)
31 * 29 Jan 1996 (Tim Norman)
32 * added support for CHDIR, RMDIR, MKDIR, and ERASE, as per
33 * suggestion of Steffan Kaiser
35 * changed "file not found" error message to "bad command or
36 * filename" thanks to Dustin Norman for noticing that confusing
39 * changed the format to call internal commands (again) so that if
40 * they want to split their commands, they can do it themselves
41 * (none of the internal functions so far need that much power, anyway)
43 * 27 Aug 1996 (Tim Norman)
44 * added in support for Oliver Mueller's ALIAS command
46 * 14 Jun 1997 (Steffan Kaiser)
47 * added ctrl-break handling and error level
49 * 16 Jun 1998 (Rob Lake)
50 * Runs command.com if /P is specified in command line. Command.com
51 * also stays permanent. If /C is in the command line, starts the
52 * program next in the line.
54 * 21 Jun 1998 (Rob Lake)
55 * Fixed up /C so that arguments for the program
57 * 08-Jul-1998 (John P. Price)
58 * Now sets COMSPEC environment variable
59 * misc clean up and optimization
60 * added date and time commands
61 * changed to using spawnl instead of exec. exec does not copy the
62 * environment to the child process!
64 * 14 Jul 1998 (Hans B Pufal)
65 * Reorganised source to be more efficient and to more closely
66 * follow MS-DOS conventions. (eg %..% environment variable
67 * replacement works form command line as well as batch file.
69 * New organisation also properly support nested batch files.
71 * New command table structure is half way towards providing a
72 * system in which COMMAND will find out what internal commands
75 * 24 Jul 1998 (Hans B Pufal) [HBP_003]
76 * Fixed return value when called with /C option
78 * 27 Jul 1998 John P. Price
79 * added config.h include
81 * 28 Jul 1998 John P. Price
82 * added showcmds function to show commands and options available
84 * 07-Aug-1998 (John P Price <linux-guru@gcfl.net>)
85 * Fixed carrage return output to better match MSDOS with echo
86 * on or off. (marked with "JPP 19980708")
88 * 07-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
89 * First ReactOS release.
90 * Extended length of commandline buffers to 512.
92 * 13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
93 * Added COMSPEC environment variable.
94 * Added "/t" support (color) on cmd command line.
96 * 07-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
97 * Added help text ("cmd /?").
99 * 25-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
100 * Unicode and redirection safe!
101 * Fixed redirections and piping.
102 * Piping is based on temporary files, but basic support
103 * for anonymous pipes already exists.
105 * 27-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
106 * Replaced spawnl() by CreateProcess().
108 * 22-Oct-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
109 * Added break handler.
111 * 15-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
112 * Fixed current directory
114 * 28-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
115 * Restore window title after program/batch execution
117 * 03-Feb-2001 (Eric Kohl <ekohl@rz-online.de>)
118 * Workaround because argc[0] is NULL under ReactOS
120 * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
121 * %envvar% replacement conflicted with for.
137 BOOL bExit = FALSE; /* indicates EXIT was typed */
138 BOOL bCanExit = TRUE; /* indicates if this shell is exitable */
139 BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */
140 BOOL bIgnoreEcho = FALSE; /* Ignore 'newline' before 'cls' */
141 INT nErrorLevel = 0; /* Errorlevel of last launched external program */
142 BOOL bChildProcessRunning = FALSE;
143 DWORD dwChildProcessId = 0;
148 #ifdef INCLUDE_CMD_COLOR
149 WORD wColor; /* current color */
150 WORD wDefColor; /* default color */
155 * is character a delimeter when used on first word?
159 static BOOL IsDelimiter (TCHAR c)
161 return (c == _T('/') || c == _T('=') || c == _T('\0') || _istspace (c));
166 * This command (in first) was not found in the command table
168 * first - first word on command line
169 * rest - rest of command line
173 Execute (LPTSTR first, LPTSTR rest)
175 TCHAR szFullName[MAX_PATH];
177 TCHAR szWindowTitle[MAX_PATH];
179 DWORD dwExitCode = 0;
182 DebugPrintf ("Execute: \'%s\' \'%s\'\n", first, rest);
185 /* check for a drive change */
186 if ((_istalpha (first[0])) && (!_tcscmp (first + 1, _T(":"))))
189 if (!SetCurrentDirectory(first))
190 /* Guess they changed disc or something, handle that gracefully and get to root */
197 working = SetCurrentDirectory(str);
200 if (!working) ConErrPuts (INVALIDDRIVE);
205 /* get the PATH environment variable and parse it */
206 /* search the PATH environment variable for the binary */
207 if (!SearchForExecutable (first, szFullName))
209 error_bad_command ();
214 GetConsoleTitle (szWindowTitle, MAX_PATH);
217 /* check if this is a .BAT or .CMD file */
218 if (!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".bat")) ||
219 !_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".cmd")))
222 DebugPrintf ("[BATCH: %s %s]\n", szFullName, rest);
224 Batch (szFullName, first, rest);
228 /* exec the program */
229 TCHAR szFullCmdLine [CMDLINE_LENGTH];
230 PROCESS_INFORMATION prci;
234 DebugPrintf ("[EXEC: %s %s]\n", szFullName, rest);
236 /* build command line for CreateProcess() */
237 _tcscpy (szFullCmdLine, first);
238 _tcscat (szFullCmdLine, _T(" "));
239 _tcscat (szFullCmdLine, rest);
241 /* fill startup info */
242 memset (&stui, 0, sizeof (STARTUPINFO));
243 stui.cb = sizeof (STARTUPINFO);
244 stui.dwFlags = STARTF_USESHOWWINDOW;
245 stui.wShowWindow = SW_SHOWDEFAULT;
247 // return console to standard mode
248 SetConsoleMode (GetStdHandle(STD_INPUT_HANDLE),
249 ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
251 if (CreateProcess (szFullName,
256 CREATE_NEW_PROCESS_GROUP,
262 /* FIXME: Protect this with critical section */
263 bChildProcessRunning = TRUE;
264 dwChildProcessId = prci.dwProcessId;
266 WaitForSingleObject (prci.hProcess, INFINITE);
268 /* FIXME: Protect this with critical section */
269 bChildProcessRunning = TRUE;
271 GetExitCodeProcess (prci.hProcess, &dwExitCode);
272 nErrorLevel = (INT)dwExitCode;
273 CloseHandle (prci.hThread);
274 CloseHandle (prci.hProcess);
278 ErrorMessage (GetLastError (),
279 "Error executing CreateProcess()!!\n");
281 // restore console mode
282 SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
283 ENABLE_PROCESSED_INPUT );
287 SetConsoleTitle (szWindowTitle);
293 * look through the internal commands and determine whether or not this
294 * command is one of them. If it is, call the command. If not, call
295 * execute to run it as an external program.
297 * line - the command line of the program to run
302 DoCommand (LPTSTR line)
304 TCHAR com[MAX_PATH]; /* the first word in the command */
307 LPTSTR rest = line; /* pointer to the rest of the command line */
312 DebugPrintf ("DoCommand: (\'%s\')\n", line);
315 /* Skip over initial white space */
316 while (isspace (*rest))
321 /* Anything to do ? */
324 if (*rest == _T('"'))
326 /* treat quoted words specially */
330 while(*rest != _T('\0') && *rest != _T('"'))
331 *cp++ = _totlower (*rest++);
335 while (!IsDelimiter (*rest))
336 *cp++ = _totlower (*rest++);
340 /* Terminate first word */
343 /* Skip over whitespace to rest of line */
344 while (_istspace (*rest))
347 /* Scan internal command table */
348 for (cmdptr = cmds;; cmdptr++)
350 /* If end of table execute ext cmd */
351 if (cmdptr->name == NULL)
357 if (!_tcscmp (com, cmdptr->name))
359 cmdptr->func (com, rest);
363 /* The following code handles the case of commands like CD which
364 * are recognised even when the command name and parameter are
365 * not space separated.
371 /* Get length of command name */
372 cl = _tcslen (cmdptr->name);
374 if ((cmdptr->flags & CMD_SPECIAL) &&
375 (!_tcsncmp (cmdptr->name, com, cl)) &&
376 (_tcschr (_T("\\.-"), *(com + cl))))
378 /* OK its one of the specials...*/
380 /* Terminate first word properly */
383 /* Call with new rest */
384 cmdptr->func (com, cstart + cl);
393 * process the command line and execute the appropriate functions
394 * full input/output redirection and piping are supported
397 VOID ParseCommandLine (LPTSTR cmd)
399 TCHAR cmdline[CMDLINE_LENGTH];
401 #ifdef FEATURE_REDIRECTION
402 TCHAR in[CMDLINE_LENGTH] = "";
403 TCHAR out[CMDLINE_LENGTH] = "";
404 TCHAR err[CMDLINE_LENGTH] = "";
405 TCHAR szTempPath[MAX_PATH] = _T(".\\");
406 TCHAR szFileName[2][MAX_PATH] = {"", ""};
407 HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
415 #endif /* FEATURE_REDIRECTION */
417 _tcscpy (cmdline, cmd);
421 DebugPrintf ("ParseCommandLine: (\'%s\')\n", s);
424 #ifdef FEATURE_ALIASES
425 /* expand all aliases */
426 ExpandAlias (s, CMDLINE_LENGTH);
427 #endif /* FEATURE_ALIAS */
429 #ifdef FEATURE_REDIRECTION
430 /* find the temp path to store temporary files */
431 GetTempPath (MAX_PATH, szTempPath);
432 if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\'))
433 _tcscat (szTempPath, _T("\\"));
435 /* get the redirections from the command line */
436 num = GetRedirection (s, in, out, err, &nRedirFlags);
438 /* more efficient, but do we really need to do this? */
439 for (t = in; _istspace (*t); t++)
443 for (t = out; _istspace (*t); t++)
447 for (t = err; _istspace (*t); t++)
451 /* Set up the initial conditions ... */
452 /* preserve STDIN, STDOUT and STDERR handles */
453 hOldConIn = GetStdHandle (STD_INPUT_HANDLE);
454 hOldConOut = GetStdHandle (STD_OUTPUT_HANDLE);
455 hOldConErr = GetStdHandle (STD_ERROR_HANDLE);
461 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
463 hFile = CreateFile (in, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING,
464 FILE_ATTRIBUTE_NORMAL, NULL);
465 if (hFile == INVALID_HANDLE_VALUE)
467 ConErrPrintf ("Can't redirect input from file %s\n", in);
471 if (!SetStdHandle (STD_INPUT_HANDLE, hFile))
473 ConErrPrintf ("Can't redirect input from file %s\n", in);
477 DebugPrintf (_T("Input redirected from: %s\n"), in);
481 /* Now do all but the last pipe command */
482 *szFileName[0] = '\0';
483 hFile[0] = INVALID_HANDLE_VALUE;
487 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
489 /* Create unique temporary file name */
490 GetTempFileName (szTempPath, "CMD", 0, szFileName[1]);
492 /* Set current stdout to temporary file */
493 hFile[1] = CreateFile (szFileName[1], GENERIC_WRITE, 0, &sa,
494 TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
495 SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
499 /* close stdout file */
500 SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
501 if ((hFile[1] != INVALID_HANDLE_VALUE) && (hFile[1] != hOldConOut))
503 CloseHandle (hFile[1]);
504 hFile[1] = INVALID_HANDLE_VALUE;
507 /* close old stdin file */
508 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
509 if ((hFile[0] != INVALID_HANDLE_VALUE) && (hFile[0] != hOldConIn))
511 /* delete old stdin file, if it is a real file */
512 CloseHandle (hFile[0]);
513 hFile[0] = INVALID_HANDLE_VALUE;
514 DeleteFile (szFileName[0]);
515 *szFileName[0] = _T('\0');
518 /* copy stdout file name to stdin file name */
519 _tcscpy (szFileName[0], szFileName[1]);
520 *szFileName[1] = _T('\0');
522 /* open new stdin file */
523 hFile[0] = CreateFile (szFileName[0], GENERIC_READ, 0, &sa,
524 OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
525 SetStdHandle (STD_INPUT_HANDLE, hFile[0]);
527 s = s + _tcslen (s) + 1;
530 /* Now set up the end conditions... */
531 /* redirect STDOUT */
534 /* Final output to here */
536 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
538 hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_READ, &sa,
539 (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
540 FILE_ATTRIBUTE_NORMAL, NULL);
541 if (hFile == INVALID_HANDLE_VALUE)
543 ConErrPrintf ("Can't redirect to file %s\n", out);
547 if (!SetStdHandle (STD_OUTPUT_HANDLE, hFile))
549 ConErrPrintf ("Can't redirect to file %s\n", out);
553 if (nRedirFlags & OUTPUT_APPEND)
557 if (GetFileType (hFile) == FILE_TYPE_DISK)
558 SetFilePointer (hFile, 0, &lHighPos, FILE_END);
561 DebugPrintf (_T("Output redirected to: %s\n"), out);
564 else if (hOldConOut != INVALID_HANDLE_VALUE)
566 /* Restore original stdout */
567 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
568 SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
569 if (hOldConOut != hOut)
571 hOldConOut = INVALID_HANDLE_VALUE;
574 /* redirect STDERR */
577 /* Final output to here */
579 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
581 if (!_tcscmp (err, out))
584 DebugPrintf (_T("Stdout and stderr will use the same file!!\n"));
586 DuplicateHandle (GetCurrentProcess (),
587 GetStdHandle (STD_OUTPUT_HANDLE),
588 GetCurrentProcess (),
589 &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS);
593 hFile = CreateFile (err,
597 (nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
598 FILE_ATTRIBUTE_NORMAL,
600 if (hFile == INVALID_HANDLE_VALUE)
602 ConErrPrintf ("Can't redirect to file %s\n", err);
606 if (!SetStdHandle (STD_ERROR_HANDLE, hFile))
608 ConErrPrintf ("Can't redirect to file %s\n", err);
612 if (nRedirFlags & ERROR_APPEND)
616 if (GetFileType (hFile) == FILE_TYPE_DISK)
617 SetFilePointer (hFile, 0, &lHighPos, FILE_END);
620 DebugPrintf (_T("Error redirected to: %s\n"), err);
623 else if (hOldConErr != INVALID_HANDLE_VALUE)
625 /* Restore original stderr */
626 HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE);
627 SetStdHandle (STD_ERROR_HANDLE, hOldConErr);
628 if (hOldConErr != hErr)
630 hOldConErr = INVALID_HANDLE_VALUE;
634 /* process final command */
637 #ifdef FEATURE_REDIRECTION
638 /* close old stdin file */
639 #if 0 /* buggy implementation */
640 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
641 if ((hFile[0] != INVALID_HANDLE_VALUE) &&
642 (hFile[0] != hOldConIn))
644 /* delete old stdin file, if it is a real file */
645 CloseHandle (hFile[0]);
646 hFile[0] = INVALID_HANDLE_VALUE;
647 DeleteFile (szFileName[0]);
648 *szFileName[0] = _T('\0');
651 /* Restore original STDIN */
652 if (hOldConIn != INVALID_HANDLE_VALUE)
654 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
655 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
656 if (hOldConIn != hIn)
658 hOldConIn = INVALID_HANDLE_VALUE;
663 DebugPrintf (_T("Can't restore STDIN! Is invalid!!\n"), out);
666 #endif /* buggy implementation */
669 if (hOldConIn != INVALID_HANDLE_VALUE)
671 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
672 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
673 if (hIn == INVALID_HANDLE_VALUE)
676 DebugPrintf (_T("Previous STDIN is invalid!!\n"));
681 if (GetFileType (hIn) == FILE_TYPE_DISK)
685 CloseHandle (hFile[0]);
686 hFile[0] = INVALID_HANDLE_VALUE;
687 DeleteFile (szFileName[0]);
688 *szFileName[0] = _T('\0');
693 DebugPrintf (_T("hFile[0] and hIn dont match!!!\n"));
701 /* Restore original STDOUT */
702 if (hOldConOut != INVALID_HANDLE_VALUE)
704 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
705 SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
706 if (hOldConOut != hOut)
708 hOldConOut = INVALID_HANDLE_VALUE;
711 /* Restore original STDERR */
712 if (hOldConErr != INVALID_HANDLE_VALUE)
714 HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE);
715 SetStdHandle (STD_ERROR_HANDLE, hOldConErr);
716 if (hOldConErr != hErr)
718 hOldConErr = INVALID_HANDLE_VALUE;
720 #endif /* FEATURE_REDIRECTION */
725 * do the prompt/input/process loop
730 ProcessInput (BOOL bFlag)
732 TCHAR commandline[CMDLINE_LENGTH];
733 TCHAR readline[CMDLINE_LENGTH];
741 /* if no batch input then... */
742 if (!(ip = ReadBatchLine (&bEchoThisLine)))
747 ReadCommand (readline, CMDLINE_LENGTH);
749 bEchoThisLine = FALSE;
773 if ((tp = FindArg (*ip - _T('0'))))
775 cp = stpcpy (cp, tp);
783 cp += _stprintf (cp, _T("%u"), nErrorLevel);
788 tp = _tcschr(ip, _T('%'));
790 (tp <= _tcschr(ip, _T(' ')) - 1))
795 /* FIXME: This is just a quick hack!! */
796 /* Do a proper memory allocation!! */
797 if (GetEnvironmentVariable (ip, evar, 512))
798 cp = stpcpy (cp, evar);
818 /* strip trailing spaces */
819 while ((--cp >= commandline) && _istspace (*cp));
821 *(cp + 1) = _T('\0');
824 /* Echo batch file line */
828 ConOutPuts (commandline);
833 ParseCommandLine (commandline);
834 if (bEcho && !bIgnoreEcho)
839 while (!bCanExit || !bExit);
846 * control-break handler.
848 BOOL BreakHandler (DWORD dwCtrlType)
850 if ((dwCtrlType != CTRL_C_EVENT) &&
851 (dwCtrlType != CTRL_BREAK_EVENT))
854 if (bChildProcessRunning == TRUE)
856 GenerateConsoleCtrlEvent (CTRL_C_EVENT,
861 /* FIXME: Handle batch files */
863 /* FIXME: Print "^C" */
870 VOID AddBreakHandler (VOID)
873 SetConsoleCtrlHandler ((PHANDLER_ROUTINE)&BreakHandler,
879 VOID RemoveBreakHandler (VOID)
882 SetConsoleCtrlHandler (NULL, FALSE);
888 * show commands and options that are available.
894 /* print command list */
895 ConOutPrintf (_T("\nInternal commands available:\n"));
898 /* print feature list */
899 ConOutPuts ("\nFeatures available:");
900 #ifdef FEATURE_ALIASES
901 ConOutPuts (" [aliases]");
903 #ifdef FEATURE_HISTORY
904 ConOutPuts (" [history]");
906 #ifdef FEATURE_UNIX_FILENAME_COMPLETION
907 ConOutPuts (" [unix filename completion]");
909 #ifdef FEATURE_DIRECTORY_STACK
910 ConOutPuts (" [directory stack]");
912 #ifdef FEATURE_REDIRECTION
913 ConOutPuts (" [redirections and piping]");
920 * set up global initializations and process parameters
922 * argc - number of parameters to command.com
923 * argv - command-line parameters
927 Initialize (int argc, char *argv[])
929 TCHAR commandline[CMDLINE_LENGTH];
930 TCHAR ModuleName[_MAX_PATH + 1];
936 DebugPrintf ("[command args:\n");
937 for (x = 0; x < argc; x++)
939 DebugPrintf ("%d. %s\n", x, argv[x]);
944 /* get version information */
945 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
946 GetVersionEx (&osvi);
950 /* get default input and output console handles */
951 hOut = GetStdHandle (STD_OUTPUT_HANDLE);
952 hIn = GetStdHandle (STD_INPUT_HANDLE);
955 if (argc >= 2 && !_tcsncmp (argv[1], _T("/?"), 2))
957 ConOutPuts (_T("Starts a new instance of the ReactOS command line interpreter.\n"
959 "CMD [/[C|K] command][/P][/Q][/T:bf]\n"
961 " /C command Runs the specified command and terminates.\n"
962 " /K command Runs the specified command and remains.\n"
963 " /P CMD becomes permanent and runs autoexec.bat\n"
964 " (cannot be terminated).\n"
965 " /T:bf Sets the background/foreground color (see COLOR command)."));
968 SetConsoleMode (hIn, ENABLE_PROCESSED_INPUT);
970 #ifdef INCLUDE_CMD_CHDIR
974 #ifdef FATURE_ALIASES
980 for (i = 1; i < argc; i++)
982 if (!_tcsicmp (argv[i], _T("/p")))
984 if (!IsValidFileName (_T("\\autoexec.bat")))
986 #ifdef INCLUDE_CMD_DATE
989 #ifdef INCLUDE_CMD_TIME
995 ParseCommandLine (_T("\\autoexec.bat"));
999 else if (!_tcsicmp (argv[i], _T("/c")))
1001 /* This just runs a program and exits */
1005 _tcscpy (commandline, argv[i]);
1008 _tcscat (commandline, " ");
1009 _tcscat (commandline, argv[i]);
1012 ParseCommandLine(commandline);
1013 ExitProcess (ProcessInput (TRUE));
1020 else if (!_tcsicmp (argv[i], _T("/k")))
1022 /* This just runs a program and remains */
1026 _tcscpy (commandline, argv[i]);
1029 _tcscat (commandline, " ");
1030 _tcscat (commandline, argv[i]);
1033 ParseCommandLine(commandline);
1036 #ifdef INCLUDE_CMD_COLOR
1037 else if (!_tcsnicmp (argv[i], _T("/t:"), 3))
1039 /* process /t (color) argument */
1040 wDefColor = (WORD)strtoul (&argv[i][3], NULL, 16);
1042 SetScreenColor (wColor, TRUE);
1048 /* run cmdstart.bat */
1049 if (IsValidFileName (_T("cmdstart.bat")))
1051 ParseCommandLine (_T("cmdstart.bat"));
1053 else if (IsValidFileName (_T("\\cmdstart.bat")))
1055 ParseCommandLine (_T("\\cmdstart.bat"));
1060 /* try to run cmdstart.bat from install dir */
1063 _tcscpy (commandline, argv[0]);
1064 p = _tcsrchr (commandline, _T('\\')) + 1;
1065 _tcscpy (p, _T("cmdstart.bat"));
1067 if (IsValidFileName (_T("commandline")))
1069 ConErrPrintf ("Running %s...\n", commandline);
1070 ParseCommandLine (commandline);
1075 #ifdef FEATURE_DIR_STACK
1076 /* initialize directory stack */
1077 InitDirectoryStack ();
1081 #ifdef FEATURE_HISTORY
1082 /*initialize history*/
1086 /* Set COMSPEC environment variable */
1087 if (0 != GetModuleFileName (NULL, ModuleName, _MAX_PATH + 1))
1089 ModuleName[_MAX_PATH] = _T('\0');
1090 SetEnvironmentVariable (_T("COMSPEC"), ModuleName);
1093 /* add ctrl break handler */
1098 static VOID Cleanup (int argc, char *argv[])
1100 /* run cmdexit.bat */
1101 if (IsValidFileName (_T("cmdexit.bat")))
1103 ConErrPrintf ("Running cmdexit.bat...\n");
1104 ParseCommandLine (_T("cmdexit.bat"));
1106 else if (IsValidFileName (_T("\\cmdexit.bat")))
1108 ConErrPrintf ("Running \\cmdexit.bat...\n");
1109 ParseCommandLine (_T("\\cmdexit.bat"));
1114 /* try to run cmdexit.bat from install dir */
1115 TCHAR commandline[CMDLINE_LENGTH];
1118 _tcscpy (commandline, argv[0]);
1119 p = _tcsrchr (commandline, _T('\\')) + 1;
1120 _tcscpy (p, _T("cmdexit.bat"));
1122 if (IsValidFileName (_T("commandline")))
1124 ConErrPrintf ("Running %s...\n", commandline);
1125 ParseCommandLine (commandline);
1130 #ifdef FEATURE_ALIASES
1134 #ifdef FEATURE_DIECTORY_STACK
1135 /* destroy directory stack */
1136 DestroyDirectoryStack ();
1139 #ifdef INCLUDE_CMD_CHDIR
1143 #ifdef FEATURE_HISTORY
1148 /* remove ctrl break handler */
1149 RemoveBreakHandler ();
1150 SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
1151 ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
1158 int main (int argc, char *argv[])
1160 CONSOLE_SCREEN_BUFFER_INFO Info;
1166 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info) == FALSE)
1168 fprintf(stderr, "GetConsoleScreenBufferInfo: Error: %ld\n", GetLastError());
1170 /* On ReactOS GetConsoleScreenBufferInfo returns an error if the stdin
1171 handle is redirected to a pipe or file. This stops windres from working. */
1175 wColor = Info.wAttributes;
1178 /* check switches on command-line */
1179 Initialize(argc, argv);
1181 /* call prompt routine */
1182 nExitCode = ProcessInput(FALSE);
1184 /* do the cleanup */
1185 Cleanup(argc, argv);