Leaked source code of windows server 2003
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.

1014 lines
33 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. #if defined(RICHARDW)
  14. TCHAR Buffer27[TMPBUFLEN];
  15. #endif
  16. TCHAR CurDrvDir[MAX_PATH] ; /* Current drive and directory */
  17. BOOL SingleBatchInvocation = FALSE ;
  18. BOOL SingleCommandInvocation = FALSE;
  19. BOOLEAN fDisableUNCCheck = FALSE;
  20. int cmdfound = -1; /* @@5 - command found index */
  21. int cpyfirst = TRUE; /* @@5 - flag to ctrl DOSQFILEMODE calls */
  22. int cpydflag = FALSE; /* @@5 - flag save dirflag from las DQFMDE*/
  23. int cpydest = FALSE; /* @@6 - flag to not display bad dev msg */
  24. int cdevfail = FALSE; /* @@7 - flag to not display extra emsg */
  25. #ifdef UNICODE
  26. BOOLEAN fOutputUnicode = FALSE;/* Unicode/Ansi output */
  27. #endif // UNICODE
  28. BOOLEAN fEnableExtensions = FALSE;
  29. BOOLEAN fDefaultExtensions = TRUE;
  30. BOOLEAN fDelayedExpansion = FALSE;
  31. BOOLEAN ReportDelayLoadErrors = TRUE;
  32. unsigned tywild = 0; /* flag to tell if wild type args @@5 @J1 */
  33. int array_size = 0 ; /* original array size is zero */
  34. CPINFO CurrentCPInfo;
  35. UINT CurrentCP;
  36. WORD wDefaultColor = 0; // default is whatever console currently has
  37. // but default can be overriden by the registry.
  38. TCHAR chCompletionCtrl = SPACE; // Default is no completion (must be Ctrl character)
  39. TCHAR chPathCompletionCtrl = SPACE;
  40. VOID InitLocale( VOID );
  41. extern TCHAR ComSpec[], ComSpecStr[] ; /* M021 */
  42. extern TCHAR PathStr[], PCSwitch, SCSwitch, PromptStr[] ;
  43. extern TCHAR PathExtStr[], PathExtDefaultStr[];
  44. extern TCHAR BCSwitch ; /* @@ */
  45. extern TCHAR QCSwitch ; /* @@dv */
  46. extern TCHAR UCSwitch;
  47. extern TCHAR ACSwitch;
  48. extern TCHAR XCSwitch;
  49. extern TCHAR YCSwitch;
  50. extern TCHAR DevNul[], VolSrch[] ; /* M021 - To set PathChar */
  51. extern TCHAR SwitChar, PathChar ; /* M000 - Made non-settable */
  52. extern int Necho ; /* @@dv - true if /Q for no echo */
  53. extern TCHAR MsgBuf[];
  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. * Check for any switches.
  145. * Make a version check.
  146. * If version out of range
  147. * Print error message.
  148. * If Permanent Command
  149. * Loop forever
  150. * Else
  151. * Exit.
  152. * Save the current drive and directory.
  153. * Check for other command line arguments.
  154. * Set up the environment.
  155. * Always print a bannner if MSDOS version of Command.
  156. * Return any "comline" value found.
  157. *
  158. * TCHAR *Init()
  159. *
  160. * Args:
  161. *
  162. * Returns:
  163. * Comline (it's NULL if NOT in single command mode).
  164. *
  165. * Notes:
  166. * See CSIG.C for a description of the way ^Cs and INT24s are handled
  167. * during initialization.
  168. * M024 - Brought functionality for checking non-specific args into
  169. * init from routines CheckOtherArgs and ChangeComSpec which have
  170. * been eliminated.
  171. *
  172. */
  173. BOOL Init(
  174. TCHAR *InitialCmds[]
  175. )
  176. {
  177. #if 0 /* Set debug group and level words */
  178. int fh;
  179. PTCHAR nptr;
  180. nptr = TmpBuf;
  181. nptr = EatWS(nptr, NULL);
  182. nptr = mystrchr(nptr, TEXT(' '));
  183. nptr = EatWS(nptr, NULL);
  184. //
  185. // Assume a non-zero debugging group
  186. //
  187. DebGroup = hstoi(nptr) ; /* 1st debug arg */
  188. if (DebGroup) {
  189. for (fh=0 ; fh < 2 ; fh++) {
  190. if (fh == 1)
  191. DebLevel = hstoi(nptr) ; /* 2nd debug arg */
  192. while(*nptr && !_istspace(*nptr)) { /* Index past it */
  193. ++nptr ;
  194. }
  195. nptr = EatWS(nptr, NULL) ;
  196. }
  197. }
  198. DEBUG((INGRP, RSLVL, "INIT: Debug GRP=%04x LVL=%04x", DebGroup, DebLevel)) ;
  199. mystrcpy(TmpBuf, nptr) ; /* Elim from cmdline */
  200. #endif
  201. //
  202. // Initialize Critical Section to handle access to
  203. // flag for control C handling
  204. //
  205. lpcritCtrlC = &CtrlCSection;
  206. InitializeCriticalSection(lpcritCtrlC);
  207. ResetCtrlC();
  208. SetConsoleCtrlHandler(Handler,TRUE);
  209. //
  210. // Make sure we have the correct console modes.
  211. //
  212. ResetConsoleMode();
  213. #ifndef UNICODE
  214. setbuf(stdout, NULL); /* Don't buffer output @@5 */
  215. setbuf(stderr, NULL); /* @@5 */
  216. _setmode(1, O_BINARY); /* Set output to text mode @@5 */
  217. _setmode(2, O_BINARY); /* @@5 */
  218. #endif
  219. InitEnv( );
  220. GetRegistryValues(InitialCmds);
  221. if (_tcslen( GetCommandLine( )) + 1 > TMPBUFLEN) {
  222. PutStdErr( MSG_COMMAND_LINE_TOO_LONG, NOARGS );
  223. CMDexit(1) ;
  224. }
  225. mystrcpy(TmpBuf, GetCommandLine());
  226. LexCopy( TmpBuf, TmpBuf, mystrlen( TmpBuf ) ); /* convert dbcs spaces */
  227. GetDir(CurDrvDir, GD_DEFAULT) ;
  228. SetUpEnvironment() ;
  229. /* Check cmdline switches */
  230. CheckSwitches(InitialCmds, TmpBuf);
  231. if (CurDrvDir[0] == BSLASH && CurDrvDir[1] == BSLASH) {
  232. if (!fDisableUNCCheck) {
  233. PutStdErr(MSG_NO_UNC_INITDIR, ONEARG, CurDrvDir);
  234. if( GetWindowsDirectory(CurDrvDir, sizeof( CurDrvDir )/sizeof( TCHAR )) ) {
  235. ChangeDir2(CurDrvDir, TRUE);
  236. } else {
  237. CMDexit( 1 );
  238. }
  239. }
  240. }
  241. //
  242. // Get current CodePage Info. We need this to decide whether
  243. // or not to use half-width characters. This is actually here
  244. // in the init code for safety - the Dir command calls it before
  245. // each dir is executed, because chcp may have been executed.
  246. //
  247. GetCPInfo((CurrentCP=GetConsoleOutputCP()), &CurrentCPInfo);
  248. InitLocale();
  249. pszTitleCur = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR) + 2*sizeof(TCHAR));
  250. pszTitleOrg = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR) + 2*sizeof(TCHAR));
  251. if ((pszTitleCur != NULL) && (pszTitleOrg != NULL)) {
  252. if (GetConsoleTitle(pszTitleOrg, MAX_PATH)) {
  253. mystrcpy(pszTitleCur, pszTitleOrg);
  254. } else {
  255. *pszTitleCur = 0;
  256. *pszTitleOrg = 0;
  257. }
  258. }
  259. if (!SingleCommandInvocation) {
  260. if (FileIsConsole(STDOUT)) {
  261. #ifndef WIN95_CMD
  262. CONSOLE_SCREEN_BUFFER_INFO csbi;
  263. if (!wDefaultColor) {
  264. if (GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
  265. wDefaultColor = csbi.wAttributes;
  266. }
  267. }
  268. #endif // WIN95_CMD
  269. if (wDefaultColor) {
  270. SetColor( wDefaultColor );
  271. }
  272. }
  273. }
  274. /* Print banner if no command string on command line */
  275. if (!InitialCmds[2]) {
  276. TCHAR VersionFormat[32];
  277. GetVersionString( VersionFormat, sizeof( VersionFormat ) / sizeof( VersionFormat[0] ));
  278. PutStdOut( MSG_MS_DOS_VERSION,
  279. ONEARG,
  280. VersionFormat );
  281. cmd_printf( CrLf );
  282. PutStdOut( MSG_COPYRIGHT, NOARGS ) ;
  283. if (fDefaultExtensions) {
  284. //
  285. // DaveC says say nothing to user here.
  286. //
  287. // PutStdOut(MSG_EXT_ENABLED_BY_DEFAULT, NOARGS);
  288. } else
  289. if (fEnableExtensions) {
  290. PutStdOut(MSG_EXT_ENABLED, NOARGS) ;
  291. }
  292. }
  293. DEBUG((INGRP, RSLVL, "INIT: Returning now.")) ;
  294. #ifndef WIN95_CMD
  295. {
  296. hKernel32 = GetModuleHandle( TEXT("KERNEL32.DLL") );
  297. lpCopyFileExW = (LPCOPYFILEEX_ROUTINE)
  298. GetProcAddress( hKernel32, "CopyFileExW" );
  299. lpIsDebuggerPresent = (LPISDEBUGGERPRESENT_ROUTINE)
  300. GetProcAddress( hKernel32, "IsDebuggerPresent" );
  301. lpSetConsoleInputExeName = (LPSETCONSOLEINPUTEXENAME_ROUTINE)
  302. GetProcAddress( hKernel32, "SetConsoleInputExeNameW" );
  303. }
  304. #endif // WIN95_CMD
  305. return(InitialCmds[0] != NULL || InitialCmds[1] != NULL || InitialCmds[2] != NULL);
  306. }
  307. void GetRegistryValues(
  308. TCHAR *InitialCmds[]
  309. )
  310. {
  311. long rc;
  312. HKEY hKey;
  313. ULONG ValueBuffer[ 1024 ];
  314. LPBYTE lpData;
  315. DWORD cbData;
  316. DWORD dwType;
  317. DWORD cchSrc, cchDst;
  318. PTCHAR s;
  319. int i;
  320. HKEY PredefinedKeys[2] = {HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER};
  321. if (fDefaultExtensions) {
  322. fEnableExtensions = TRUE;
  323. }
  324. for (i=0; i<2; i++) {
  325. rc = RegOpenKey(PredefinedKeys[i], TEXT("Software\\Microsoft\\Command Processor"), &hKey);
  326. if (rc) {
  327. continue;
  328. }
  329. dwType = REG_NONE;
  330. lpData = (LPBYTE)ValueBuffer;
  331. cbData = sizeof(ValueBuffer);
  332. rc = RegQueryValueEx(hKey, TEXT("DisableUNCCheck"), NULL, &dwType, lpData, &cbData);
  333. if (!rc) {
  334. if (dwType == REG_DWORD) {
  335. fDisableUNCCheck = (BOOLEAN)(*(PULONG)lpData != 0);
  336. }
  337. else
  338. if (dwType == REG_SZ) {
  339. fDisableUNCCheck = (BOOLEAN)(_wtol((PWSTR)lpData) == 1);
  340. #if defined(RICHARDW)
  341. _tcscpy( Buffer27, (PWSTR)lpData );
  342. #endif
  343. }
  344. }
  345. cbData = sizeof(ValueBuffer);
  346. rc = RegQueryValueEx(hKey, TEXT("EnableExtensions"), NULL, &dwType, lpData, &cbData);
  347. if (!rc) {
  348. if (dwType == REG_DWORD) {
  349. fEnableExtensions = (BOOLEAN)(*(PULONG)lpData != 0);
  350. }
  351. else
  352. if (dwType == REG_SZ) {
  353. fEnableExtensions = (BOOLEAN)(_wtol((PWSTR)lpData) == 1);
  354. }
  355. }
  356. cbData = sizeof(ValueBuffer);
  357. rc = RegQueryValueEx(hKey, TEXT("DelayedExpansion"), NULL, &dwType, lpData, &cbData);
  358. if (!rc) {
  359. if (dwType == REG_DWORD) {
  360. fDelayedExpansion = (BOOLEAN)(*(PULONG)lpData != 0);
  361. }
  362. else
  363. if (dwType == REG_SZ) {
  364. fDelayedExpansion = (BOOLEAN)(_wtol((PWSTR)lpData) == 1);
  365. }
  366. }
  367. cbData = sizeof(ValueBuffer);
  368. rc = RegQueryValueEx(hKey, TEXT("DefaultColor"), NULL, &dwType, lpData, &cbData);
  369. if (!rc) {
  370. if (dwType == REG_DWORD) {
  371. wDefaultColor = (WORD) *(PULONG)lpData;
  372. }
  373. else
  374. if (dwType == REG_SZ) {
  375. wDefaultColor = (WORD)_tcstol((PTCHAR)lpData, NULL, 0);
  376. }
  377. }
  378. cbData = sizeof(ValueBuffer);
  379. rc = RegQueryValueEx(hKey, TEXT("CompletionChar"), NULL, &dwType, lpData, &cbData);
  380. if (!rc) {
  381. if (dwType == REG_DWORD) {
  382. chCompletionCtrl = (TCHAR)*(PULONG)lpData;
  383. }
  384. else
  385. if (dwType == REG_SZ) {
  386. chCompletionCtrl = (TCHAR)_tcstol((PTCHAR)lpData, NULL, 0);
  387. }
  388. if (chCompletionCtrl == 0 || chCompletionCtrl == 0x0d || chCompletionCtrl > SPACE) {
  389. chCompletionCtrl = SPACE;
  390. }
  391. }
  392. cbData = sizeof(ValueBuffer);
  393. rc = RegQueryValueEx(hKey, TEXT("PathCompletionChar"), NULL, &dwType, lpData, &cbData);
  394. if (!rc) {
  395. if (dwType == REG_DWORD) {
  396. chPathCompletionCtrl = (TCHAR)*(PULONG)lpData;
  397. }
  398. else
  399. if (dwType == REG_SZ) {
  400. chPathCompletionCtrl = (TCHAR)_tcstol((PTCHAR)lpData, NULL, 0);
  401. }
  402. if (chPathCompletionCtrl == 0 || chPathCompletionCtrl == 0x0d || chPathCompletionCtrl > SPACE) {
  403. chPathCompletionCtrl = SPACE;
  404. }
  405. }
  406. if (chCompletionCtrl == SPACE && chPathCompletionCtrl < SPACE) {
  407. chCompletionCtrl = chPathCompletionCtrl;
  408. } else
  409. if (chPathCompletionCtrl == SPACE && chCompletionCtrl < SPACE) {
  410. chPathCompletionCtrl = chCompletionCtrl;
  411. }
  412. cbData = sizeof(ValueBuffer);
  413. rc = RegQueryValueEx(hKey, TEXT("AutoRun"), NULL, &dwType, lpData, &cbData);
  414. if (!rc) {
  415. s = (TCHAR *)lpData;
  416. if (dwType == REG_EXPAND_SZ) {
  417. cchSrc = cbData / sizeof( TCHAR );
  418. cchDst = (sizeof( ValueBuffer ) - cbData) / sizeof( TCHAR );
  419. if (ExpandEnvironmentStrings( s,
  420. &s[ cchSrc+2 ],
  421. cchDst
  422. )
  423. )
  424. _tcscpy( s, &s[ cchSrc+2 ] );
  425. else
  426. *s = NULLC;
  427. }
  428. if (*s)
  429. InitialCmds[i] = mystrcpy( mkstr( (_tcslen(s)+1) * sizeof( TCHAR ) ), s );
  430. }
  431. RegCloseKey(hKey);
  432. }
  433. //
  434. // Initialize for %RANDOM%
  435. //
  436. srand( (unsigned)time( NULL ) );
  437. return;
  438. }
  439. /*** CheckSwitches - process Command's switches
  440. *
  441. * Purpose:
  442. * Check to see if Command was passed any switches and take appropriate
  443. * action. The switches are:
  444. * /P - Permanent Command. Set permanent CMD flag.
  445. * /C - Single command. Build a command line out of the rest of
  446. * the args and pass it back to Init.
  447. * @@ /K - Same as /C but also set BatCom flag.
  448. * /Q - No echo
  449. * /A - Output in ANSI
  450. * /U - Output in UNICODE
  451. *
  452. * All other switches are ignored.
  453. *
  454. * TCHAR *CheckSwitches(TCHAR *nptr)
  455. *
  456. * Args:
  457. * nptr = Ptr to cmdline to check for switches
  458. *
  459. * Returns:
  460. * Comline (it's NULL if NOT in single command mode).
  461. *
  462. * Notes:
  463. * M034 - This function revised to use the raw cmdline
  464. * from the passed environment.
  465. *
  466. */
  467. void
  468. CheckSwitches(
  469. TCHAR *InitialCmds[],
  470. TCHAR *nptr
  471. )
  472. {
  473. TCHAR a, /* Holds switch value */
  474. *comline = NULL , /* Ptr to command line if /c found */
  475. store,
  476. *ptr, /* A temporary pointers */
  477. *ptr_b,
  478. *ptr_e;
  479. BOOL FoundSpace;
  480. BOOLEAN fAutoGen = FALSE; // On if "/S" in cmdline meaning cmdline was parsed by CMD.EXE previously
  481. BOOLEAN fOrigEnableExt;
  482. struct cmdnode cmd_node; // need for SearchForExecutable()
  483. TCHAR cmdline [MAX_PATH];
  484. TCHAR argptr [MAX_PATH];
  485. PTCHAR CmdBuf;
  486. int retc;
  487. CmdBuf = mkstr( (MAXTOKLEN + 3) * sizeof( TCHAR ));
  488. if (CmdBuf == NULL) {
  489. CMDexit( 1 );
  490. }
  491. memset( &cmd_node, 0, sizeof( cmd_node ));
  492. fOrigEnableExt = fEnableExtensions;
  493. DEBUG((INGRP, ACLVL, "CHKSW: entered.")) ;
  494. while (nptr = mystrchr(nptr, SwitChar)) {
  495. a = (TCHAR) _totlower(nptr[1]) ;
  496. if (a == NULLC)
  497. break;
  498. if (a == QMARK) {
  499. BeginHelpPause();
  500. do {
  501. if (CtrlCSeen) break; PutStdOut(MSG_HELP_CMD, NOARGS);
  502. if (CtrlCSeen) break; PutStdOut(MSG_HELP_CMD1, NOARGS);
  503. if (!fOrigEnableExt && !fEnableExtensions) break;
  504. if (CtrlCSeen) break; PutStdOut(MSG_HELP_CMD_EXTENSIONS, NOARGS);
  505. if (CtrlCSeen) break; PutStdOut(MSG_HELP_CMD_EXTENSIONS1, NOARGS);
  506. if (CtrlCSeen) break; PutStdOut(MSG_HELP_CMD_COMPLETION1, NOARGS);
  507. if (CtrlCSeen) break; PutStdOut(MSG_HELP_CMD_COMPLETION2, NOARGS);
  508. } while ( FALSE );
  509. EndHelpPause();
  510. CMDexit(1);
  511. } else if (a == QCSwitch) { /* Quiet cmd switch */
  512. Necho = TRUE ;
  513. mystrcpy(nptr, nptr+2) ;
  514. } else if ((a == SCSwitch) || (a == BCSwitch) || a == TEXT('r')) {
  515. DEBUG((INGRP, ACLVL, "CHKSW: Single command switch")) ;
  516. if ( a == BCSwitch ) {
  517. SingleBatchInvocation = TRUE; // /K specified
  518. } else {
  519. SingleCommandInvocation = TRUE; // /C or /R specified
  520. }
  521. if (!(comline = mkstr(mystrlen(nptr+2)*sizeof(TCHAR)+2*sizeof(TCHAR)))) {
  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. FoundSpace = FALSE;
  591. {
  592. PTCHAR p = comline;
  593. while (*p) {
  594. if (_istspace( *p )) {
  595. FoundSpace = TRUE;
  596. break;
  597. }
  598. p++;
  599. }
  600. if ( !FoundSpace ) {
  601. *ptr_b = store;
  602. goto old_way;
  603. }
  604. }
  605. // the last check is for valid executable
  606. cmd_node.type = CMDTYP ;
  607. cmd_node.cmdline = cmdline;
  608. cmd_node.argptr = argptr;
  609. cmd_node.rio = NULL;
  610. mystrcpy (cmdline, comline); // get token between quotes
  611. mystrcpy (argptr, TEXT (" ") );
  612. *ptr_b = store; // restore comline
  613. retc = SearchForExecutable (&cmd_node, CmdBuf);
  614. if (retc == SFE_NOTFND)
  615. goto old_way;
  616. if (retc == SFE_FAIL) {
  617. PutStdErr( DosErr, NOARGS );
  618. CMDexit( DosErr );
  619. }
  620. goto new_way; // assume filename and DO NOT strip quotes.
  621. }
  622. old_way:
  623. if (*comline == QUOTE) {
  624. ++comline ;
  625. ptr = mystrrchr(comline, QUOTE);
  626. if ( ptr ) {
  627. *ptr = NULLC;
  628. ++ptr;
  629. mystrcat(comline,ptr);
  630. }
  631. }
  632. new_way:
  633. *(comline+mystrlen(comline)) = NLN ;
  634. DEBUG((INGRP, ACLVL, "CHKSW: Single command line = `%ws'", comline)) ;
  635. InitialCmds[2] = comline;
  636. break ; /* Once /K or /C found, no more args exist */
  637. } else if (a == UCSwitch) { /* Unicode output switch */
  638. #ifdef UNICODE
  639. fOutputUnicode = TRUE;
  640. mystrcpy(nptr, nptr+2) ;
  641. #else
  642. PutStdErr(MSG_UNICODE_NOT_SUPPORTED, NOARGS);
  643. #endif // UNICODE
  644. } else if (a == ACSwitch) { /* Ansi output switch */
  645. #ifdef UNICODE
  646. fOutputUnicode = FALSE;
  647. #endif // UNICODE
  648. mystrcpy(nptr, nptr+2) ;
  649. //
  650. // Old style of enabling extensions with /X
  651. //
  652. } else if (a == XCSwitch) { /* Enable extensions switch */
  653. fEnableExtensions = TRUE;
  654. mystrcpy(nptr, nptr+2) ;
  655. //
  656. // Old style of disabling extensions with /Y
  657. //
  658. } else if (a == YCSwitch) { /* Disable extensions switch */
  659. fEnableExtensions = FALSE;
  660. mystrcpy(nptr, nptr+2) ;
  661. //
  662. // Enable/Disable command extensions. /E or /E:ON to enable
  663. // and /E:OFF to disable.
  664. //
  665. } else if (a == TEXT('e')) {
  666. mystrcpy(nptr, nptr+2) ;
  667. if (*nptr == COLON && !_tcsnicmp(nptr+1, TEXT("OFF"), 3)) {
  668. fEnableExtensions = FALSE;
  669. mystrcpy(nptr, nptr+4) ;
  670. } else {
  671. fEnableExtensions = TRUE;
  672. if (!_tcsnicmp(nptr, TEXT(":ON"), 3)) {
  673. mystrcpy(nptr, nptr+3) ;
  674. }
  675. }
  676. //
  677. // Disable AutoRun from Registry if /D specified.
  678. //
  679. } else if (a == TEXT('d')) {
  680. mystrcpy(nptr, nptr+2) ;
  681. InitialCmds[0] = NULL;
  682. InitialCmds[1] = NULL;
  683. //
  684. // Enable/Disable file and directory name completion. /F or /F:ON to
  685. // enable and /F:OFF to disable.
  686. //
  687. } else if (a == TEXT('f')) {
  688. mystrcpy(nptr, nptr+2) ;
  689. if (*nptr == COLON && !_tcsnicmp(nptr+1, TEXT("OFF"), 3)) {
  690. chCompletionCtrl = SPACE;
  691. chPathCompletionCtrl = SPACE;
  692. mystrcpy(nptr, nptr+4) ;
  693. } else {
  694. chCompletionCtrl = 0x6; // Ctrl-F
  695. chPathCompletionCtrl = 0x4; // Ctrl-D
  696. if (!_tcsnicmp(nptr, TEXT(":ON"), 3)) {
  697. mystrcpy(nptr, nptr+3) ;
  698. }
  699. }
  700. //
  701. // Enable/Disable delayed variable expansion inside FOR loops. /V or /V:ON to
  702. // enable and /V:OFF to disable.
  703. //
  704. } else if (a == TEXT('v')) {
  705. mystrcpy(nptr, nptr+2) ;
  706. if (*nptr == COLON && !_tcsnicmp(nptr+1, TEXT("OFF"), 3)) {
  707. fDelayedExpansion = FALSE;
  708. mystrcpy(nptr, nptr+4) ;
  709. } else {
  710. fDelayedExpansion = TRUE;
  711. if (!_tcsnicmp(nptr, TEXT(":ON"), 3)) {
  712. mystrcpy(nptr, nptr+3) ;
  713. }
  714. }
  715. //
  716. // Set the foreground/background screen coler
  717. // enable and /F:OFF to disable.
  718. //
  719. } else if (fEnableExtensions && a == TEXT('t')) { /* Define start color */
  720. if (*(nptr+2) == __TEXT(':') && _istxdigit(*(nptr+3)) &&
  721. _istxdigit(*(nptr+4)) && !_istxdigit(*(nptr+5))) {
  722. wDefaultColor = (WORD) (_istdigit(*(nptr+3)) ? (WORD)*(nptr+3) - (WORD)TEXT('0')
  723. : (WORD)_totlower(*(nptr+3)) - (WORD)TEXT('W')) ;
  724. wDefaultColor <<= 4;
  725. wDefaultColor |= (WORD) (_istdigit(*(nptr+4)) ? (WORD)*(nptr+4) - (WORD)TEXT('0')
  726. : (WORD)_totlower(*(nptr+4)) - (WORD)TEXT('W')) ;
  727. mystrcpy(nptr+2, nptr+5 );
  728. }
  729. mystrcpy(nptr, nptr+2) ;
  730. } else if (a == TEXT('s') ) { /* CMD inserts when parsing pipes */
  731. fAutoGen = TRUE ;
  732. mystrcpy(nptr, nptr+2) ;
  733. } else {
  734. mystrcpy(nptr, nptr+2) ; /* Remove any other switches */
  735. } ;
  736. } ;
  737. FreeStr( CmdBuf );
  738. return;
  739. }
  740. /*** SetUpEnvironment - initialize Command's environment
  741. *
  742. * Purpose:
  743. * Initialize the PATH and COMSPEC variables as necessary.
  744. *
  745. * SetUpEnvironment()
  746. *
  747. */
  748. extern TCHAR KeysStr[]; /* @@5 */
  749. extern int KeysFlag; /* @@5 */
  750. void SetUpEnvironment(void)
  751. {
  752. TCHAR *cds ; // Command directory string
  753. TCHAR *nptr ; // Temp cmd name ptr
  754. if (!(cds = mkstr(MAX_PATH*sizeof(TCHAR)))) {
  755. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  756. CMDexit(1) ;
  757. }
  758. GetModuleFileName( NULL, cds, MAX_PATH );
  759. //
  760. // If the PATH variable is not set, it must be added as a NULL. This is
  761. // so that DOS apps inherit the current directory path.
  762. //
  763. if (!GetEnvVar(PathStr)) {
  764. SetEnvVar(PathStr, TEXT("") );
  765. }
  766. //
  767. // If the PATHEXT variable is not set, and extensions are enabled, set it to
  768. // the default list of extensions that will be searched.
  769. //
  770. if (!GetEnvVar(PathExtStr)) {
  771. SetEnvVar(PathExtStr, PathExtDefaultStr );
  772. }
  773. //
  774. // If the PROMPT variable is not set, it must be added as $P$G. This is
  775. // special cased, since we do not allow users to add NULLs.
  776. //
  777. if (!GetEnvVar(PromptStr)) {
  778. SetEnvVar(PromptStr, TEXT("$P$G") );
  779. }
  780. if (!GetEnvVar(ComSpecStr)) {
  781. DEBUG((INGRP, EILVL, "SETENV: No COMSPEC var")) ;
  782. if(!mystrchr(cds,DOT)) { /* If no fname, use default */
  783. _tcsupr(CmdSpec);
  784. if((cds+mystrlen(cds)-1) != mystrrchr(cds,PathChar)) {
  785. mystrcat(cds,ComSpec) ;
  786. } else {
  787. mystrcat(cds,&ComSpec[1]) ;
  788. }
  789. }
  790. SetEnvVar(ComSpecStr, cds ) ;
  791. }
  792. if ( (nptr = GetEnvVar(KeysStr)) && (!_tcsicmp(nptr, TEXT("ON"))) ) {
  793. KeysFlag = 1;
  794. }
  795. ChangeDir(CurDrvDir);
  796. }
  797. VOID
  798. ResetCtrlC() {
  799. EnterCriticalSection(lpcritCtrlC);
  800. CtrlCSeen = FALSE;
  801. LeaveCriticalSection(lpcritCtrlC);
  802. }
  803. VOID
  804. SetCtrlC() {
  805. EnterCriticalSection(lpcritCtrlC);
  806. CtrlCSeen = TRUE;
  807. LeaveCriticalSection(lpcritCtrlC);
  808. }
  809. void
  810. CMDexit(int rc)
  811. {
  812. while (ePopDir(NULL) == SUCCESS)
  813. ;
  814. exit(rc);
  815. }
  816. //
  817. // Get the current OS version and put it into the common version format
  818. //
  819. VOID
  820. GetVersionString(
  821. IN OUT PTCHAR VersionString,
  822. IN ULONG Length
  823. )
  824. {
  825. ULONG vrs = GetVersion();
  826. //
  827. // Version format is [Major.Minor(2).Build(4)]
  828. //
  829. _sntprintf( VersionString, Length,
  830. TEXT( "%d.%d.%04d" ),
  831. vrs & 0xFF,
  832. (vrs >> 8) & 0xFF,
  833. (vrs >> 16) & 0x3FFF
  834. );
  835. }