Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1007 lines
32 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. cinit.c
  5. Abstract:
  6. Initialization
  7. --*/
  8. #include "cmd.h"
  9. #if CMD_DEBUG_ENABLE
  10. unsigned DebGroup=0;
  11. unsigned DebLevel=0;
  12. #endif
  13. TCHAR CurDrvDir[MAX_PATH] ; /* Current drive and directory */
  14. BOOL SingleBatchInvocation = FALSE ;
  15. BOOL SingleCommandInvocation = FALSE;
  16. BOOLEAN fDisableUNCCheck = FALSE;
  17. int cmdfound = -1; /* @@5 - command found index */
  18. int cpyfirst = TRUE; /* @@5 - flag to ctrl DOSQFILEMODE calls */
  19. int cpydflag = FALSE; /* @@5 - flag save dirflag from las DQFMDE*/
  20. int cpydest = FALSE; /* @@6 - flag to not display bad dev msg */
  21. int cdevfail = FALSE; /* @@7 - flag to not display extra emsg */
  22. #ifdef UNICODE
  23. BOOLEAN fOutputUnicode = FALSE;/* Unicode/Ansi output */
  24. #endif // UNICODE
  25. BOOLEAN fEnableExtensions = FALSE;
  26. BOOLEAN fDefaultExtensions = TRUE;
  27. BOOLEAN fDelayedExpansion = FALSE;
  28. BOOLEAN ReportDelayLoadErrors = TRUE;
  29. unsigned tywild = 0; /* flag to tell if wild type args @@5 @J1 */
  30. int array_size = 0 ; /* original array size is zero */
  31. CPINFO CurrentCPInfo;
  32. UINT CurrentCP;
  33. WORD wDefaultColor = 0; // default is whatever console currently has
  34. // but default can be overriden by the registry.
  35. TCHAR chCompletionCtrl = SPACE; // Default is no completion (must be Ctrl character)
  36. TCHAR chPathCompletionCtrl = SPACE;
  37. VOID InitLocale( VOID );
  38. extern TCHAR ComSpec[], ComSpecStr[] ; /* M021 */
  39. extern TCHAR PathStr[], PCSwitch, SCSwitch, PromptStr[] ;
  40. extern TCHAR PathExtStr[], PathExtDefaultStr[];
  41. extern TCHAR BCSwitch ; /* @@ */
  42. extern TCHAR QCSwitch ; /* @@dv */
  43. extern TCHAR UCSwitch;
  44. extern TCHAR ACSwitch;
  45. extern TCHAR XCSwitch;
  46. extern TCHAR YCSwitch;
  47. extern TCHAR DevNul[], VolSrch[] ; /* M021 - To set PathChar */
  48. extern TCHAR SwitChar, PathChar ; /* M000 - Made non-settable */
  49. extern int Necho ; /* @@dv - true if /Q for no echo */
  50. extern TCHAR MsgBuf[];
  51. extern struct envdata CmdEnv;
  52. extern struct envdata * penvOrig;
  53. struct envdata OrigEnv;
  54. extern TCHAR TmpBuf[] ; /* M034 */
  55. extern TCHAR ComSpec[];
  56. TCHAR *CmdSpec = &ComSpec[1]; /* M033 */
  57. extern unsigned DosErr ; /* D64 */
  58. //
  59. // TRUE if the ctrl-c thread has been run.
  60. //
  61. BOOL CtrlCSeen;
  62. //
  63. // Set TRUE when it is ok the print a control-c.
  64. // If we are waiting for another process this will be
  65. // FALSE
  66. BOOLEAN fPrintCtrlC = TRUE;
  67. //
  68. // console mode at program startup time. Used to reset mode
  69. // after running another process.
  70. //
  71. DWORD dwCurInputConMode;
  72. DWORD dwCurOutputConMode;
  73. //
  74. // Initial Title. Used for restoration on abort etc.
  75. // MAX_PATH was arbitrary
  76. //
  77. PTCHAR pszTitleCur;
  78. PTCHAR pszTitleOrg;
  79. BOOLEAN fTitleChanged = FALSE; // title has been changed and needs to be reset
  80. //
  81. // used to gate access to ctrlcseen flag between ctrl-c thread
  82. // and main thread
  83. //
  84. CRITICAL_SECTION CtrlCSection;
  85. LPCRITICAL_SECTION lpcritCtrlC;
  86. //
  87. // Used to set and reset ctlcseen flag
  88. //
  89. VOID SetCtrlC();
  90. VOID ResetCtrlC();
  91. Handler(
  92. IN ULONG CtrlType
  93. )
  94. {
  95. if ( (CtrlType == CTRL_C_EVENT) ||
  96. (CtrlType == CTRL_BREAK_EVENT) ) {
  97. //
  98. // Note that we had a ^C event
  99. //
  100. SetCtrlC();
  101. //
  102. // Display the ^C if we are enabled and if we're not in a batch file
  103. //
  104. if (fPrintCtrlC && CurrentBatchFile != NULL) {
  105. fprintf( stderr, "^C" );
  106. fflush( stderr );
  107. }
  108. return TRUE;
  109. } else {
  110. return FALSE;
  111. }
  112. }
  113. /********************* START OF SPECIFICATION **************************/
  114. /* */
  115. /* SUBROUTINE NAME: Init */
  116. /* */
  117. /* DESCRIPTIVE NAME: CMD.EXE Initialization Process */
  118. /* */
  119. /* FUNCTION: Initialization of CMD.EXE. */
  120. /* */
  121. /* NOTES: */
  122. /* */
  123. /* ENTRY POINT: Init */
  124. /* */
  125. /* INPUT: None. */
  126. /* */
  127. /* OUTPUT: None. */
  128. /* */
  129. /* EXIT-NORMAL: */
  130. /* Return the pointer to command line. */
  131. /* */
  132. /* EXIT-ERROR: */
  133. /* Return NULL string. */
  134. /* */
  135. /* EFFECTS: None. */
  136. /* */
  137. /********************** END OF SPECIFICATION **************************/
  138. /*** Init - initialize Command
  139. *
  140. * Purpose:
  141. * Save current SIGINTR response (SIGIGN or SIGDEF) and set SIGIGN.
  142. * If debugging
  143. * Set DebGroup & DebLevel
  144. * Get Environment and init CmdEnv structure (M034)
  145. * Check for any switches.
  146. * Make a version check.
  147. * If version out of range
  148. * Print error message.
  149. * If Permanent Command
  150. * Loop forever
  151. * Else
  152. * Exit.
  153. * Save the current drive and directory.
  154. * Check for other command line arguments.
  155. * Set up the environment.
  156. * Always print a bannner if MSDOS version of Command.
  157. * Return any "comline" value found.
  158. *
  159. * TCHAR *Init()
  160. *
  161. * Args:
  162. *
  163. * Returns:
  164. * Comline (it's NULL if NOT in single command mode).
  165. *
  166. * Notes:
  167. * See CSIG.C for a description of the way ^Cs and INT24s are handled
  168. * during initialization.
  169. * M024 - Brought functionality for checking non-specific args into
  170. * init from routines CheckOtherArgs and ChangeComSpec which have
  171. * been eliminated.
  172. *
  173. */
  174. BOOL Init(
  175. TCHAR *InitialCmds[]
  176. )
  177. {
  178. #if 0 /* Set debug group and level words */
  179. int fh;
  180. PTCHAR nptr;
  181. nptr = TmpBuf;
  182. nptr = EatWS(nptr, NULL);
  183. nptr = mystrchr(nptr, TEXT(' '));
  184. nptr = EatWS(nptr, NULL);
  185. //
  186. // Assume a non-zero debugging group
  187. //
  188. DebGroup = hstoi(nptr) ; /* 1st debug arg */
  189. if (DebGroup) {
  190. for (fh=0 ; fh < 2 ; fh++) {
  191. if (fh == 1)
  192. DebLevel = hstoi(nptr) ; /* 2nd debug arg */
  193. while(*nptr && !_istspace(*nptr)) { /* Index past it */
  194. ++nptr ;
  195. }
  196. nptr = EatWS(nptr, NULL) ;
  197. }
  198. }
  199. DEBUG((INGRP, RSLVL, "INIT: Debug GRP=%04x LVL=%04x", DebGroup, DebLevel)) ;
  200. mystrcpy(TmpBuf, nptr) ; /* Elim from cmdline */
  201. #endif
  202. //
  203. // Initialize Critical Section to handle access to
  204. // flag for control C handling
  205. //
  206. lpcritCtrlC = &CtrlCSection;
  207. InitializeCriticalSection(lpcritCtrlC);
  208. ResetCtrlC();
  209. SetConsoleCtrlHandler(Handler,TRUE);
  210. //
  211. // Make sure we have the correct console modes.
  212. //
  213. ResetConsoleMode();
  214. #ifndef UNICODE
  215. setbuf(stdout, NULL); /* Don't buffer output @@5 */
  216. setbuf(stderr, NULL); /* @@5 */
  217. _setmode(1, O_BINARY); /* Set output to text mode @@5 */
  218. _setmode(2, O_BINARY); /* @@5 */
  219. #endif
  220. CmdEnv.handle = GetEnvironmentStrings();
  221. GetRegistryValues(InitialCmds);
  222. mystrcpy(TmpBuf, GetCommandLine());
  223. LexCopy( TmpBuf, TmpBuf, mystrlen( TmpBuf ) ); /* convert dbcs spaces */
  224. GetDir(CurDrvDir, GD_DEFAULT) ;
  225. SetUpEnvironment() ;
  226. /* Check cmdline switches */
  227. CheckSwitches(InitialCmds, TmpBuf);
  228. if (CurDrvDir[0] == BSLASH && CurDrvDir[1] == BSLASH) {
  229. #if 0
  230. if (fEnableExtensions) {
  231. struct cmdnode *n ;
  232. PutStdErr(MSG_SIM_UNC_CURDIR, ONEARG, CurDrvDir);
  233. n = mkstr(sizeof(*n));
  234. n->argptr = mkstr((_tcslen(CurDrvDir)+1) * sizeof(TCHAR));
  235. _tcscpy(n->argptr, CurDrvDir);
  236. GetWindowsDirectory(CurDrvDir, sizeof(CurDrvDir)/sizeof(TCHAR));
  237. ChangeDir2(CurDrvDir, TRUE);
  238. ePushDir(n);
  239. } else
  240. #endif
  241. if (!fDisableUNCCheck) {
  242. PutStdErr(MSG_NO_UNC_INITDIR, ONEARG, CurDrvDir);
  243. GetWindowsDirectory(CurDrvDir, sizeof(CurDrvDir)/sizeof(TCHAR));
  244. ChangeDir2(CurDrvDir, TRUE);
  245. }
  246. }
  247. //
  248. // Get current CodePage Info. We need this to decide whether
  249. // or not to use half-width characters. This is actually here
  250. // in the init code for safety - the Dir command calls it before
  251. // each dir is executed, because chcp may have been executed.
  252. //
  253. GetCPInfo((CurrentCP=GetConsoleOutputCP()), &CurrentCPInfo);
  254. InitLocale();
  255. pszTitleCur = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR) + 2*sizeof(TCHAR));
  256. pszTitleOrg = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR) + 2*sizeof(TCHAR));
  257. if ((pszTitleCur != NULL) && (pszTitleOrg != NULL)) {
  258. if (GetConsoleTitle(pszTitleOrg, MAX_PATH)) {
  259. mystrcpy(pszTitleCur, pszTitleOrg);
  260. } else {
  261. *pszTitleCur = 0;
  262. *pszTitleOrg = 0;
  263. }
  264. }
  265. if (!SingleCommandInvocation) {
  266. if (FileIsConsole(STDOUT)) {
  267. #ifndef WIN95_CMD
  268. CONSOLE_SCREEN_BUFFER_INFO csbi;
  269. if (!wDefaultColor) {
  270. if (GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
  271. wDefaultColor = csbi.wAttributes;
  272. }
  273. }
  274. #endif // WIN95_CMD
  275. if (wDefaultColor) {
  276. SetColor( wDefaultColor );
  277. }
  278. }
  279. }
  280. /* Print banner if no command string on command line */
  281. if (!InitialCmds[2]) {
  282. TCHAR VersionFormat[32];
  283. GetVersionString( VersionFormat, sizeof( VersionFormat ) / sizeof( VersionFormat[0] ));
  284. PutStdOut( MSG_MS_DOS_VERSION,
  285. ONEARG,
  286. VersionFormat );
  287. cmd_printf( CrLf );
  288. PutStdOut( MSG_COPYRIGHT, NOARGS ) ;
  289. if (fDefaultExtensions) {
  290. //
  291. // DaveC says say nothing to user here.
  292. //
  293. // PutStdOut(MSG_EXT_ENABLED_BY_DEFAULT, NOARGS);
  294. } else
  295. if (fEnableExtensions) {
  296. PutStdOut(MSG_EXT_ENABLED, NOARGS) ;
  297. }
  298. }
  299. DEBUG((INGRP, RSLVL, "INIT: Returning now.")) ;
  300. #ifndef WIN95_CMD
  301. {
  302. hKernel32 = GetModuleHandle( TEXT("KERNEL32.DLL") );
  303. lpCopyFileExW = (LPCOPYFILEEX_ROUTINE)
  304. GetProcAddress( hKernel32, "CopyFileExW" );
  305. lpIsDebuggerPresent = (LPISDEBUGGERPRESENT_ROUTINE)
  306. GetProcAddress( hKernel32, "IsDebuggerPresent" );
  307. lpSetConsoleInputExeName = (LPSETCONSOLEINPUTEXENAME_ROUTINE)
  308. GetProcAddress( hKernel32, "SetConsoleInputExeNameW" );
  309. }
  310. #endif // WIN95_CMD
  311. return(InitialCmds[0] != NULL || InitialCmds[1] != NULL || InitialCmds[2] != NULL);
  312. }
  313. void GetRegistryValues(
  314. TCHAR *InitialCmds[]
  315. )
  316. {
  317. long rc;
  318. HKEY hKey;
  319. ULONG ValueBuffer[ 1024 ];
  320. LPBYTE lpData;
  321. DWORD cbData;
  322. DWORD dwType;
  323. DWORD cchSrc, cchDst;
  324. PTCHAR s;
  325. int i;
  326. HKEY PredefinedKeys[2] = {HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER};
  327. if (fDefaultExtensions) {
  328. fEnableExtensions = TRUE;
  329. }
  330. for (i=0; i<2; i++) {
  331. rc = RegOpenKey(PredefinedKeys[i], TEXT("Software\\Microsoft\\Command Processor"), &hKey);
  332. if (rc) {
  333. continue;
  334. }
  335. dwType = REG_NONE;
  336. lpData = (LPBYTE)ValueBuffer;
  337. cbData = sizeof(ValueBuffer);
  338. rc = RegQueryValueEx(hKey, TEXT("DisableUNCCheck"), NULL, &dwType, lpData, &cbData);
  339. if (!rc) {
  340. if (dwType == REG_DWORD) {
  341. fDisableUNCCheck = (BOOLEAN)(*(PULONG)lpData != 0);
  342. }
  343. else
  344. if (dwType == REG_SZ) {
  345. fDisableUNCCheck = (BOOLEAN)(_wtol((PWSTR)lpData) == 1);
  346. }
  347. }
  348. cbData = sizeof(ValueBuffer);
  349. rc = RegQueryValueEx(hKey, TEXT("EnableExtensions"), NULL, &dwType, lpData, &cbData);
  350. if (!rc) {
  351. if (dwType == REG_DWORD) {
  352. fEnableExtensions = (BOOLEAN)(*(PULONG)lpData != 0);
  353. }
  354. else
  355. if (dwType == REG_SZ) {
  356. fEnableExtensions = (BOOLEAN)(_wtol((PWSTR)lpData) == 1);
  357. }
  358. }
  359. cbData = sizeof(ValueBuffer);
  360. rc = RegQueryValueEx(hKey, TEXT("DelayedExpansion"), NULL, &dwType, lpData, &cbData);
  361. if (!rc) {
  362. if (dwType == REG_DWORD) {
  363. fDelayedExpansion = (BOOLEAN)(*(PULONG)lpData != 0);
  364. }
  365. else
  366. if (dwType == REG_SZ) {
  367. fDelayedExpansion = (BOOLEAN)(_wtol((PWSTR)lpData) == 1);
  368. }
  369. }
  370. cbData = sizeof(ValueBuffer);
  371. rc = RegQueryValueEx(hKey, TEXT("DefaultColor"), NULL, &dwType, lpData, &cbData);
  372. if (!rc) {
  373. if (dwType == REG_DWORD) {
  374. wDefaultColor = (WORD) *(PULONG)lpData;
  375. }
  376. else
  377. if (dwType == REG_SZ) {
  378. wDefaultColor = (WORD)_tcstol((PTCHAR)lpData, NULL, 0);
  379. }
  380. }
  381. cbData = sizeof(ValueBuffer);
  382. rc = RegQueryValueEx(hKey, TEXT("CompletionChar"), NULL, &dwType, lpData, &cbData);
  383. if (!rc) {
  384. if (dwType == REG_DWORD) {
  385. chCompletionCtrl = (TCHAR)*(PULONG)lpData;
  386. }
  387. else
  388. if (dwType == REG_SZ) {
  389. chCompletionCtrl = (TCHAR)_tcstol((PTCHAR)lpData, NULL, 0);
  390. }
  391. if (chCompletionCtrl == 0 || chCompletionCtrl == 0x0d || chCompletionCtrl > SPACE) {
  392. chCompletionCtrl = SPACE;
  393. }
  394. }
  395. cbData = sizeof(ValueBuffer);
  396. rc = RegQueryValueEx(hKey, TEXT("PathCompletionChar"), NULL, &dwType, lpData, &cbData);
  397. if (!rc) {
  398. if (dwType == REG_DWORD) {
  399. chPathCompletionCtrl = (TCHAR)*(PULONG)lpData;
  400. }
  401. else
  402. if (dwType == REG_SZ) {
  403. chPathCompletionCtrl = (TCHAR)_tcstol((PTCHAR)lpData, NULL, 0);
  404. }
  405. if (chPathCompletionCtrl == 0 || chPathCompletionCtrl == 0x0d || chPathCompletionCtrl > SPACE) {
  406. chPathCompletionCtrl = SPACE;
  407. }
  408. }
  409. if (chCompletionCtrl == SPACE && chPathCompletionCtrl < SPACE) {
  410. chCompletionCtrl = chPathCompletionCtrl;
  411. } else
  412. if (chPathCompletionCtrl == SPACE && chCompletionCtrl < SPACE) {
  413. chPathCompletionCtrl = chCompletionCtrl;
  414. }
  415. cbData = sizeof(ValueBuffer);
  416. rc = RegQueryValueEx(hKey, TEXT("AutoRun"), NULL, &dwType, lpData, &cbData);
  417. if (!rc) {
  418. s = (TCHAR *)lpData;
  419. if (dwType == REG_EXPAND_SZ) {
  420. cchSrc = cbData / sizeof( TCHAR );
  421. cchDst = (sizeof( ValueBuffer ) - cbData) / sizeof( TCHAR );
  422. if (ExpandEnvironmentStrings( s,
  423. &s[ cchSrc+2 ],
  424. cchDst
  425. )
  426. )
  427. _tcscpy( s, &s[ cchSrc+2 ] );
  428. else
  429. *s = NULLC;
  430. }
  431. if (*s)
  432. InitialCmds[i] = mystrcpy( mkstr( (_tcslen(s)+1) * sizeof( TCHAR ) ), s );
  433. }
  434. RegCloseKey(hKey);
  435. }
  436. //
  437. // Initialize for %RANDOM%
  438. //
  439. srand( (unsigned)time( NULL ) );
  440. return;
  441. }
  442. /*** CheckSwitches - process Command's switches
  443. *
  444. * Purpose:
  445. * Check to see if Command was passed any switches and take appropriate
  446. * action. The switches are:
  447. * /P - Permanent Command. Set permanent CMD flag.
  448. * /C - Single command. Build a command line out of the rest of
  449. * the args and pass it back to Init.
  450. * @@ /K - Same as /C but also set BatCom flag.
  451. * /Q - No echo
  452. * /A - Output in ANSI
  453. * /U - Output in UNICODE
  454. *
  455. * All other switches are ignored.
  456. *
  457. * TCHAR *CheckSwitches(TCHAR *nptr)
  458. *
  459. * Args:
  460. * nptr = Ptr to cmdline to check for switches
  461. *
  462. * Returns:
  463. * Comline (it's NULL if NOT in single command mode).
  464. *
  465. * Notes:
  466. * M034 - This function revised to use the raw cmdline
  467. * from the passed environment.
  468. *
  469. */
  470. void
  471. CheckSwitches(
  472. TCHAR *InitialCmds[],
  473. TCHAR *nptr
  474. )
  475. {
  476. TCHAR a, /* Holds switch value */
  477. *comline = NULL , /* Ptr to command line if /c found */
  478. store,
  479. *ptr, /* A temporary pointers */
  480. *ptr_b,
  481. *ptr_e;
  482. BOOLEAN fAutoGen = FALSE; // On if "/S" in cmdline meaning cmdline was parsed by CMD.EXE previously
  483. BOOLEAN fOrigEnableExt;
  484. struct cmdnode cmd_node; // need for SearchForExecutable()
  485. TCHAR cmdline [MAX_PATH];
  486. TCHAR argptr [MAX_PATH];
  487. TCHAR CmdBuf [MAXTOKLEN+3];
  488. int retc;
  489. memset( &cmd_node, 0, sizeof( cmd_node ));
  490. fOrigEnableExt = fEnableExtensions;
  491. DEBUG((INGRP, ACLVL, "CHKSW: entered.")) ;
  492. while (nptr = mystrchr(nptr, SwitChar)) {
  493. a = (TCHAR) _totlower(nptr[1]) ;
  494. if (a == NULLC)
  495. break;
  496. if (a == QMARK) {
  497. #define CTRLCBREAK if (CtrlCSeen) break
  498. BeginHelpPause();
  499. do {
  500. CTRLCBREAK; PutStdOut(MSG_HELP_CMD, NOARGS);
  501. CTRLCBREAK; PutStdOut(MSG_HELP_CMD1, NOARGS);
  502. if (!fOrigEnableExt && !fEnableExtensions) break;
  503. CTRLCBREAK; PutStdOut(MSG_HELP_CMD_EXTENSIONS, NOARGS);
  504. CTRLCBREAK; PutStdOut(MSG_HELP_CMD_EXTENSIONS1, NOARGS);
  505. CTRLCBREAK; PutStdOut(MSG_HELP_CMD_COMPLETION1, NOARGS);
  506. CTRLCBREAK; PutStdOut(MSG_HELP_CMD_COMPLETION2, NOARGS);
  507. } while ( FALSE );
  508. EndHelpPause();
  509. CMDexit(1);
  510. } else if (a == QCSwitch) { /* Quiet cmd switch */
  511. Necho = TRUE ;
  512. mystrcpy(nptr, nptr+2) ;
  513. } else if ((a == SCSwitch) || (a == BCSwitch) || a == TEXT('r')) {
  514. DEBUG((INGRP, ACLVL, "CHKSW: Single command switch")) ;
  515. if ( a == BCSwitch ) {
  516. SingleBatchInvocation = TRUE; // /K specified
  517. } else {
  518. SingleCommandInvocation = TRUE; // /C or /R specified
  519. }
  520. if (!(comline = mkstr(mystrlen(nptr+2)*sizeof(TCHAR)+2*sizeof(TCHAR)))) {
  521. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  522. CMDexit(1) ;
  523. } ;
  524. mystrcpy(comline, nptr+2) ; /* Make comline */
  525. *nptr = NULLC ; /* Invalidate this arg */
  526. comline = SkipWhiteSpace( comline );
  527. //---------------------------------------------------------------------------------------------------------
  528. // CMD.EXE uses quotes by two reasons:
  529. // 1. to embed command symbols "&", "<", ">", "|", "&&", "||" into command arguments, e.g.
  530. // cmd /c " dir | more "
  531. // 2. to embed spaces into filename, e.g.
  532. // cmd /c " my batfile with spaces.cmd"
  533. // Note that the caret "^" has no effect when used in between quotes in the current implementation (941221).
  534. // Also, CMD.EXE binds the quote with the next one.
  535. //
  536. // I see a problem here: the commands like
  537. // cmd /c "findstr " | " | find "smth" " OR
  538. // cmd /c "ls | " my filterbat with spaces.cmd" | more"
  539. // WON'T WORK unless we all decide to change CMD's syntax to better handle quotes!
  540. //
  541. // There is more to it: when CMD.EXE parses pipes,CMD creates process with the command argument like this:
  542. // <full path of CMD.EXE> /S /C" <cmdname> "
  543. // so we've got spaces inside the quotes.
  544. //
  545. // I hope I am not missing anything else...
  546. //
  547. // With given design restrictions, I will at least solve simple but most wide-spread problem:
  548. // using filenames with spaces by trying this:
  549. // IF ( (there is no /S switch ) AND // it is not the result of prev. parsing
  550. // (there are exactly 2 quotes) AND // the existing design problem with multiple quotes
  551. // (there is no special chars between quotes) AND // don't break command symbols parsing
  552. // (there is a whitespace between quotes) AND // otherwise it is not filename with spaces
  553. // (the token between quotes is a valid executable) )// otherwise we can't help anyway
  554. // THEN
  555. // Preserve quotes // Assume it is a filename with spaces
  556. // ELSE
  557. // Exec. old logic // Strip first and last quotes
  558. //
  559. // Ugly, but what options do I have? Only to patch existing logic or change syntax.
  560. //-----------------------------------------------------------------------------------------------------------
  561. if (fAutoGen) // seen /S switch
  562. goto old_way;
  563. if (*comline == QUOTE) {
  564. ptr_b = comline + 1;
  565. ptr_e = mystrchr (ptr_b, QUOTE);
  566. if (ptr_e) { // at least 2 quotes
  567. ptr_b = ptr_e + 1;
  568. ptr_e = mystrchr (ptr_b, QUOTE);
  569. if (ptr_e) { // more than 2 quotes
  570. goto old_way;
  571. }
  572. }
  573. else { // only 1 quote
  574. goto old_way;
  575. }
  576. // exactly 2 quotes
  577. store = *ptr_b;
  578. *ptr_b = NULLC;
  579. if ( (mystrchr (comline, ANDOP) ) ||
  580. (mystrchr (comline, INOP) ) ||
  581. (mystrchr (comline, OUTOP) ) ||
  582. (mystrchr (comline, LPOP) ) ||
  583. (mystrchr (comline, RPOP) ) ||
  584. (mystrchr (comline, SILOP) ) ||
  585. (mystrchr (comline, ESCHAR)) ||
  586. (mystrchr (comline, PIPOP) ) ) {
  587. *ptr_b = store; // special chars between quotes
  588. goto old_way;
  589. }
  590. if ( ! mystrchr (comline, TEXT(' ')) ) {
  591. *ptr_b = store; // no spaces between quotes
  592. goto old_way;
  593. }
  594. // the last check is for valid executable
  595. cmd_node.type = CMDTYP ;
  596. cmd_node.cmdline = cmdline;
  597. cmd_node.argptr = argptr;
  598. cmd_node.rio = NULL;
  599. mystrcpy (cmdline, comline); // get token between quotes
  600. mystrcpy (argptr, TEXT (" ") );
  601. *ptr_b = store; // restore comline
  602. retc = SearchForExecutable (&cmd_node, CmdBuf);
  603. if ( ( retc == SFE_NOTFND) || ( retc == SFE_FAIL) )
  604. goto old_way;
  605. goto new_way; // assume filename and DO NOT strip quotes.
  606. }
  607. old_way:
  608. if (*comline == QUOTE) {
  609. ++comline ;
  610. ptr = mystrrchr(comline, QUOTE);
  611. if ( ptr ) {
  612. *ptr = NULLC;
  613. ++ptr;
  614. mystrcat(comline,ptr);
  615. }
  616. }
  617. new_way:
  618. *(comline+mystrlen(comline)) = NLN ;
  619. DEBUG((INGRP, ACLVL, "CHKSW: Single command line = `%ws'", comline)) ;
  620. InitialCmds[2] = comline;
  621. break ; /* Once /K or /C found, no more args exist */
  622. } else if (a == UCSwitch) { /* Unicode output switch */
  623. #ifdef UNICODE
  624. fOutputUnicode = TRUE;
  625. mystrcpy(nptr, nptr+2) ;
  626. #else
  627. PutStdErr(MSG_UNICODE_NOT_SUPPORTED, NOARGS);
  628. #endif // UNICODE
  629. } else if (a == ACSwitch) { /* Ansi output switch */
  630. #ifdef UNICODE
  631. fOutputUnicode = FALSE;
  632. #endif // UNICODE
  633. mystrcpy(nptr, nptr+2) ;
  634. //
  635. // Old style of enabling extensions with /X
  636. //
  637. } else if (a == XCSwitch) { /* Enable extensions switch */
  638. fEnableExtensions = TRUE;
  639. mystrcpy(nptr, nptr+2) ;
  640. //
  641. // Old style of disabling extensions with /Y
  642. //
  643. } else if (a == YCSwitch) { /* Disable extensions switch */
  644. fEnableExtensions = FALSE;
  645. mystrcpy(nptr, nptr+2) ;
  646. //
  647. // Enable/Disable command extensions. /E or /E:ON to enable
  648. // and /E:OFF to disable.
  649. //
  650. } else if (a == TEXT('e')) {
  651. mystrcpy(nptr, nptr+2) ;
  652. if (*nptr == COLON && !_tcsnicmp(nptr+1, TEXT("OFF"), 3)) {
  653. fEnableExtensions = FALSE;
  654. mystrcpy(nptr, nptr+4) ;
  655. } else {
  656. fEnableExtensions = TRUE;
  657. if (!_tcsnicmp(nptr, TEXT(":ON"), 3)) {
  658. mystrcpy(nptr, nptr+3) ;
  659. }
  660. }
  661. //
  662. // Disable AutoRun from Registry if /D specified.
  663. //
  664. } else if (a == TEXT('d')) {
  665. mystrcpy(nptr, nptr+2) ;
  666. InitialCmds[0] = NULL;
  667. InitialCmds[1] = NULL;
  668. //
  669. // Enable/Disable file and directory name completion. /F or /F:ON to
  670. // enable and /F:OFF to disable.
  671. //
  672. } else if (a == TEXT('f')) {
  673. mystrcpy(nptr, nptr+2) ;
  674. if (*nptr == COLON && !_tcsnicmp(nptr+1, TEXT("OFF"), 3)) {
  675. chCompletionCtrl = SPACE;
  676. chPathCompletionCtrl = SPACE;
  677. mystrcpy(nptr, nptr+4) ;
  678. } else {
  679. chCompletionCtrl = 0x6; // Ctrl-F
  680. chPathCompletionCtrl = 0x4; // Ctrl-D
  681. if (!_tcsnicmp(nptr, TEXT(":ON"), 3)) {
  682. mystrcpy(nptr, nptr+3) ;
  683. }
  684. }
  685. //
  686. // Enable/Disable delayed variable expansion inside FOR loops. /V or /V:ON to
  687. // enable and /V:OFF to disable.
  688. //
  689. } else if (a == TEXT('v')) {
  690. mystrcpy(nptr, nptr+2) ;
  691. if (*nptr == COLON && !_tcsnicmp(nptr+1, TEXT("OFF"), 3)) {
  692. fDelayedExpansion = FALSE;
  693. mystrcpy(nptr, nptr+4) ;
  694. } else {
  695. fDelayedExpansion = TRUE;
  696. if (!_tcsnicmp(nptr, TEXT(":ON"), 3)) {
  697. mystrcpy(nptr, nptr+3) ;
  698. }
  699. }
  700. //
  701. // Set the foreground/background screen coler
  702. // enable and /F:OFF to disable.
  703. //
  704. } else if (fEnableExtensions && a == TEXT('t')) { /* Define start color */
  705. if (*(nptr+2) == __TEXT(':') && _istxdigit(*(nptr+3)) &&
  706. _istxdigit(*(nptr+4)) && !_istxdigit(*(nptr+5))) {
  707. wDefaultColor = (WORD) (_istdigit(*(nptr+3)) ? (WORD)*(nptr+3) - (WORD)TEXT('0')
  708. : (WORD)_totlower(*(nptr+3)) - (WORD)TEXT('W')) ;
  709. wDefaultColor <<= 4;
  710. wDefaultColor |= (WORD) (_istdigit(*(nptr+4)) ? (WORD)*(nptr+4) - (WORD)TEXT('0')
  711. : (WORD)_totlower(*(nptr+4)) - (WORD)TEXT('W')) ;
  712. mystrcpy(nptr+2, nptr+5 );
  713. }
  714. mystrcpy(nptr, nptr+2) ;
  715. } else if (a == TEXT('s') ) { /* CMD inserts when parsing pipes */
  716. fAutoGen = TRUE ;
  717. mystrcpy(nptr, nptr+2) ;
  718. } else {
  719. mystrcpy(nptr, nptr+2) ; /* Remove any other switches */
  720. } ;
  721. } ;
  722. return;
  723. }
  724. /*** SetUpEnvironment - initialize Command's environment
  725. *
  726. * Purpose:
  727. * Take the environment pointer received earlier and initialize it
  728. * with respect with respect to size and maxsize. Initialize the
  729. * PATH and COMSPEC variables as necessary.
  730. *
  731. * SetUpEnvironment()
  732. *
  733. */
  734. extern TCHAR KeysStr[]; /* @@5 */
  735. extern int KeysFlag; /* @@5 */
  736. void SetUpEnvironment(void)
  737. {
  738. TCHAR *cds ; // Command directory string
  739. TCHAR *nptr ; // Temp cmd name ptr
  740. TCHAR *eptr ; // Temp cmd name ptr
  741. MEMORY_BASIC_INFORMATION MemInfo;
  742. eptr = CmdEnv.handle;
  743. CmdEnv.cursize = GetEnvCb( eptr );
  744. VirtualQuery( CmdEnv.handle, &MemInfo, sizeof( MemInfo ));
  745. CmdEnv.maxsize = (UINT)MemInfo.RegionSize;
  746. if (!(cds = mkstr(MAX_PATH*sizeof(TCHAR)))) {
  747. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  748. CMDexit(1) ;
  749. }
  750. GetModuleFileName( NULL, cds, MAX_PATH );
  751. //
  752. // If the PATH variable is not set, it must be added as a NULL. This is
  753. // so that DOS apps inherit the current directory path.
  754. //
  755. if (!GetEnvVar(PathStr)) {
  756. SetEnvVar(PathStr, TEXT(""), &CmdEnv);
  757. }
  758. //
  759. // If the PATHEXT variable is not set, and extensions are enabled, set it to
  760. // the default list of extensions that will be searched.
  761. //
  762. if (!GetEnvVar(PathExtStr)) {
  763. SetEnvVar(PathExtStr, PathExtDefaultStr, &CmdEnv);
  764. }
  765. //
  766. // If the PROMPT variable is not set, it must be added as $P$G. This is
  767. // special cased, since we do not allow users to add NULLs.
  768. //
  769. if (!GetEnvVar(PromptStr)) {
  770. SetEnvVar(PromptStr, TEXT("$P$G"), &CmdEnv);
  771. }
  772. if (!GetEnvVar(ComSpecStr)) {
  773. DEBUG((INGRP, EILVL, "SETENV: No COMSPEC var")) ;
  774. if(!mystrchr(cds,DOT)) { /* If no fname, use default */
  775. _tcsupr(CmdSpec);
  776. if((cds+mystrlen(cds)-1) != mystrrchr(cds,PathChar)) {
  777. mystrcat(cds,ComSpec) ;
  778. } else {
  779. mystrcat(cds,&ComSpec[1]) ;
  780. }
  781. }
  782. SetEnvVar(ComSpecStr, cds, &CmdEnv) ;
  783. }
  784. if ( (nptr = GetEnvVar(KeysStr)) && (!_tcsicmp(nptr, TEXT("ON"))) ) {
  785. KeysFlag = 1;
  786. }
  787. ChangeDir(CurDrvDir);
  788. penvOrig = CopyEnv();
  789. if (penvOrig) {
  790. OrigEnv = *penvOrig;
  791. penvOrig = &OrigEnv;
  792. }
  793. }
  794. VOID
  795. ResetCtrlC() {
  796. EnterCriticalSection(lpcritCtrlC);
  797. CtrlCSeen = FALSE;
  798. LeaveCriticalSection(lpcritCtrlC);
  799. }
  800. VOID
  801. SetCtrlC() {
  802. EnterCriticalSection(lpcritCtrlC);
  803. CtrlCSeen = TRUE;
  804. LeaveCriticalSection(lpcritCtrlC);
  805. }
  806. void
  807. CMDexit(int rc)
  808. {
  809. while (ePopDir(NULL) == SUCCESS)
  810. ;
  811. exit(rc);
  812. }
  813. //
  814. // Get the current OS version and put it into the common version format
  815. //
  816. VOID
  817. GetVersionString(
  818. IN OUT PTCHAR VersionString,
  819. IN ULONG Length
  820. )
  821. {
  822. ULONG vrs = GetVersion();
  823. //
  824. // Version format is [Major.Minor(2).Build(4)]
  825. //
  826. _sntprintf( VersionString, Length,
  827. TEXT( "%d.%d.%04d" ),
  828. vrs & 0xFF,
  829. (vrs >> 8) & 0xFF,
  830. (vrs >> 16) & 0x3FFF
  831. );
  832. }