adding %RANDOM% example how to use it echo %random%
[reactos.git] / reactos / subsys / system / cmd / cmd.c
1 /*
2 * CMD.C - command-line interface.
3 *
4 *
5 * History:
6 *
7 * 17 Jun 1994 (Tim Norman)
8 * started.
9 *
10 * 08 Aug 1995 (Matt Rains)
11 * I have cleaned up the source code. changes now bring this source
12 * into guidelines for recommended programming practice.
13 *
14 * A added the the standard FreeDOS GNU licence test to the
15 * initialize() function.
16 *
17 * Started to replace puts() with printf(). this will help
18 * standardize output. please follow my lead.
19 *
20 * I have added some constants to help making changes easier.
21 *
22 * 15 Dec 1995 (Tim Norman)
23 * major rewrite of the code to make it more efficient and add
24 * redirection support (finally!)
25 *
26 * 06 Jan 1996 (Tim Norman)
27 * finished adding redirection support! Changed to use our own
28 * exec code (MUCH thanks to Svante Frey!!)
29 *
30 * 29 Jan 1996 (Tim Norman)
31 * added support for CHDIR, RMDIR, MKDIR, and ERASE, as per
32 * suggestion of Steffan Kaiser
33 *
34 * changed "file not found" error message to "bad command or
35 * filename" thanks to Dustin Norman for noticing that confusing
36 * message!
37 *
38 * changed the format to call internal commands (again) so that if
39 * they want to split their commands, they can do it themselves
40 * (none of the internal functions so far need that much power, anyway)
41 *
42 * 27 Aug 1996 (Tim Norman)
43 * added in support for Oliver Mueller's ALIAS command
44 *
45 * 14 Jun 1997 (Steffan Kaiser)
46 * added ctrl-break handling and error level
47 *
48 * 16 Jun 1998 (Rob Lake)
49 * Runs command.com if /P is specified in command line. Command.com
50 * also stays permanent. If /C is in the command line, starts the
51 * program next in the line.
52 *
53 * 21 Jun 1998 (Rob Lake)
54 * Fixed up /C so that arguments for the program
55 *
56 * 08-Jul-1998 (John P. Price)
57 * Now sets COMSPEC environment variable
58 * misc clean up and optimization
59 * added date and time commands
60 * changed to using spawnl instead of exec. exec does not copy the
61 * environment to the child process!
62 *
63 * 14 Jul 1998 (Hans B Pufal)
64 * Reorganised source to be more efficient and to more closely
65 * follow MS-DOS conventions. (eg %..% environment variable
66 * replacement works form command line as well as batch file.
67 *
68 * New organisation also properly support nested batch files.
69 *
70 * New command table structure is half way towards providing a
71 * system in which COMMAND will find out what internal commands
72 * are loaded
73 *
74 * 24 Jul 1998 (Hans B Pufal) [HBP_003]
75 * Fixed return value when called with /C option
76 *
77 * 27 Jul 1998 John P. Price
78 * added config.h include
79 *
80 * 28 Jul 1998 John P. Price
81 * added showcmds function to show commands and options available
82 *
83 * 07-Aug-1998 (John P Price <linux-guru@gcfl.net>)
84 * Fixed carrage return output to better match MSDOS with echo
85 * on or off. (marked with "JPP 19980708")
86 *
87 * 07-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
88 * First ReactOS release.
89 * Extended length of commandline buffers to 512.
90 *
91 * 13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
92 * Added COMSPEC environment variable.
93 * Added "/t" support (color) on cmd command line.
94 *
95 * 07-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
96 * Added help text ("cmd /?").
97 *
98 * 25-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
99 * Unicode and redirection safe!
100 * Fixed redirections and piping.
101 * Piping is based on temporary files, but basic support
102 * for anonymous pipes already exists.
103 *
104 * 27-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
105 * Replaced spawnl() by CreateProcess().
106 *
107 * 22-Oct-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
108 * Added break handler.
109 *
110 * 15-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
111 * Fixed current directory
112 *
113 * 28-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
114 * Restore window title after program/batch execution
115 *
116 * 03-Feb-2001 (Eric Kohl <ekohl@rz-online.de>)
117 * Workaround because argc[0] is NULL under ReactOS
118 *
119 * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
120 * %envvar% replacement conflicted with for.
121 *
122 * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
123 * Make MakeSureDirectoryPathExistsEx unicode safe.
124 *
125 * 28-Mai-2004 (Hartmut Birr)
126 * Removed MakeSureDirectoryPathExistsEx.
127 * Use the current directory if GetTempPath fails.
128 *
129 * 12-Jul-2004 (Jens Collin <jens.collin@lakhei.com>)
130 * Added ShellExecute call when all else fails to be able to "launch" any file.
131 *
132 * 02-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
133 * Remove all hardcode string to En.rc
134 *
135 * 06-May-2005 (Klemens Friedl <frik85@gmail.com>)
136 * Add 'help' command (list all commands plus description)
137 *
138 * 06-jul-2005 (Magnus Olsen <magnus@greatlord.com>)
139 * translate '%errorlevel%' to the internal value.
140 * Add proper memmory alloc ProcessInput, the error
141 * handling for memmory handling need to be improve
142 */
143
144 #include <precomp.h>
145 #include "resource.h"
146
147 #ifndef NT_SUCCESS
148 #define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
149 #endif
150
151 typedef NTSTATUS (STDCALL *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASS,
152 PVOID, ULONG, PULONG);
153 typedef NTSTATUS (STDCALL *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG);
154
155 BOOL bExit = FALSE; /* indicates EXIT was typed */
156 BOOL bCanExit = TRUE; /* indicates if this shell is exitable */
157 BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */
158 BOOL bIgnoreEcho = FALSE; /* Ignore 'newline' before 'cls' */
159 INT nErrorLevel = 0; /* Errorlevel of last launched external program */
160 BOOL bChildProcessRunning = FALSE;
161 DWORD dwChildProcessId = 0;
162 OSVERSIONINFO osvi;
163 HANDLE hIn;
164 HANDLE hOut;
165 HANDLE hConsole;
166 HANDLE CMD_ModuleHandle;
167
168 static NtQueryInformationProcessProc NtQueryInformationProcessPtr;
169 static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr;
170 static BOOL NtDllChecked = FALSE;
171
172 #ifdef INCLUDE_CMD_COLOR
173 WORD wColor; /* current color */
174 WORD wDefColor; /* default color */
175 #endif
176
177 /*
178 * is character a delimeter when used on first word?
179 *
180 */
181
182 static BOOL IsDelimiter (TCHAR c)
183 {
184 return (c == _T('/') || c == _T('=') || c == _T('\0') || _istspace (c));
185 }
186
187 /*
188 * Is a process a console process?
189 */
190 static BOOL IsConsoleProcess(HANDLE Process)
191 {
192 NTSTATUS Status;
193 PROCESS_BASIC_INFORMATION Info;
194 PEB ProcessPeb;
195 ULONG BytesRead;
196 HMODULE NtDllModule;
197
198 /* Some people like to run ReactOS cmd.exe on Win98, it helps in the
199 build process. So don't link implicitly against ntdll.dll, load it
200 dynamically instead */
201 if (! NtDllChecked)
202 {
203 NtDllChecked = TRUE;
204 NtDllModule = LoadLibrary(_T("ntdll.dll"));
205 if (NULL == NtDllModule)
206 {
207 /* Probably non-WinNT system. Just wait for the commands
208 to finish. */
209 NtQueryInformationProcessPtr = NULL;
210 NtReadVirtualMemoryPtr = NULL;
211 return TRUE;
212 }
213 NtQueryInformationProcessPtr = (NtQueryInformationProcessProc)
214 GetProcAddress(NtDllModule, "NtQueryInformationProcess");
215 NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)
216 GetProcAddress(NtDllModule, "NtReadVirtualMemory");
217 }
218
219 if (NULL == NtQueryInformationProcessPtr || NULL == NtReadVirtualMemoryPtr)
220 {
221 return TRUE;
222 }
223
224 Status = NtQueryInformationProcessPtr(Process, ProcessBasicInformation,
225 &Info, sizeof(PROCESS_BASIC_INFORMATION), NULL);
226 if (! NT_SUCCESS(Status))
227 {
228 #ifdef _DEBUG
229 DebugPrintf (_T("NtQueryInformationProcess failed with status %08x\n"), Status);
230 #endif
231 return TRUE;
232 }
233 Status = NtReadVirtualMemoryPtr(Process, Info.PebBaseAddress, &ProcessPeb,
234 sizeof(PEB), &BytesRead);
235 if (! NT_SUCCESS(Status) || sizeof(PEB) != BytesRead)
236 {
237 #ifdef _DEBUG
238 DebugPrintf (_T("Couldn't read virt mem status %08x bytes read %lu\n"), Status, BytesRead);
239 #endif
240 return TRUE;
241 }
242
243 return IMAGE_SUBSYSTEM_WINDOWS_CUI == ProcessPeb.ImageSubSystem;
244 }
245
246
247
248 #ifdef _UNICODE
249 #define SHELLEXECUTETEXT "ShellExecuteW"
250 #else
251 #define SHELLEXECUTETEXT "ShellExecuteA"
252 #endif
253
254 typedef HINSTANCE (WINAPI *MYEX)(
255 HWND hwnd,
256 LPCTSTR lpOperation,
257 LPCTSTR lpFile,
258 LPCTSTR lpParameters,
259 LPCTSTR lpDirectory,
260 INT nShowCmd
261 );
262
263
264
265 static BOOL RunFile(LPTSTR filename)
266 {
267 HMODULE hShell32;
268 MYEX hShExt;
269 HINSTANCE ret;
270
271 #ifdef _DEBUG
272 DebugPrintf (_T("RunFile(%s)\n"), filename);
273 #endif
274 hShell32 = LoadLibrary(_T("SHELL32.DLL"));
275 if (!hShell32)
276 {
277 #ifdef _DEBUG
278 DebugPrintf (_T("RunFile: couldn't load SHELL32.DLL!\n"));
279 #endif
280 return FALSE;
281 }
282
283 hShExt = (MYEX)(FARPROC)GetProcAddress(hShell32, SHELLEXECUTETEXT);
284 if (!hShExt)
285 {
286 #ifdef _DEBUG
287 DebugPrintf (_T("RunFile: couldn't find ShellExecuteA/W in SHELL32.DLL!\n"));
288 #endif
289 FreeLibrary(hShell32);
290 return FALSE;
291 }
292
293 #ifdef _DEBUG
294 DebugPrintf (_T("RunFile: ShellExecuteA/W is at %x\n"), hShExt);
295 #endif
296
297 ret = (hShExt)(NULL, _T("open"), filename, NULL, NULL, SW_SHOWNORMAL);
298
299 #ifdef _DEBUG
300 DebugPrintf (_T("RunFile: ShellExecuteA/W returned %d\n"), (DWORD)ret);
301 #endif
302
303 FreeLibrary(hShell32);
304 return (((DWORD)ret) > 32);
305 }
306
307
308
309 /*
310 * This command (in first) was not found in the command table
311 *
312 * first - first word on command line
313 * rest - rest of command line
314 */
315
316 static VOID
317 Execute (LPTSTR full, LPTSTR first, LPTSTR rest)
318 {
319 TCHAR szFullName[MAX_PATH];
320 #ifndef __REACTOS__
321 TCHAR szWindowTitle[MAX_PATH];
322 #endif
323 DWORD dwExitCode = 0;
324
325 #ifdef _DEBUG
326 DebugPrintf (_T("Execute: \'%s\' \'%s\'\n"), first, rest);
327 #endif
328
329 /* check for a drive change */
330 if ((_istalpha (first[0])) && (!_tcscmp (first + 1, _T(":"))))
331 {
332 BOOL working = TRUE;
333 if (!SetCurrentDirectory(first))
334 /* Guess they changed disc or something, handle that gracefully and get to root */
335 {
336 TCHAR str[4];
337 str[0]=first[0];
338 str[1]=_T(':');
339 str[2]=_T('\\');
340 str[3]=0;
341 working = SetCurrentDirectory(str);
342 }
343
344 if (!working) ConErrResPuts (STRING_FREE_ERROR1);
345
346 return;
347 }
348
349 /* get the PATH environment variable and parse it */
350 /* search the PATH environment variable for the binary */
351 if (!SearchForExecutable (first, szFullName))
352 {
353 error_bad_command ();
354 return;
355 }
356
357 #ifndef __REACTOS__
358 GetConsoleTitle (szWindowTitle, MAX_PATH);
359 #endif
360
361 /* check if this is a .BAT or .CMD file */
362 if (!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".bat")) ||
363 !_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".cmd")))
364 {
365 #ifdef _DEBUG
366 DebugPrintf (_T("[BATCH: %s %s]\n"), szFullName, rest);
367 #endif
368 Batch (szFullName, first, rest);
369 }
370 else
371 {
372 /* exec the program */
373 PROCESS_INFORMATION prci;
374 STARTUPINFO stui;
375
376 #ifdef _DEBUG
377 DebugPrintf (_T("[EXEC: %s %s]\n"), full, rest);
378 #endif
379 /* build command line for CreateProcess() */
380
381 /* fill startup info */
382 memset (&stui, 0, sizeof (STARTUPINFO));
383 stui.cb = sizeof (STARTUPINFO);
384 stui.dwFlags = STARTF_USESHOWWINDOW;
385 stui.wShowWindow = SW_SHOWDEFAULT;
386
387 // return console to standard mode
388 SetConsoleMode (GetStdHandle(STD_INPUT_HANDLE),
389 ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
390
391 if (CreateProcess (szFullName,
392 full,
393 NULL,
394 NULL,
395 TRUE,
396 CREATE_NEW_PROCESS_GROUP,
397 NULL,
398 NULL,
399 &stui,
400 &prci))
401 {
402 if (IsConsoleProcess(prci.hProcess))
403 {
404 /* FIXME: Protect this with critical section */
405 bChildProcessRunning = TRUE;
406 dwChildProcessId = prci.dwProcessId;
407
408 WaitForSingleObject (prci.hProcess, INFINITE);
409
410 /* FIXME: Protect this with critical section */
411 bChildProcessRunning = FALSE;
412
413 GetExitCodeProcess (prci.hProcess, &dwExitCode);
414 nErrorLevel = (INT)dwExitCode;
415 }
416 CloseHandle (prci.hThread);
417 CloseHandle (prci.hProcess);
418 }
419 else
420 {
421 #ifdef _DEBUG
422 DebugPrintf (_T("[ShellExecute: %s]\n"), full);
423 #endif
424 // See if we can run this with ShellExecute() ie myfile.xls
425 if (!RunFile(full))
426 {
427 #ifdef _DEBUG
428 DebugPrintf (_T("[ShellExecute failed!: %s]\n"), full);
429 #endif
430 error_bad_command ();
431 }
432 }
433 // restore console mode
434 SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
435 ENABLE_PROCESSED_INPUT );
436 }
437
438 /* Get code page if it has been change */
439 InputCodePage= GetConsoleCP();
440 OutputCodePage = GetConsoleOutputCP();
441 #ifndef __REACTOS__
442 SetConsoleTitle (szWindowTitle);
443 #endif
444 }
445
446
447 /*
448 * look through the internal commands and determine whether or not this
449 * command is one of them. If it is, call the command. If not, call
450 * execute to run it as an external program.
451 *
452 * line - the command line of the program to run
453 *
454 */
455
456 static VOID
457 DoCommand (LPTSTR line)
458 {
459 TCHAR com[CMDLINE_LENGTH]; /* the first word in the command */
460 LPTSTR cp = com;
461 LPTSTR cstart;
462 LPTSTR rest; /* pointer to the rest of the command line */
463 INT cl;
464 LPCOMMAND cmdptr;
465
466 #ifdef _DEBUG
467 DebugPrintf (_T("DoCommand: (\'%s\')\n"), line);
468 #endif /* DEBUG */
469
470 /* Skip over initial white space */
471 while (_istspace (*line))
472 line++;
473 rest = line;
474
475 cstart = rest;
476
477 /* Anything to do ? */
478 if (*rest)
479 {
480 if (*rest == _T('"'))
481 {
482 /* treat quoted words specially */
483
484 rest++;
485
486 while(*rest != _T('\0') && *rest != _T('"'))
487 *cp++ = _totlower (*rest++);
488 if (*rest == _T('"'))
489 rest++;
490 }
491 else
492 {
493 while (!IsDelimiter (*rest))
494 *cp++ = _totlower (*rest++);
495 }
496
497
498 /* Terminate first word */
499 *cp = _T('\0');
500
501 /* commands are limited to MAX_PATH */
502 if(_tcslen(com) > MAX_PATH)
503 {
504 error_bad_command();
505 return;
506 }
507
508 /* Skip over whitespace to rest of line */
509 while (_istspace (*rest))
510 rest++;
511
512 /* Scan internal command table */
513 for (cmdptr = cmds;; cmdptr++)
514 {
515 /* If end of table execute ext cmd */
516 if (cmdptr->name == NULL)
517 {
518 Execute (line, com, rest);
519 break;
520 }
521
522 if (!_tcscmp (com, cmdptr->name))
523 {
524 cmdptr->func (com, rest);
525 break;
526 }
527
528 /* The following code handles the case of commands like CD which
529 * are recognised even when the command name and parameter are
530 * not space separated.
531 *
532 * e.g dir..
533 * cd\freda
534 */
535
536 /* Get length of command name */
537 cl = _tcslen (cmdptr->name);
538
539 if ((cmdptr->flags & CMD_SPECIAL) &&
540 (!_tcsncmp (cmdptr->name, com, cl)) &&
541 (_tcschr (_T("\\.-"), *(com + cl))))
542 {
543 /* OK its one of the specials...*/
544
545 /* Terminate first word properly */
546 com[cl] = _T('\0');
547
548 /* Call with new rest */
549 cmdptr->func (com, cstart + cl);
550 break;
551 }
552 }
553 }
554 }
555
556
557 /*
558 * process the command line and execute the appropriate functions
559 * full input/output redirection and piping are supported
560 */
561
562 VOID ParseCommandLine (LPTSTR cmd)
563 {
564 TCHAR szMsg[RC_STRING_MAX_SIZE];
565 TCHAR cmdline[CMDLINE_LENGTH];
566 LPTSTR s;
567 #ifdef FEATURE_REDIRECTION
568 TCHAR in[CMDLINE_LENGTH] = _T("");
569 TCHAR out[CMDLINE_LENGTH] = _T("");
570 TCHAR err[CMDLINE_LENGTH] = _T("");
571 TCHAR szTempPath[MAX_PATH] = _T(".\\");
572 TCHAR szFileName[2][MAX_PATH] = {_T(""), _T("")};
573 HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
574 LPTSTR t = NULL;
575 INT num = 0;
576 INT nRedirFlags = 0;
577 INT Length;
578 UINT Attributes;
579
580 HANDLE hOldConIn;
581 HANDLE hOldConOut;
582 HANDLE hOldConErr;
583 #endif /* FEATURE_REDIRECTION */
584
585 _tcscpy (cmdline, cmd);
586 s = &cmdline[0];
587
588 #ifdef _DEBUG
589 DebugPrintf (_T("ParseCommandLine: (\'%s\')\n"), s);
590 #endif /* DEBUG */
591
592 #ifdef FEATURE_ALIASES
593 /* expand all aliases */
594 ExpandAlias (s, CMDLINE_LENGTH);
595 #endif /* FEATURE_ALIAS */
596
597 #ifdef FEATURE_REDIRECTION
598 /* find the temp path to store temporary files */
599 Length = GetTempPath (MAX_PATH, szTempPath);
600 if (Length > 0 && Length < MAX_PATH)
601 {
602 Attributes = GetFileAttributes(szTempPath);
603 if (Attributes == 0xffffffff ||
604 !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
605 {
606 Length = 0;
607 }
608 }
609 if (Length == 0 || Length >= MAX_PATH)
610 {
611 _tcscpy(szTempPath, _T(".\\"));
612 }
613 if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\'))
614 _tcscat (szTempPath, _T("\\"));
615
616 /* get the redirections from the command line */
617 num = GetRedirection (s, in, out, err, &nRedirFlags);
618
619 /* more efficient, but do we really need to do this? */
620 for (t = in; _istspace (*t); t++)
621 ;
622 _tcscpy (in, t);
623
624 for (t = out; _istspace (*t); t++)
625 ;
626 _tcscpy (out, t);
627
628 for (t = err; _istspace (*t); t++)
629 ;
630 _tcscpy (err, t);
631
632 /* Set up the initial conditions ... */
633 /* preserve STDIN, STDOUT and STDERR handles */
634 hOldConIn = GetStdHandle (STD_INPUT_HANDLE);
635 hOldConOut = GetStdHandle (STD_OUTPUT_HANDLE);
636 hOldConErr = GetStdHandle (STD_ERROR_HANDLE);
637
638 /* redirect STDIN */
639 if (in[0])
640 {
641 HANDLE hFile;
642 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
643
644 hFile = CreateFile (in, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING,
645 FILE_ATTRIBUTE_NORMAL, NULL);
646 if (hFile == INVALID_HANDLE_VALUE)
647 {
648 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR1, szMsg, RC_STRING_MAX_SIZE);
649 ConErrPrintf(szMsg, in);
650 return;
651 }
652
653 if (!SetStdHandle (STD_INPUT_HANDLE, hFile))
654 {
655 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR1, szMsg, RC_STRING_MAX_SIZE);
656 ConErrPrintf(szMsg, in);
657 return;
658 }
659 #ifdef _DEBUG
660 DebugPrintf (_T("Input redirected from: %s\n"), in);
661 #endif
662 }
663
664 /* Now do all but the last pipe command */
665 *szFileName[0] = _T('\0');
666 hFile[0] = INVALID_HANDLE_VALUE;
667
668 while (num-- > 1)
669 {
670 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
671
672 /* Create unique temporary file name */
673 GetTempFileName (szTempPath, _T("CMD"), 0, szFileName[1]);
674
675 /* Set current stdout to temporary file */
676 hFile[1] = CreateFile (szFileName[1], GENERIC_WRITE, 0, &sa,
677 TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
678 if (hFile[1] == INVALID_HANDLE_VALUE)
679 {
680 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR2, szMsg, RC_STRING_MAX_SIZE);
681 ConErrPrintf(szMsg);
682 return;
683 }
684
685 SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
686
687 DoCommand (s);
688
689 /* close stdout file */
690 SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
691 if ((hFile[1] != INVALID_HANDLE_VALUE) && (hFile[1] != hOldConOut))
692 {
693 CloseHandle (hFile[1]);
694 hFile[1] = INVALID_HANDLE_VALUE;
695 }
696
697 /* close old stdin file */
698 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
699 if ((hFile[0] != INVALID_HANDLE_VALUE) && (hFile[0] != hOldConIn))
700 {
701 /* delete old stdin file, if it is a real file */
702 CloseHandle (hFile[0]);
703 hFile[0] = INVALID_HANDLE_VALUE;
704 DeleteFile (szFileName[0]);
705 *szFileName[0] = _T('\0');
706 }
707
708 /* copy stdout file name to stdin file name */
709 _tcscpy (szFileName[0], szFileName[1]);
710 *szFileName[1] = _T('\0');
711
712 /* open new stdin file */
713 hFile[0] = CreateFile (szFileName[0], GENERIC_READ, 0, &sa,
714 OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
715 SetStdHandle (STD_INPUT_HANDLE, hFile[0]);
716
717 s = s + _tcslen (s) + 1;
718 }
719
720 /* Now set up the end conditions... */
721 /* redirect STDOUT */
722 if (out[0])
723 {
724 /* Final output to here */
725 HANDLE hFile;
726 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
727
728 hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_READ, &sa,
729 (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
730 FILE_ATTRIBUTE_NORMAL, NULL);
731 if (hFile == INVALID_HANDLE_VALUE)
732 {
733 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
734 ConErrPrintf(szMsg, out);
735 return;
736 }
737
738 if (!SetStdHandle (STD_OUTPUT_HANDLE, hFile))
739 {
740 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
741 ConErrPrintf(szMsg, out);
742 return;
743 }
744
745 if (nRedirFlags & OUTPUT_APPEND)
746 {
747 LONG lHighPos = 0;
748
749 if (GetFileType (hFile) == FILE_TYPE_DISK)
750 SetFilePointer (hFile, 0, &lHighPos, FILE_END);
751 }
752 #ifdef _DEBUG
753 DebugPrintf (_T("Output redirected to: %s\n"), out);
754 #endif
755 }
756 else if (hOldConOut != INVALID_HANDLE_VALUE)
757 {
758 /* Restore original stdout */
759 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
760 SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
761 if (hOldConOut != hOut)
762 CloseHandle (hOut);
763 hOldConOut = INVALID_HANDLE_VALUE;
764 }
765
766 /* redirect STDERR */
767 if (err[0])
768 {
769 /* Final output to here */
770 HANDLE hFile;
771 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
772
773 if (!_tcscmp (err, out))
774 {
775 #ifdef _DEBUG
776 DebugPrintf (_T("Stdout and stderr will use the same file!!\n"));
777 #endif
778 DuplicateHandle (GetCurrentProcess (),
779 GetStdHandle (STD_OUTPUT_HANDLE),
780 GetCurrentProcess (),
781 &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS);
782 }
783 else
784 {
785 hFile = CreateFile (err,
786 GENERIC_WRITE,
787 0,
788 &sa,
789 (nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
790 FILE_ATTRIBUTE_NORMAL,
791 NULL);
792 if (hFile == INVALID_HANDLE_VALUE)
793 {
794 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
795 ConErrPrintf(szMsg, err);
796 return;
797 }
798 }
799
800 if (!SetStdHandle (STD_ERROR_HANDLE, hFile))
801 {
802 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
803 ConErrPrintf(szMsg, err);
804 return;
805 }
806
807 if (nRedirFlags & ERROR_APPEND)
808 {
809 LONG lHighPos = 0;
810
811 if (GetFileType (hFile) == FILE_TYPE_DISK)
812 SetFilePointer (hFile, 0, &lHighPos, FILE_END);
813 }
814 #ifdef _DEBUG
815 DebugPrintf (_T("Error redirected to: %s\n"), err);
816 #endif
817 }
818 else if (hOldConErr != INVALID_HANDLE_VALUE)
819 {
820 /* Restore original stderr */
821 HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE);
822 SetStdHandle (STD_ERROR_HANDLE, hOldConErr);
823 if (hOldConErr != hErr)
824 CloseHandle (hErr);
825 hOldConErr = INVALID_HANDLE_VALUE;
826 }
827 #endif
828
829 /* process final command */
830 DoCommand (s);
831
832 #ifdef FEATURE_REDIRECTION
833 /* close old stdin file */
834 #if 0 /* buggy implementation */
835 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
836 if ((hFile[0] != INVALID_HANDLE_VALUE) &&
837 (hFile[0] != hOldConIn))
838 {
839 /* delete old stdin file, if it is a real file */
840 CloseHandle (hFile[0]);
841 hFile[0] = INVALID_HANDLE_VALUE;
842 DeleteFile (szFileName[0]);
843 *szFileName[0] = _T('\0');
844 }
845
846 /* Restore original STDIN */
847 if (hOldConIn != INVALID_HANDLE_VALUE)
848 {
849 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
850 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
851 if (hOldConIn != hIn)
852 CloseHandle (hIn);
853 hOldConIn = INVALID_HANDLE_VALUE;
854 }
855 else
856 {
857 #ifdef _DEBUG
858 DebugPrintf (_T("Can't restore STDIN! Is invalid!!\n"), out);
859 #endif
860 }
861 #endif /* buggy implementation */
862
863
864 if (hOldConIn != INVALID_HANDLE_VALUE)
865 {
866 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
867 SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
868 if (hIn == INVALID_HANDLE_VALUE)
869 {
870 #ifdef _DEBUG
871 DebugPrintf (_T("Previous STDIN is invalid!!\n"));
872 #endif
873 }
874 else
875 {
876 if (GetFileType (hIn) == FILE_TYPE_DISK)
877 {
878 if (hFile[0] == hIn)
879 {
880 CloseHandle (hFile[0]);
881 hFile[0] = INVALID_HANDLE_VALUE;
882 DeleteFile (szFileName[0]);
883 *szFileName[0] = _T('\0');
884 }
885 else
886 {
887 #ifdef _DEBUG
888 DebugPrintf (_T("hFile[0] and hIn dont match!!!\n"));
889 #endif
890 }
891 }
892 }
893 }
894
895
896 /* Restore original STDOUT */
897 if (hOldConOut != INVALID_HANDLE_VALUE)
898 {
899 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
900 SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
901 if (hOldConOut != hOut)
902 CloseHandle (hOut);
903 hOldConOut = INVALID_HANDLE_VALUE;
904 }
905
906 /* Restore original STDERR */
907 if (hOldConErr != INVALID_HANDLE_VALUE)
908 {
909 HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE);
910 SetStdHandle (STD_ERROR_HANDLE, hOldConErr);
911 if (hOldConErr != hErr)
912 CloseHandle (hErr);
913 hOldConErr = INVALID_HANDLE_VALUE;
914 }
915 #endif /* FEATURE_REDIRECTION */
916 }
917
918
919 /*
920 * do the prompt/input/process loop
921 *
922 */
923
924 static INT
925 ProcessInput (BOOL bFlag)
926 {
927 TCHAR commandline[CMDLINE_LENGTH];
928 TCHAR readline[CMDLINE_LENGTH];
929 LPTSTR tp = NULL;
930 LPTSTR ip;
931 LPTSTR cp;
932 BOOL bEchoThisLine;
933
934
935 do
936 {
937 /* if no batch input then... */
938 if (!(ip = ReadBatchLine (&bEchoThisLine)))
939 {
940 if (bFlag)
941 return 0;
942
943 ReadCommand (readline, CMDLINE_LENGTH);
944 ip = readline;
945 bEchoThisLine = FALSE;
946 }
947
948 cp = commandline;
949 while (*ip)
950 {
951 if (*ip == _T('%'))
952 {
953 switch (*++ip)
954 {
955 case _T('%'):
956 *cp++ = *ip++;
957 break;
958
959 case _T('0'):
960 case _T('1'):
961 case _T('2'):
962 case _T('3'):
963 case _T('4'):
964 case _T('5'):
965 case _T('6'):
966 case _T('7'):
967 case _T('8'):
968 case _T('9'):
969 if ((tp = FindArg (*ip - _T('0'))))
970 {
971 cp = _stpcpy (cp, tp);
972 ip++;
973 }
974 else
975 *cp++ = _T('%');
976 break;
977
978 case _T('?'):
979 cp += _stprintf (cp, _T("%u"), nErrorLevel);
980 ip++;
981 break;
982
983 default:
984 tp = _tcschr(ip, _T('%'));
985 if ((tp != NULL) &&
986 (tp <= _tcschr(ip, _T(' ')) - 1))
987 {
988 INT size = 512;
989 TCHAR *evar;
990 *tp = _T('\0');
991
992 /* FIXME: Correct error handling when it can not alloc memmory */
993
994 /* %CD% */
995 if (_tcsicmp(ip,_T("cd")) ==0)
996 {
997 TCHAR szPath[MAX_PATH];
998 GetCurrentDirectory (MAX_PATH, szPath);
999 cp = _stpcpy (cp, szPath);
1000 }
1001
1002 /* %TIME% */
1003 else if (_tcsicmp(ip,_T("time")) ==0)
1004 {
1005 TCHAR szTime[40];
1006 GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, szTime, sizeof(szTime));
1007 cp = _stpcpy (cp, szTime);
1008 }
1009
1010 /* %DATE% */
1011 else if (_tcsicmp(ip,_T("date")) ==0)
1012 {
1013 TCHAR szDate[40];
1014
1015 GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, _T("ddd"), szDate, sizeof (szDate));
1016 cp = _stpcpy (cp, szDate);
1017 cp = _stpcpy (cp, _T(" "));
1018 GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, sizeof (szDate));
1019 cp = _stpcpy (cp, szDate);
1020 }
1021
1022 /* %RANDOM% */
1023 else if (_tcsicmp(ip,_T("random")) ==0)
1024 {
1025 TCHAR szRand[40];
1026 /* Get random number */
1027 _itot(rand(),szRand,10);
1028 cp = _stpcpy (cp, szRand);
1029 }
1030
1031
1032 /* %ERRORLEVEL% */
1033 else if (_tcsicmp(ip,_T("errorlevel")) ==0)
1034 {
1035 evar = malloc ( size * sizeof(TCHAR));
1036 if (evar==NULL)
1037 return 1;
1038
1039 memset(evar,0,512 * sizeof(TCHAR));
1040 _itot(nErrorLevel,evar,10);
1041 cp = _stpcpy (cp, evar);
1042
1043 free(evar);
1044 }
1045 else
1046 {
1047 evar = malloc ( size * sizeof(TCHAR));
1048 if (evar==NULL)
1049 return 1;
1050
1051 size = GetEnvironmentVariable (ip, evar, size);
1052 if (size!=0)
1053 {
1054 evar = realloc(evar,size * sizeof(TCHAR) );
1055 if (evar!=NULL)
1056 {
1057 size = GetEnvironmentVariable (ip, evar, size);
1058 }
1059 }
1060
1061 if (size)
1062 {
1063 cp = _stpcpy (cp, evar);
1064 }
1065
1066 free(evar);
1067 }
1068
1069 ip = tp + 1;
1070
1071 }
1072 else
1073 {
1074 *cp++ = _T('%');
1075 }
1076
1077 break;
1078 }
1079 continue;
1080 }
1081
1082
1083
1084
1085 if (_istcntrl (*ip))
1086 *ip = _T(' ');
1087 *cp++ = *ip++;
1088 }
1089
1090 *cp = _T('\0');
1091
1092 /* strip trailing spaces */
1093 while ((--cp >= commandline) && _istspace (*cp));
1094
1095 *(cp + 1) = _T('\0');
1096
1097 /* JPP 19980807 */
1098 /* Echo batch file line */
1099 if (bEchoThisLine)
1100 {
1101 PrintPrompt ();
1102 ConOutPuts (commandline);
1103 }
1104
1105 if (*commandline)
1106 {
1107 ParseCommandLine (commandline);
1108 if (bEcho && !bIgnoreEcho)
1109 ConOutChar ('\n');
1110 bIgnoreEcho = FALSE;
1111 }
1112 }
1113 while (!bCanExit || !bExit);
1114
1115 return 0;
1116 }
1117
1118
1119 /*
1120 * control-break handler.
1121 */
1122 BOOL WINAPI BreakHandler (DWORD dwCtrlType)
1123 {
1124
1125 if ((dwCtrlType != CTRL_C_EVENT) &&
1126 (dwCtrlType != CTRL_BREAK_EVENT))
1127 return FALSE;
1128
1129 if (bChildProcessRunning == TRUE)
1130 {
1131 GenerateConsoleCtrlEvent (CTRL_C_EVENT,
1132 dwChildProcessId);
1133 return TRUE;
1134 }
1135
1136 /* FIXME: Handle batch files */
1137
1138 /* FIXME: Print "^C" */
1139
1140
1141 return TRUE;
1142 }
1143
1144
1145 VOID AddBreakHandler (VOID)
1146 {
1147 SetConsoleCtrlHandler ((PHANDLER_ROUTINE)BreakHandler, TRUE);
1148 }
1149
1150
1151 VOID RemoveBreakHandler (VOID)
1152 {
1153 SetConsoleCtrlHandler ((PHANDLER_ROUTINE)BreakHandler, FALSE);
1154 }
1155
1156
1157 /*
1158 * show commands and options that are available.
1159 *
1160 */
1161 #if 0
1162 static VOID
1163 ShowCommands (VOID)
1164 {
1165 /* print command list */
1166 ConOutResPuts(STRING_CMD_HELP1);
1167 PrintCommandList();
1168
1169 /* print feature list */
1170 ConOutResPuts(STRING_CMD_HELP2);
1171
1172 #ifdef FEATURE_ALIASES
1173 ConOutResPuts(STRING_CMD_HELP3);
1174 #endif
1175 #ifdef FEATURE_HISTORY
1176 ConOutResPuts(STRING_CMD_HELP4);
1177 #endif
1178 #ifdef FEATURE_UNIX_FILENAME_COMPLETION
1179 ConOutResPuts(STRING_CMD_HELP5);
1180 #endif
1181 #ifdef FEATURE_DIRECTORY_STACK
1182 ConOutResPuts(STRING_CMD_HELP6);
1183 #endif
1184 #ifdef FEATURE_REDIRECTION
1185 ConOutResPuts(STRING_CMD_HELP7);
1186 #endif
1187 ConOutChar(_T('\n'));
1188 }
1189 #endif
1190
1191 /*
1192 * set up global initializations and process parameters
1193 *
1194 * argc - number of parameters to command.com
1195 * argv - command-line parameters
1196 *
1197 */
1198 static VOID
1199 Initialize (int argc, TCHAR* argv[])
1200 {
1201 TCHAR commandline[CMDLINE_LENGTH];
1202 TCHAR ModuleName[_MAX_PATH + 1];
1203 INT i;
1204
1205 //INT len;
1206 //TCHAR *ptr, *cmdLine;
1207
1208
1209 #ifdef _DEBUG
1210 INT x;
1211
1212 DebugPrintf (_T("[command args:\n"));
1213 for (x = 0; x < argc; x++)
1214 {
1215 DebugPrintf (_T("%d. %s\n"), x, argv[x]);
1216 }
1217 DebugPrintf (_T("]\n"));
1218 #endif
1219
1220 /* get version information */
1221 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1222 GetVersionEx (&osvi);
1223
1224 InitLocale ();
1225
1226 /* get default input and output console handles */
1227 hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1228 hIn = GetStdHandle (STD_INPUT_HANDLE);
1229
1230
1231 if (argc >= 2 && !_tcsncmp (argv[1], _T("/?"), 2))
1232 {
1233 ConOutResPaging(TRUE,STRING_CMD_HELP8);
1234 ExitProcess(0);
1235 }
1236 SetConsoleMode (hIn, ENABLE_PROCESSED_INPUT);
1237
1238 #ifdef INCLUDE_CMD_CHDIR
1239 InitLastPath ();
1240 #endif
1241
1242 #ifdef FATURE_ALIASES
1243 InitializeAlias ();
1244 #endif
1245
1246 if (argc >= 2)
1247 {
1248 for (i = 1; i < argc; i++)
1249 {
1250 if (!_tcsicmp (argv[i], _T("/p")))
1251 {
1252 if (!IsExistingFile (_T("\\autoexec.bat")))
1253 {
1254 #ifdef INCLUDE_CMD_DATE
1255 cmd_date (_T(""), _T(""));
1256 #endif
1257 #ifdef INCLUDE_CMD_TIME
1258 cmd_time (_T(""), _T(""));
1259 #endif
1260 }
1261 else
1262 {
1263 ParseCommandLine (_T("\\autoexec.bat"));
1264 }
1265 bCanExit = FALSE;
1266 }
1267 else if (!_tcsicmp (argv[i], _T("/c")))
1268 {
1269 /* This just runs a program and exits */
1270 ++i;
1271 if (i < argc)
1272 {
1273 _tcscpy (commandline, argv[i]);
1274 while (++i < argc)
1275 {
1276 _tcscat (commandline, _T(" "));
1277 _tcscat (commandline, argv[i]);
1278 }
1279
1280 ParseCommandLine(commandline);
1281 ExitProcess (ProcessInput (TRUE));
1282 }
1283 else
1284 {
1285 ExitProcess (0);
1286 }
1287 }
1288 else if (!_tcsicmp (argv[i], _T("/k")))
1289 {
1290 /* This just runs a program and remains */
1291 ++i;
1292 if (i < argc)
1293 {
1294 _tcscpy (commandline, argv[i]);
1295 while (++i < argc)
1296 {
1297 _tcscat (commandline, _T(" "));
1298 _tcscat (commandline, argv[i]);
1299 }
1300
1301 ParseCommandLine(commandline);
1302 }
1303 }
1304 #ifdef INCLUDE_CMD_COLOR
1305 else if (!_tcsnicmp (argv[i], _T("/t:"), 3))
1306 {
1307 /* process /t (color) argument */
1308 wDefColor = (WORD)_tcstoul (&argv[i][3], NULL, 16);
1309 wColor = wDefColor;
1310 SetScreenColor (wColor, TRUE);
1311 }
1312 #endif
1313 }
1314 }
1315
1316 /* run cmdstart.bat */
1317 if (IsExistingFile (_T("cmdstart.bat")))
1318 {
1319 ParseCommandLine (_T("cmdstart.bat"));
1320 }
1321 else if (IsExistingFile (_T("\\cmdstart.bat")))
1322 {
1323 ParseCommandLine (_T("\\cmdstart.bat"));
1324 }
1325 #ifndef __REACTOS__
1326 else
1327 {
1328 /* try to run cmdstart.bat from install dir */
1329 LPTSTR p;
1330
1331 _tcscpy (commandline, argv[0]);
1332 p = _tcsrchr (commandline, _T('\\')) + 1;
1333 _tcscpy (p, _T("cmdstart.bat"));
1334
1335 if (IsExistingFile (_T("commandline")))
1336 {
1337 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR4, szMsg, RC_STRING_MAX_SIZE);
1338 ConErrPrintf(szMsg, commandline);
1339 ParseCommandLine (commandline);
1340 }
1341 }
1342 #endif
1343
1344 #ifdef FEATURE_DIR_STACK
1345 /* initialize directory stack */
1346 InitDirectoryStack ();
1347 #endif
1348
1349
1350 #ifdef FEATURE_HISTORY
1351 /*initialize history*/
1352 InitHistory();
1353 #endif
1354
1355 /* Set COMSPEC environment variable */
1356 if (0 != GetModuleFileName (NULL, ModuleName, _MAX_PATH + 1))
1357 {
1358 ModuleName[_MAX_PATH] = _T('\0');
1359 SetEnvironmentVariable (_T("COMSPEC"), ModuleName);
1360 }
1361
1362 /* add ctrl break handler */
1363 AddBreakHandler ();
1364 }
1365
1366
1367 static VOID Cleanup (int argc, TCHAR *argv[])
1368 {
1369 #ifndef __REACTOS__
1370 TCHAR szMsg[RC_STRING_MAX_SIZE];
1371 #endif
1372
1373 /* run cmdexit.bat */
1374 if (IsExistingFile (_T("cmdexit.bat")))
1375 {
1376 ConErrResPuts(STRING_CMD_ERROR5);
1377
1378 ParseCommandLine (_T("cmdexit.bat"));
1379 }
1380 else if (IsExistingFile (_T("\\cmdexit.bat")))
1381 {
1382 ConErrResPuts (STRING_CMD_ERROR5);
1383 ParseCommandLine (_T("\\cmdexit.bat"));
1384 }
1385 #ifndef __REACTOS__
1386 else
1387 {
1388 /* try to run cmdexit.bat from install dir */
1389 TCHAR commandline[CMDLINE_LENGTH];
1390 LPTSTR p;
1391
1392 _tcscpy (commandline, argv[0]);
1393 p = _tcsrchr (commandline, _T('\\')) + 1;
1394 _tcscpy (p, _T("cmdexit.bat"));
1395
1396 if (IsExistingFile (_T("commandline")))
1397 {
1398 LoadString(CMD_ModuleHandle, STRING_CMD_ERROR4, szMsg, RC_STRING_MAX_SIZE);
1399 ConErrPrintf(szMsg, commandline);
1400 ParseCommandLine (commandline);
1401 }
1402 }
1403 #endif
1404
1405 #ifdef FEATURE_ALIASES
1406 DestroyAlias ();
1407 #endif
1408
1409 #ifdef FEATURE_DIECTORY_STACK
1410 /* destroy directory stack */
1411 DestroyDirectoryStack ();
1412 #endif
1413
1414 #ifdef INCLUDE_CMD_CHDIR
1415 FreeLastPath ();
1416 #endif
1417
1418 #ifdef FEATURE_HISTORY
1419 CleanHistory();
1420 #endif
1421
1422
1423 /* remove ctrl break handler */
1424 RemoveBreakHandler ();
1425 SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
1426 ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
1427 }
1428
1429 #ifdef __REACTOS__
1430 #ifdef _UNICODE
1431 PWCHAR * _CommandLineToArgvW(PWCHAR lpCmdLine, int *pNumArgs)
1432 {
1433 PWCHAR * argvw = NULL;
1434 PWCHAR ptr = lpCmdLine;
1435 PWCHAR str;
1436 int len;
1437 int NumArgs;
1438
1439 NumArgs = 0;
1440
1441 while(lpCmdLine && *lpCmdLine)
1442 {
1443 while (iswspace(*lpCmdLine)) lpCmdLine++;
1444 if (*lpCmdLine)
1445 {
1446 if ((NumArgs % 10)==0)
1447 {
1448 PWCHAR * old_argvw = argvw;
1449 argvw = malloc((NumArgs + 10) * sizeof(PWCHAR));
1450 memcpy(argvw, old_argvw, NumArgs * sizeof(PWCHAR));
1451 free(old_argvw);
1452 }
1453 ptr = wcschr(lpCmdLine, L' ');
1454 if (ptr)
1455 {
1456 len = ptr - lpCmdLine;
1457 }
1458 else
1459 {
1460 len = wcslen(lpCmdLine);
1461 }
1462 str = malloc((len + 1) * sizeof(WCHAR));
1463 memcpy(str, lpCmdLine, len * sizeof(WCHAR));
1464 str[len] = 0;
1465 argvw[NumArgs]=str;
1466 NumArgs++;
1467 lpCmdLine = ptr;
1468 }
1469 }
1470 *pNumArgs = NumArgs;
1471 return argvw;
1472 }
1473 #endif
1474 #endif
1475
1476 /*
1477 * main function
1478 */
1479 #ifdef _UNICODE
1480 int main(void)
1481 #else
1482 int main (int argc, char *argv[])
1483 #endif
1484 {
1485 CONSOLE_SCREEN_BUFFER_INFO Info;
1486 INT nExitCode;
1487 #ifdef _UNICODE
1488 PWCHAR * argv;
1489 int argc=0;
1490 #ifdef __REACTOS__
1491 argv = _CommandLineToArgvW(GetCommandLineW(), &argc);
1492 #else
1493 argv = CommandLineToArgvW(GetCommandLineW(), &argc);
1494 #endif
1495 #endif
1496
1497 SetFileApisToOEM();
1498 InputCodePage= 0;
1499 OutputCodePage = 0;
1500
1501 hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE,
1502 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1503 OPEN_EXISTING, 0, NULL);
1504 if (GetConsoleScreenBufferInfo(hConsole, &Info) == FALSE)
1505 {
1506 ConOutFormatMessage(GetLastError());
1507 return(1);
1508 }
1509 wColor = Info.wAttributes;
1510 wDefColor = wColor;
1511
1512 InputCodePage= GetConsoleCP();
1513 OutputCodePage = GetConsoleOutputCP();
1514 CMD_ModuleHandle = GetModuleHandle(NULL);
1515
1516 /* check switches on command-line */
1517 Initialize(argc, argv);
1518
1519 /* call prompt routine */
1520 nExitCode = ProcessInput(FALSE);
1521
1522 /* do the cleanup */
1523 Cleanup(argc, argv);
1524
1525 return(nExitCode);
1526 }
1527
1528 /* EOF */