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.

2284 lines
68 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. ctools2.c
  5. Abstract:
  6. Low level utilities
  7. --*/
  8. #include "cmd.h"
  9. #pragma hdrstop
  10. #include "ctable.h"
  11. #define MSG_USE_DEFAULT -1 /* M031 */
  12. extern TCHAR PathChar ;
  13. extern TCHAR CurDrvDir[] ;
  14. #define DAYLENGTH 3
  15. extern TCHAR Delimiters[] ;
  16. extern TCHAR SwitChar ;
  17. extern int Ctrlc;
  18. //
  19. // flag if control-c was seen
  20. //
  21. extern BOOL CtrlCSeen;
  22. extern int ExtCtrlc; /* @@4 */
  23. extern TCHAR Fmt19[];
  24. extern unsigned flgwd ;
  25. unsigned int DosErr = 0 ;
  26. unsigned long OHTbl[3] = {0,0,0} ;
  27. extern BOOLEAN fPrintCtrlC;
  28. unsigned int cbTitleCurPrefix;
  29. extern BOOLEAN fTitleChanged;
  30. //
  31. // Used to set and reset ctlcseen flag
  32. //
  33. VOID SetCtrlC();
  34. VOID ResetCtrlC();
  35. //
  36. // console mode at program startup time. Used to reset mode
  37. // after running another process.
  38. //
  39. extern DWORD dwCurInputConMode;
  40. extern DWORD dwCurOutputConMode;
  41. struct msentry { /* M027 */
  42. unsigned errnum ;
  43. unsigned msnum ;
  44. } ;
  45. struct msentry mstabl[] = {
  46. {(unsigned)ERROR_INVALID_FUNCTION, (unsigned)MSG_USE_DEFAULT}, /* 1 */
  47. {ERROR_FILE_NOT_FOUND, ERROR_FILE_NOT_FOUND}, /* 2 */
  48. {ERROR_PATH_NOT_FOUND, ERROR_PATH_NOT_FOUND}, /* 3 */
  49. {ERROR_TOO_MANY_OPEN_FILES, ERROR_TOO_MANY_OPEN_FILES}, /* 4 */
  50. {ERROR_ACCESS_DENIED, ERROR_ACCESS_DENIED}, /* 5 */
  51. {ERROR_INVALID_HANDLE, ERROR_INVALID_HANDLE}, /* 6 */
  52. {ERROR_NOT_ENOUGH_MEMORY, ERROR_NOT_ENOUGH_MEMORY}, /* 8 */
  53. {(unsigned)ERROR_INVALID_ACCESS, (unsigned)MSG_USE_DEFAULT}, /* 12 */
  54. {ERROR_NO_MORE_FILES, ERROR_FILE_NOT_FOUND}, /* 18 */
  55. {ERROR_SECTOR_NOT_FOUND, ERROR_SECTOR_NOT_FOUND}, /* 27 */
  56. {ERROR_SHARING_VIOLATION, ERROR_SHARING_VIOLATION}, /* 32 */
  57. {ERROR_LOCK_VIOLATION, ERROR_LOCK_VIOLATION}, /* 33 */
  58. {ERROR_FILE_EXISTS, ERROR_FILE_EXISTS}, /* 80 */
  59. {ERROR_CANNOT_MAKE, ERROR_CANNOT_MAKE}, /* 82 */
  60. {(unsigned)ERROR_INVALID_PARAMETER, (unsigned)MSG_USE_DEFAULT}, /* 87 */
  61. {ERROR_OPEN_FAILED, ERROR_OPEN_FAILED}, /* 110 */
  62. {ERROR_DISK_FULL, ERROR_DISK_FULL}, /* 112 */
  63. {0,0} /* End of Table */
  64. } ;
  65. /*** OnOffCheck - check an argument string for "ON" or "OFF"
  66. *
  67. * Purpose:
  68. * To check str for the word "ON" or the word "OFF". If flag is nonzero,
  69. * an error message will be printed if str contains anything other than
  70. * just "ON", "OFF", or an empty string.
  71. *
  72. * int OnOffCheck(TCHAR *str, int flag)
  73. *
  74. * Args:
  75. * str - the string to check
  76. * flag - nonzero if error checking is to be done
  77. *
  78. * Returns:
  79. * OOC_EMPTY if str was empty.
  80. * OOC_ON if just "ON" was found.
  81. * OOC_OFF if just "OFF" was found.
  82. * OOC_OTHER if anything else was found.
  83. *
  84. */
  85. int OnOffCheck( TCHAR *str, int flag )
  86. {
  87. TCHAR *tas ; /* Tokenized arg string */
  88. int retval = OOC_OTHER ; /* Return value */
  89. TCHAR SavedChar;
  90. if (str == NULL) {
  91. return OOC_EMPTY;
  92. }
  93. //
  94. // Ignore leading spaces
  95. //
  96. tas = str = SkipWhiteSpace( str );
  97. if (*tas == NULLC) {
  98. return OOC_EMPTY;
  99. }
  100. //
  101. // Find end of first non-blank token
  102. //
  103. while (*tas && !_istspace(*tas))
  104. tas += 1;
  105. //
  106. // If there's another token beyond the first token
  107. // then we can't have ON/OFF
  108. //
  109. if (*SkipWhiteSpace( tas ) != NULLC) {
  110. return retval;
  111. }
  112. SavedChar = *tas;
  113. *tas = NULLC;
  114. if (_tcsicmp( str, TEXT( "on" )) == 0) /* M015 */
  115. retval = OOC_ON ;
  116. else if (_tcsicmp(str,TEXT( "off" )) == 0) /* M015 */
  117. retval = OOC_OFF ;
  118. *tas = SavedChar;
  119. if (retval == OOC_OTHER && flag == OOC_ERROR)
  120. PutStdErr(MSG_BAD_PARM1, NOARGS);
  121. return(retval) ;
  122. }
  123. /*** ChangeDrive - change Command's current drive
  124. *
  125. * Purpose:
  126. * To change Command's default drive.
  127. *
  128. * ChangeDrive(int drvnum)
  129. *
  130. * Args:
  131. * drvnum - the drive number to change to (M010 - 1 == A, etc.)
  132. *
  133. */
  134. void ChangeDrive(drvnum)
  135. int drvnum ;
  136. {
  137. TCHAR denvname[ 4 ];
  138. TCHAR denvvalue[ MAX_PATH ];
  139. TCHAR *s;
  140. BOOLEAN fSet;
  141. UINT OldErrorMode;
  142. denvname[ 0 ] = EQ;
  143. denvname[ 1 ] = (TEXT('A') + (drvnum-1));
  144. denvname[ 2 ] = COLON;
  145. denvname[ 3 ] = NULLC;
  146. fSet = FALSE;
  147. s = NULL;
  148. if (s = GetEnvVar( denvname )) {
  149. fSet = (BOOLEAN)SetCurrentDirectory( s );
  150. }
  151. //
  152. // if the drive was not at current position then
  153. // reset. If it was a mapped drive then it may have
  154. // been disconnected and then reconnected and so
  155. // we should reset to root.
  156. //
  157. if (!fSet) {
  158. //
  159. // In the case where the drive letter was not in the environment
  160. // ans so did not do the first SetCurrentDirectory then do not
  161. // turn off error pop-up
  162. //
  163. if (s != NULL) {
  164. OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  165. }
  166. denvvalue[ 0 ] = denvname[ 1 ];
  167. denvvalue[ 1 ] = denvname[ 2 ];
  168. denvvalue[ 2 ] = PathChar;
  169. denvvalue[ 3 ] = NULLC;
  170. SetEnvVar(denvname,denvvalue );
  171. if (!SetCurrentDirectory( denvvalue )) {
  172. //
  173. // Could not set the drive at all give an error
  174. //
  175. PutStdErr( GetLastError( ), NOARGS );
  176. }
  177. if (s != NULL) {
  178. SetErrorMode( OldErrorMode );
  179. }
  180. }
  181. GetDir(CurDrvDir, GD_DEFAULT) ;
  182. }
  183. /*** PutStdOut - Print a message to STDOUT
  184. *
  185. * Purpose:
  186. * Calls PutMsg sending STDOUT as the handle to which the message
  187. * will be written.
  188. *
  189. * int PutStdOut(unsigned MsgNum, unsigned NumOfArgs, ...)
  190. *
  191. * Args:
  192. * MsgNum - the number of the message to print
  193. * NumOfArgs - the number of total arguments
  194. * ... - the additional arguments for the message
  195. *
  196. * Returns:
  197. * Return value from PutMsg() M026
  198. *
  199. */
  200. PutStdOut(unsigned int MsgNum, unsigned int NumOfArgs, ...)
  201. {
  202. int Result;
  203. va_list arglist;
  204. va_start(arglist, NumOfArgs);
  205. Result = PutMsg(MsgNum, STDOUT, NumOfArgs, &arglist);
  206. va_end(arglist);
  207. return Result;
  208. }
  209. /*** PutStdErr - Print a message to STDERR
  210. *
  211. * Purpose:
  212. * Calls PutMsg sending STDERR as the handle to which the message
  213. * will be written.
  214. *
  215. * int PutStdErr(unsigned MsgNum, unsigned NumOfArgs, ...)
  216. *
  217. * Args:
  218. * MsgNum - the number of the message to print
  219. * NumOfArgs - the number of total arguments
  220. * ... - the additonal arguments for the message
  221. *
  222. * Returns:
  223. * Return value from PutMsg() M026
  224. *
  225. */
  226. int
  227. PutStdErr(unsigned int MsgNum, unsigned int NumOfArgs, ...)
  228. {
  229. int Result;
  230. va_list arglist;
  231. va_start(arglist, NumOfArgs);
  232. Result = PutMsg(MsgNum, STDERR, NumOfArgs, &arglist);
  233. va_end(arglist);
  234. return Result;
  235. }
  236. int
  237. FindMsg(unsigned MsgNum, PTCHAR NullArg, unsigned NumOfArgs, va_list *arglist)
  238. {
  239. unsigned msglen;
  240. TCHAR *Inserts[ 2 ];
  241. CHAR numbuf[ 32 ];
  242. #ifdef UNICODE
  243. TCHAR wnumbuf[ 32 ];
  244. #endif
  245. #if DBG
  246. int error;
  247. #endif
  248. //
  249. // find message without doing argument substitution
  250. //
  251. if (MsgNum == ERROR_MR_MID_NOT_FOUND) {
  252. msglen = 0;
  253. } else {
  254. msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
  255. | FORMAT_MESSAGE_FROM_SYSTEM
  256. | FORMAT_MESSAGE_IGNORE_INSERTS,
  257. NULL,
  258. MsgNum,
  259. 0,
  260. MsgBuf,
  261. sizeof(MsgBuf) / sizeof(TCHAR),
  262. NULL
  263. );
  264. }
  265. if (msglen == 0) {
  266. #if DBG
  267. error = GetLastError();
  268. DEBUG((CTGRP, COLVL, "FindMsg: FormatMessage #2 error %d",error)) ;
  269. #endif
  270. //
  271. // didn't find message
  272. //
  273. _ultoa( MsgNum, numbuf, 16 );
  274. #ifdef UNICODE
  275. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, numbuf, -1, wnumbuf, 32);
  276. Inserts[ 0 ]= wnumbuf;
  277. #else
  278. Inserts[ 0 ]= numbuf;
  279. #endif
  280. Inserts[ 1 ]= (MsgNum >= MSG_FIRST_CMD_MSG_ID ?
  281. TEXT("Application") : TEXT("System"));
  282. MsgNum = ERROR_MR_MID_NOT_FOUND;
  283. msglen = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM
  284. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  285. NULL,
  286. MsgNum,
  287. 0,
  288. MsgBuf,
  289. sizeof(MsgBuf) / sizeof(TCHAR),
  290. (va_list *)Inserts
  291. );
  292. #if DBG
  293. if (msglen == 0) {
  294. error = GetLastError();
  295. DEBUG((CTGRP, COLVL, "FindMsg: FormatMessage #3 error %d",error)) ;
  296. }
  297. #endif
  298. } else {
  299. // see how many arguments are expected and make sure we have enough
  300. PTCHAR tmp;
  301. ULONG count;
  302. tmp=MsgBuf;
  303. count = 0;
  304. while (tmp = mystrchr(tmp, PERCENT)) {
  305. tmp++;
  306. if (*tmp >= TEXT('1') && *tmp <= TEXT('9')) {
  307. count += 1;
  308. } else if (*tmp == PERCENT) {
  309. tmp++;
  310. }
  311. }
  312. if (count > NumOfArgs) {
  313. PTCHAR *LocalArgList;
  314. ULONG i;
  315. LocalArgList = (PTCHAR*)HeapAlloc(GetProcessHeap(), 0, sizeof(PTCHAR) * count);
  316. if (LocalArgList == NULL) {
  317. return 0;
  318. }
  319. for (i=0; i<count; i++) {
  320. if (i < NumOfArgs) {
  321. LocalArgList[i] = (PTCHAR)va_arg( *arglist, UINT_PTR );
  322. } else {
  323. LocalArgList[i] = NullArg;
  324. }
  325. }
  326. msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
  327. | FORMAT_MESSAGE_FROM_SYSTEM
  328. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  329. NULL,
  330. MsgNum,
  331. 0,
  332. MsgBuf,
  333. sizeof(MsgBuf) / sizeof(TCHAR),
  334. (va_list *)LocalArgList
  335. );
  336. HeapFree(GetProcessHeap(), 0, LocalArgList);
  337. } else {
  338. msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
  339. | FORMAT_MESSAGE_FROM_SYSTEM ,
  340. NULL,
  341. MsgNum,
  342. 0,
  343. MsgBuf,
  344. sizeof(MsgBuf) / sizeof(TCHAR),
  345. arglist
  346. );
  347. }
  348. #if DBG
  349. if (msglen == 0) {
  350. error = GetLastError();
  351. DEBUG((CTGRP, COLVL, "FindMsg: FormatMessage error %d",error)) ;
  352. }
  353. #endif
  354. }
  355. return msglen;
  356. }
  357. BOOLEAN fHelpPauseEnabled;
  358. DWORD crowCur;
  359. PTCHAR PauseMsg;
  360. DWORD PauseMsgLen;
  361. void
  362. BeginHelpPause( void )
  363. {
  364. fHelpPauseEnabled = TRUE;
  365. crowCur = 0;
  366. PauseMsgLen = FindMsg(MSG_STRIKE_ANY_KEY, TEXT(" "), NOARGS, NULL);
  367. PauseMsg = gmkstr((PauseMsgLen+2) * sizeof(TCHAR));
  368. _tcscpy(PauseMsg, MsgBuf);
  369. _tcscat(PauseMsg, TEXT("\r"));
  370. return;
  371. }
  372. void
  373. EndHelpPause( void )
  374. {
  375. fHelpPauseEnabled = FALSE;
  376. crowCur = 0;
  377. return;
  378. }
  379. /*** PutMsg - Print a message to a handle
  380. *
  381. * Purpose:
  382. * PutMsg is the work routine which interfaces command.com with the
  383. * DOS message retriever. This routine is called by PutStdOut and
  384. * PutStdErr.
  385. *
  386. * int PutMsg(unsigned MsgNum, unsigned Handle, unsigned NumOfArgs, ...)
  387. *
  388. * Args:
  389. * MsgNum - the number of the message to print
  390. * NumOfArgs - the number of total arguments
  391. * Handle - the handle to print to
  392. * Arg1 [Arg2...] - the additonal arguments for the message
  393. *
  394. * Returns:
  395. * Return value from DOSPUTMESSAGE M026
  396. *
  397. * Notes:
  398. * - PutMsg builds an argument table which is passed to DOSGETMESSAGE;
  399. * this table contains the variable information which the DOS routine
  400. * inserts into the message.
  401. * - If more than one Arg is sent into PutMsg, it (or they) are taken
  402. * from the stack in the first for loop.
  403. * - M020 MsgBuf is a static array of 2K length. It is temporary and
  404. * will be replaced by a more efficient method when decided upon.
  405. *
  406. */
  407. DWORD GetCursorDiff(CONSOLE_SCREEN_BUFFER_INFO* ConInfo, CONSOLE_SCREEN_BUFFER_INFO* ConCurrentInfo)
  408. {
  409. return(DWORD)ConCurrentInfo->dwSize.X * ConCurrentInfo->dwCursorPosition.Y + ConCurrentInfo->dwCursorPosition.X -
  410. (DWORD)ConInfo->dwSize.X * ConInfo->dwCursorPosition.Y + ConInfo->dwCursorPosition.X;
  411. }
  412. int
  413. PutMsg(unsigned int MsgNum, CRTHANDLE Handle, unsigned int NumOfArgs, va_list *arglist)
  414. {
  415. unsigned msglen,writelen;
  416. unsigned rc;
  417. TCHAR c;
  418. PTCHAR msgptr, s, sEnd;
  419. PTCHAR NullArg = TEXT(" ");
  420. DWORD cb;
  421. HANDLE hConsole;
  422. CONSOLE_SCREEN_BUFFER_INFO ConInfo;
  423. DWORD crowMax, dwMode;
  424. if (FileIsConsole(Handle)) {
  425. hConsole = CRTTONT(Handle);
  426. if (!GetConsoleScreenBufferInfo(hConsole, &ConInfo)) {
  427. hConsole = NULL;
  428. } else {
  429. crowMax = ConInfo.srWindow.Bottom - ConInfo.srWindow.Top - 1;
  430. }
  431. } else {
  432. hConsole = NULL;
  433. }
  434. rc = 0; /* live with */
  435. msglen = FindMsg(MsgNum,NullArg,NumOfArgs,arglist);
  436. msgptr = MsgBuf;
  437. writelen = msglen;
  438. for (msgptr=MsgBuf ; msglen!=0 ; msgptr+=writelen,msglen-=writelen) {
  439. if (hConsole != NULL) {
  440. if (fHelpPauseEnabled) {
  441. if (crowCur >= crowMax) {
  442. crowCur = 0;
  443. if (GetConsoleScreenBufferInfo(hConsole, &ConInfo)) {
  444. if (WriteConsole(hConsole, PauseMsg, PauseMsgLen, &rc, NULL)) {
  445. CONSOLE_SCREEN_BUFFER_INFO ConCurrentInfo;
  446. FlushConsoleInputBuffer( GetStdHandle(STD_INPUT_HANDLE) );
  447. GetConsoleMode(hConsole, &dwMode);
  448. SetConsoleMode(hConsole, 0);
  449. c = (TCHAR)_getch();
  450. SetConsoleMode(hConsole, dwMode);
  451. GetConsoleScreenBufferInfo(hConsole, &ConCurrentInfo);
  452. //
  453. // Clear the pause message
  454. //
  455. FillConsoleOutputCharacter(hConsole,
  456. TEXT(' '),
  457. GetCursorDiff(&ConInfo, &ConCurrentInfo),
  458. ConInfo.dwCursorPosition,
  459. &rc
  460. );
  461. SetConsoleCursorPosition(hConsole, ConInfo.dwCursorPosition);
  462. if (c == 0x3) {
  463. SetCtrlC();
  464. return NO_ERROR;
  465. }
  466. }
  467. }
  468. }
  469. s = msgptr;
  470. sEnd = s + msglen;
  471. while (s < sEnd && crowCur < crowMax) {
  472. if (*s++ == TEXT('\n'))
  473. crowCur += 1;
  474. }
  475. writelen = (UINT)(s - msgptr);
  476. } else {
  477. //
  478. // write a maximum of MAXTOWRITE chars at a time so ctrl-s works
  479. //
  480. writelen = min(MAXTOWRITE,msglen);
  481. }
  482. if (!WriteConsole(hConsole, msgptr, writelen, &rc, NULL)) {
  483. rc = GetLastError();
  484. } else {
  485. rc = 0;
  486. continue;
  487. }
  488. } else
  489. if (MyWriteFile(Handle, msgptr, writelen*sizeof(TCHAR), &cb) == 0 ||
  490. cb != writelen*sizeof(TCHAR)
  491. ) {
  492. rc = GetLastError();
  493. break;
  494. } else {
  495. rc = 0;
  496. }
  497. }
  498. //
  499. // If the writefile failed, we need to see what else is at work here. If
  500. // we're trying to write to stderr and we can't, we simply exit. After all,
  501. // we can't even put out a message saying why we failed.
  502. //
  503. if ( rc && Handle == STDERR ) {
  504. CMDexit( FAILURE );
  505. }
  506. return rc;
  507. }
  508. /*** argstr1 - Create formatted message in memory
  509. *
  510. * Purpose:
  511. * Uses sprintf to create a formatted text string in memory to
  512. * use in message output.
  513. *
  514. * TCHAR *argstr1(TCHAR *format, UINT_PTR arg)
  515. *
  516. * Args:
  517. * Format - the format string
  518. * arg - the arguments for the message
  519. *
  520. * Returns:
  521. * Pointer to the formatted message text
  522. *
  523. */
  524. PTCHAR argstr1(format, arg)
  525. TCHAR *format;
  526. ULONG_PTR arg;
  527. {
  528. static TCHAR ArgStr1Buffer[MAX_PATH];
  529. _sntprintf( ArgStr1Buffer, MAX_PATH, format, arg );
  530. ArgStr1Buffer[MAX_PATH - 1] = TEXT( '\0' );
  531. return ArgStr1Buffer;
  532. }
  533. /*** Copen - CMD.EXE open function (M014)
  534. *
  535. * Purpose:
  536. * Opens a file or device and saves the handle for possible later
  537. * signal cleanup.
  538. *
  539. * int Copen(TCHAR *fn, int flags)
  540. *
  541. * Args:
  542. * fn = ASCIZ filename to open
  543. * flags = Flags controlling type of open to make
  544. * fShareMode = Flags for callers sharing mode
  545. *
  546. * Returns:
  547. * Return value from C runtime open
  548. *
  549. * Notes:
  550. * Signal cleanup table does not include STDIN, STDOUT or STDERR.
  551. * M017 - Extensively rewritten to use CreateFile rather than
  552. * runtime open().
  553. *
  554. */
  555. CRTHANDLE
  556. Copen_Work(fn, flags, fShareMode)
  557. TCHAR *fn ;
  558. unsigned int flags, fShareMode;
  559. {
  560. TCHAR c;
  561. DWORD fAccess;
  562. DWORD fCreate;
  563. HANDLE handle ;
  564. DWORD cb;
  565. LONG high;
  566. CRTHANDLE fh;
  567. SECURITY_ATTRIBUTES sa;
  568. sa.bInheritHandle = TRUE;
  569. sa.lpSecurityDescriptor = NULL;
  570. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  571. /* Note that O_RDONLY being a value of 0, cannot be tested for
  572. * conflicts with any of the write type flags.
  573. */
  574. if (((flags & (O_WRONLY | O_RDWR)) > 2) || /* Flags invalid? */
  575. ((flags & O_WRONLY) && (flags & O_APPEND))) {
  576. DEBUG((CTGRP, COLVL, "COPEN: Bad flags issued %04x",flags)) ;
  577. return(BADHANDLE) ;
  578. };
  579. /* M024 - Altered so that the only sharing restriction is to deny
  580. * others write permission if this open is for writing. Any other
  581. * sharing is allowed.
  582. */
  583. if (flags & (O_WRONLY | O_RDWR)) { /* If Writing, set... */
  584. fAccess = GENERIC_WRITE;
  585. /*
  586. * deny write only if it is not console
  587. */
  588. if (_tcsicmp(fn, TEXT("con"))) {
  589. fShareMode = FILE_SHARE_READ;
  590. }
  591. fCreate = CREATE_ALWAYS;/* ...open if exists, else create */
  592. } else {
  593. fAccess = GENERIC_READ;
  594. fCreate = OPEN_EXISTING;
  595. }
  596. if (flags == OP_APPEN) {
  597. //
  598. // When opening for append to a device, we must specify OPEN_EXISTING
  599. // (according to MSDN docs).
  600. //
  601. // If this fails, due to some error, attempt to open with OPEN_ALWAYS
  602. //
  603. if ((handle = CreateFile(fn, fAccess|GENERIC_READ, fShareMode, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
  604. if ((handle = CreateFile(fn, fAccess, fShareMode, &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
  605. DosErr = GetLastError();
  606. DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
  607. if ( DosErr == ERROR_OPEN_FAILED ) {
  608. DosErr = ERROR_FILE_NOT_FOUND;
  609. } /* endif */
  610. return(BADHANDLE) ;
  611. }
  612. }
  613. } else if ((handle = CreateFile(fn, fAccess, fShareMode, &sa, fCreate, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
  614. DosErr = GetLastError();
  615. DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
  616. if ( DosErr == ERROR_OPEN_FAILED ) {
  617. DosErr = ERROR_FILE_NOT_FOUND;
  618. } /* endif */
  619. return(BADHANDLE) ;
  620. }
  621. fh = _open_osfhandle((LONG_PTR)handle, _O_APPEND);
  622. if ((flags & O_APPEND) &&
  623. !FileIsDevice(fh) &&
  624. GetFileSize(handle,NULL) != 0) {
  625. c = NULLC ;
  626. high = -1;
  627. fCreate = SetFilePointer(handle, -1L, &high, FILE_END) ;
  628. if (fCreate == 0xffffffff &&
  629. (DosErr = GetLastError()) != NO_ERROR) {
  630. DEBUG((CTGRP,COLVL,"COPEN: SetFilePointer error %d",DosErr)) ;
  631. // should close CRT handle, not OS handle
  632. if (fh != BADHANDLE) {
  633. _close(fh);
  634. }
  635. return BADHANDLE;
  636. }
  637. fCreate = ReadFile(handle, &c, 1, &cb, NULL) ;
  638. if (fCreate == 0) {
  639. high = 0;
  640. SetFilePointer(handle, 0L, &high, FILE_END) ; /* ...back up 1 */
  641. DEBUG((CTGRP,COLVL,"COPEN: ReadFile error %d",GetLastError())) ;
  642. }
  643. DEBUG((CTGRP,COLVL, "COPEN: Moving file ptr")) ;
  644. if (c == CTRLZ) { /* If end=^Z... */
  645. high = -1;
  646. SetFilePointer(handle, -1L, &high, FILE_END) ; /* ...back up 1 */
  647. }
  648. };
  649. SetList(fh) ;
  650. return(fh) ;
  651. }
  652. CRTHANDLE
  653. Copen(fn, flags)
  654. TCHAR *fn ;
  655. unsigned int flags ;
  656. {
  657. return( Copen_Work(fn, flags, FILE_SHARE_READ | FILE_SHARE_WRITE ) ); /* deny nothing */
  658. }
  659. /*** InSetList - Determine if handle is in signal cleanup table
  660. *
  661. * Purpose:
  662. * To determine if the input handle exsists in the cleanup table.
  663. *
  664. * int InSetList(unsigned int fh)
  665. *
  666. * Args:
  667. * fh = File handle to check.
  668. *
  669. * Returns:
  670. * TRUE: if handle is in table.
  671. * FALSE: if handle is not in table.
  672. *
  673. * Notes:
  674. * - Signal cleanup table does not include STDIN, STDOUT or STDERR.
  675. *
  676. */
  677. unsigned long InSetList(
  678. IN CRTHANDLE fh
  679. )
  680. {
  681. int cnt = 0 ;
  682. if (fh > STDERR && fh < 95) {
  683. while (fh > 31) {
  684. fh -= 32 ;
  685. ++cnt ;
  686. } ;
  687. return( (OHTbl[cnt]) & ((unsigned long)1 << fh) );
  688. };
  689. return( FALSE );
  690. }
  691. /*** Cdup - CMD.EXE dup function (M014)
  692. *
  693. * Purpose:
  694. * Duplicates the supplied handle and saves the new handle for
  695. * possible signal cleanup.
  696. *
  697. * int Cdup(unsigned int fh)
  698. *
  699. * Args:
  700. * fh = Handle to be duplicated
  701. *
  702. * Returns:
  703. * The handle returned by the C runtime dup function
  704. *
  705. * Notes:
  706. * Signal cleanup table does not include STDIN, STDOUT or STDERR.
  707. *
  708. */
  709. CRTHANDLE
  710. Cdup( CRTHANDLE fh )
  711. {
  712. CRTHANDLE NewHandle ;
  713. if ((int)(NewHandle = _dup(fh)) != BADHANDLE)
  714. if ( InSetList( fh ) )
  715. SetList(NewHandle) ;
  716. return(NewHandle) ;
  717. }
  718. /*** Cdup2 - CMD.EXE dup2 function (M014)
  719. *
  720. * Purpose:
  721. * Duplicates the supplied handle and saves the new handle for
  722. * possible signal cleanup.
  723. *
  724. * HANDLE Cdup2(unsigned int fh1, unsigned int fh2)
  725. *
  726. * Args:
  727. * fh = Handle to be duplicated
  728. *
  729. * Returns:
  730. * The handle returned by the C runtime dup2 function
  731. *
  732. * Notes:
  733. * Signal cleanup table does not include STDIN, STDOUT or STDERR.
  734. *
  735. */
  736. CRTHANDLE
  737. Cdup2( CRTHANDLE fh1, CRTHANDLE fh2)
  738. {
  739. unsigned int retcode ;
  740. int cnt = 0 ;
  741. unsigned int fuse ;
  742. if ((int)(retcode = (unsigned)_dup2(fh1,fh2)) != -1) {
  743. if ((fuse = fh2) > STDERR && fuse < 95) {
  744. while (fuse > 31) {
  745. fuse -= 32 ;
  746. ++cnt ;
  747. }
  748. OHTbl[cnt] &= ~((unsigned long)1 << fuse) ;
  749. }
  750. if ( InSetList( fh1 ) )
  751. SetList(fh2) ;
  752. }
  753. return(retcode) ;
  754. }
  755. /*** Cclose - CMD.EXE close handle function (M014)
  756. *
  757. * Purpose:
  758. * Closes an open file or device and removes the handle from the
  759. * signal cleanup table.
  760. *
  761. * int Cclose(unsigned int fh)
  762. *
  763. * Args:
  764. * fh = File handle to be closed.
  765. *
  766. * Returns:
  767. * return code from C runtime close
  768. *
  769. * Notes:
  770. * - Signal cleanup table does not include STDIN, STDOUT or STDERR.
  771. * - M023 * Revised to use bit map instead of malloc'd space.
  772. *
  773. */
  774. int
  775. Cclose( CRTHANDLE fh )
  776. {
  777. int cnt = 0 ;
  778. unsigned int fuse ;
  779. int ret_val;
  780. if (fh == BADHANDLE)
  781. return(0);
  782. if ((fuse = fh) > STDERR && fuse < 95) {
  783. while (fuse > 31) {
  784. fuse -= 32 ;
  785. ++cnt ;
  786. }
  787. OHTbl[cnt] &= ~((unsigned long)1 << fuse) ;
  788. }
  789. ret_val = _close(fh); /* Delete file handle */
  790. return(ret_val);
  791. }
  792. /*** SetList - Place open handle in signal cleanup list (M014)
  793. *
  794. * Purpose:
  795. * Places a handle number in the signal cleanup table for use
  796. * during signal's closing of files.
  797. *
  798. * int SetList(unsigned int fh)
  799. *
  800. * Args:
  801. * fh = File handle to install.
  802. *
  803. * Returns:
  804. * nothing
  805. *
  806. * Notes:
  807. * - Signal cleanup table does not include STDIN, STDOUT or STDERR.
  808. * - M023 * Revised to use bit map instead of malloc'd space.
  809. *
  810. */
  811. void
  812. SetList(
  813. IN CRTHANDLE fh
  814. )
  815. {
  816. int cnt = 0 ;
  817. if (fh > STDERR && fh < 95) {
  818. while (fh > 31) {
  819. fh -= 32 ;
  820. ++cnt ;
  821. } ;
  822. OHTbl[cnt] |= ((unsigned long)1 << fh) ;
  823. };
  824. }
  825. /*** GetFuncPtr - return the i-th function pointer in JumpTable (M015)
  826. *
  827. * int (*GetFuncPtr(int i))()
  828. *
  829. * Args:
  830. * i - the index of the JumpTable entry containing the function pointer
  831. * to be returned
  832. *
  833. * Returns:
  834. * The i-th function pointer in JumpTable.
  835. *
  836. * Notes:
  837. * It is assumed that i is valid.
  838. *
  839. */
  840. int
  841. (*GetFuncPtr(i))(struct cmdnode *)
  842. int i ;
  843. {
  844. return(JumpTable[i].func) ;
  845. }
  846. /*** FindCmd - search JumpTable for a particular command (M015)
  847. *
  848. * Purpose:
  849. * Check the command name string pointers in each of the JumpTable
  850. * entries for one which matches the name in the string supplied by
  851. * the caller.
  852. *
  853. * int FindCmd(int entries, TCHAR *sname, TCHAR *sflags)
  854. *
  855. * Args:
  856. * entries - M009 - This value is highest entry to be checked. One
  857. * must be added for this to become a count of entries to
  858. * check.
  859. * sname - pointer to the command name to search for
  860. * sflags - if the command is found, store the command's flags here
  861. *
  862. * Returns:
  863. * If the entry is found, the entry's JumpTable index.
  864. * Otherwise, -1.
  865. *
  866. */
  867. int FindCmd(
  868. int entries,
  869. const TCHAR *sname,
  870. TCHAR *sflags)
  871. {
  872. int i ;
  873. for (i=0 ; i <= entries ; i++) { /* search through all entries */
  874. if (_tcsicmp(sname,JumpTable[i].name) == 0) { /* test for cmd in table @inx */
  875. /* */
  876. if (!(JumpTable[i].flags & EXTENSCMD) || fEnableExtensions) {
  877. *sflags = JumpTable[i].flags; /* M017 */
  878. cmdfound = i; /* @@5 save current cmd index */
  879. return(i); /* return not found index */
  880. }
  881. } /* */
  882. } /* */
  883. cmdfound = -1; /* @@5 save not found index */
  884. return(-1) ; /* return not found index */
  885. }
  886. /********************* START OF SPECIFICATION **************************/
  887. /* */
  888. /* SUBROUTINE NAME: KillProc */
  889. /* */
  890. /* DESCRIPTIVE NAME: Kill process and wait for it to die */
  891. /* */
  892. /* FUNCTION: This routine kills a specified process during signal */
  893. /* handling. */
  894. /* */
  895. /* NOTES: If the process is started by DosExecPgm, DosKillProcess */
  896. /* is called to kill the process and all its child processes.*/
  897. /* WaitProc is also called to wait for the termination of */
  898. /* the process and child processes. */
  899. /* If the process is started by DosStartSession, */
  900. /* DosStopSession is called to stop the specified session and*/
  901. /* its child sessions. WaitTermQProc is also called to wait */
  902. /* for the termination of the session. */
  903. /* */
  904. /* All of CMD's kills are done on the entire subtree and that */
  905. /* is assumed by this function. For single PID kills, use */
  906. /* DOSKILLPROCESS direct. */
  907. /* */
  908. /* */
  909. /* ENTRY POINT: KillProc */
  910. /* LINKAGE: NEAR */
  911. /* */
  912. /* INPUT: Process ID / Session ID - to kill */
  913. /* Wait - indicates if we should wait here or not */
  914. /* */
  915. /* OUTPUT: None */
  916. /* */
  917. /* EXIT-NORMAL: No error return code from WaitProc or WaitTermQProc */
  918. /* */
  919. /* */
  920. /* EXIT-ERROR: Error return code from DosKillProcess or */
  921. /* DosStopSession. Or error code from WaitProc or */
  922. /* */
  923. /* EFFECTS: None. */
  924. /* */
  925. /* INTERNAL REFERENCES: */
  926. /* ROUTINES: */
  927. /* WaitProc - wait for the termination of the specified process, */
  928. /* its child process, and related pipelined */
  929. /* processes. */
  930. /* */
  931. /* */
  932. /* EXTERNAL REFERENCES: */
  933. /* ROUTINES: */
  934. /* DOSKILLPROCESS - Kill the process and its child processes */
  935. /* DOSSTOPSESSION - Stop the session and its child sessions */
  936. /* WINCHANGESWITCHENTRY - Change switch list entry */
  937. /* */
  938. /********************** END OF SPECIFICATION **************************/
  939. KillProc(pid, wait)
  940. HANDLE pid ;
  941. int wait;
  942. {
  943. unsigned i = 0;
  944. DEBUG((CTGRP,COLVL, "KillProc: Entered PID = %d", pid)) ;
  945. if (!TerminateProcess((HANDLE)pid, 1)) {
  946. DosErr = GetLastError();
  947. }
  948. if (wait) {
  949. i = WaitProc(pid) ; /* wait for the related process to end */
  950. }
  951. return( i );
  952. }
  953. /*** WaitProc - Wait for a command subtree to terminate (M019)
  954. *
  955. * Purpose:
  956. * Provides a means of waiting for a process and all of its
  957. * children to terminate.
  958. *
  959. * int WaitProc(unsigned pid)
  960. *
  961. * Args:
  962. * pid - The process ID to be waited on
  963. *
  964. * Returns:
  965. * Retcode of the head process of the subtree
  966. *
  967. * Notes:
  968. * All of CMD's waits are done on the entire subtree and CMD
  969. * will always wait until someone terminates. That is assumed
  970. * by this function. For single PID waits, use DOSCWAIT direct.
  971. *
  972. */
  973. WaitProc(pid)
  974. HANDLE pid ;
  975. {
  976. unsigned FinalRCode; /* Return value from this function */
  977. DEBUG((CTGRP,COLVL, "WaitProc: Entered PID = %d", pid)) ;
  978. //
  979. // Do not allow printint of ctrl-c in ctrl-c thread while
  980. // waiting for another process. The main loop will handle
  981. // this if the process exits due to ctrl-c.
  982. //
  983. fPrintCtrlC = FALSE;
  984. WaitForSingleObject( (HANDLE)pid, INFINITE );
  985. GetExitCodeProcess( (HANDLE)pid, (LPDWORD)&FinalRCode );
  986. //if (CtrlCSeen & (FinalRCode == CONTROL_C_EXIT)) {
  987. // how do we ever get here???
  988. if (FinalRCode == CONTROL_C_EXIT) {
  989. SetCtrlC();
  990. fprintf( stderr, "^C" );
  991. fflush( stderr );
  992. }
  993. fPrintCtrlC = TRUE;
  994. DEBUG((CTGRP, COLVL, "WaitProc: Returned handle %d, FinalRCode %d", pid, FinalRCode));
  995. CloseHandle( (HANDLE)pid );
  996. DEBUG((CTGRP,COLVL,"WaitProc:Complete and returning %d", FinalRCode)) ;
  997. return(FinalRCode) ;
  998. }
  999. /*** ParseLabel - Parse a batch file label statement (M020)
  1000. *
  1001. * Purpose:
  1002. * Simulates the lexer's handling of labels in GOTO arguments.
  1003. *
  1004. * int ParseLabel(TCHAR *lab, TCHAR buf[],unsigned flag)
  1005. *
  1006. * Args:
  1007. * lab - The batch file label to parse
  1008. * buf - The buffer to hold the parsed label
  1009. * flag - TRUE if this is a source label (already parsed once)
  1010. * - FALSE if this is a test target label.
  1011. *
  1012. * Returns:
  1013. * Nothing useful
  1014. *
  1015. * Notes:
  1016. * Note that source labels (those in the GOTO statement itself),
  1017. * have already been parsed by the normal method with ESCHAR's
  1018. * and other operator tokens presumably processed. Such char's
  1019. * still in the label can be assumed to have been ESC'd already,
  1020. * and therefore, we ignore them. Target labels, however, are
  1021. * raw strings and we must simulate the parser's actions.
  1022. *
  1023. */
  1024. void
  1025. ParseLabel(
  1026. TCHAR *lab,
  1027. TCHAR buf[],
  1028. ULONG cbBufMax,
  1029. BOOLEAN flag
  1030. )
  1031. {
  1032. ULONG i ;
  1033. TCHAR c ;
  1034. lab = EatWS(lab,NULL) ; /* Strip normal whitespace */
  1035. if ((c = *lab) == COLON || c == PLUS) /* Eat first : or + ... */
  1036. ++lab ; /* ...only */
  1037. if (!flag) /* If target strip... */
  1038. lab = EatWS(lab,NULL) ; /* ... any add'l WS */
  1039. for (i = 0, c = *lab ; i < cbBufMax ; c = *(++lab)) {
  1040. DEBUG((CTGRP,COLVL,"ParseLabel: Current Char = %04x", *lab)) ;
  1041. if ((flag && mystrchr(Delimiters, c)) ||
  1042. //mystrchr("+:\n\r\x20", c)) {
  1043. mystrchr( TEXT("+:\n\r\t "), c)) { //change from \x20 to space bug
  1044. // mips compiler
  1045. DEBUG((CTGRP,COLVL,"ParseLabel: Found terminating delim.")) ;
  1046. break ;
  1047. };
  1048. if (!flag) {
  1049. if (mystrchr(TEXT("&<|>"), c)) {
  1050. DEBUG((CTGRP,COLVL,
  1051. "ParseLabel: Found operator in target!")) ;
  1052. break ;
  1053. };
  1054. if (c == ESCHAR) {
  1055. DEBUG((CTGRP,COLVL,
  1056. "ParseLabel: Found '^' adding %04x",
  1057. *(lab+1))) ;
  1058. buf[i++] = *(++lab) ;
  1059. continue ;
  1060. };
  1061. };
  1062. DEBUG((CTGRP,COLVL,"ParseLabel: Adding %02x",c)) ;
  1063. buf[i++] = c ;
  1064. } ;
  1065. buf[i] = NULLC ;
  1066. DEBUG((CTGRP,COLVL,"ParseLabel: Exitted with label %ws", buf)) ;
  1067. }
  1068. /*** EatWS - Strip leading whitespace and other special chars (M020)
  1069. *
  1070. * Purpose:
  1071. * Remove leading whitespace and any special chars from the string.
  1072. *
  1073. * TCHAR *EatWS(TCHAR *str, TCHAR *spec)
  1074. *
  1075. * Args:
  1076. * str - The string to eat from
  1077. * spec - Additional delimiters to eat
  1078. *
  1079. * Returns:
  1080. * Updated character pointer
  1081. *
  1082. * Notes:
  1083. *
  1084. */
  1085. PTCHAR
  1086. EatWS(
  1087. TCHAR *str,
  1088. TCHAR *spec )
  1089. {
  1090. TCHAR c ;
  1091. if (str != NULL) {
  1092. while ((_istspace(c = *str) && c != NLN) ||
  1093. (mystrchr(Delimiters, c) && c) ||
  1094. (spec && mystrchr(spec,c) && c))
  1095. ++str ;
  1096. }
  1097. return(str) ;
  1098. }
  1099. /*** IsValidDrv - Check drive validity
  1100. *
  1101. * Purpose:
  1102. * Check validity of passed drive letter.
  1103. *
  1104. * int IsValidDrv(TCHAR drv)
  1105. *
  1106. * Args:
  1107. * drv - The letter of the drive to check
  1108. *
  1109. * Returns:
  1110. * TRUE if drive is valid
  1111. * FALSE if not
  1112. *
  1113. * Notes:
  1114. *
  1115. */
  1116. IsValidDrv(TCHAR drv)
  1117. {
  1118. TCHAR temp[4];
  1119. temp[ 0 ] = drv;
  1120. temp[ 1 ] = COLON;
  1121. temp[ 2 ] = PathChar;
  1122. temp[ 3 ] = NULLC;
  1123. //
  1124. // return of 0 or 1 mean can't determine or root
  1125. // does not exists.
  1126. //
  1127. if (GetDriveType(temp) <= 1)
  1128. return( FALSE );
  1129. else {
  1130. return( TRUE );
  1131. }
  1132. }
  1133. /*** IsDriveLocked - Check For Drive Locked Condition
  1134. *
  1135. * Purpose:
  1136. * The real purpose is to check for a drive locked, but since this
  1137. * could be the first time that the disk get hit we will just return
  1138. * the Dos Error Code
  1139. *
  1140. * int IsDriveLocked(TCHAR drv)
  1141. *
  1142. * Args:
  1143. * drv - The letter of the drive to check
  1144. *
  1145. * Returns:
  1146. * 0 if no errors
  1147. * Dos Error number if failure
  1148. *
  1149. * Notes:
  1150. *
  1151. */
  1152. IsDriveLocked( TCHAR drv )
  1153. {
  1154. DWORD Vsn[2];
  1155. TCHAR szVolName[MAX_PATH];
  1156. TCHAR szVolRoot[5];
  1157. DWORD rc;
  1158. szVolRoot[ 0 ] = drv;
  1159. szVolRoot[ 1 ] = COLON;
  1160. szVolRoot[ 2 ] = PathChar;
  1161. szVolRoot[ 3 ] = NULLC;
  1162. //
  1163. // If floppy and locked will get this.
  1164. //
  1165. if ( (rc = GetDriveType(szVolRoot)) <= 1) {
  1166. return( TRUE );
  1167. }
  1168. //
  1169. // If removable check if access to vol. info allowed.
  1170. // if not then assume it is locked.
  1171. //
  1172. if ((rc != DRIVE_REMOVABLE) && (rc != DRIVE_CDROM)) {
  1173. if (!GetVolumeInformation(szVolRoot,
  1174. szVolName,
  1175. MAX_PATH,
  1176. Vsn,
  1177. NULL,
  1178. NULL,
  1179. NULL,
  1180. 0)) {
  1181. if ( GetLastError() == ERROR_ACCESS_DENIED) {
  1182. return( TRUE );
  1183. }
  1184. }
  1185. }
  1186. return( FALSE );
  1187. }
  1188. /*** PtrErr - Print Error resulting from last recorded system call
  1189. *
  1190. * Purpose:
  1191. * Prints appropriate error message resulting from last system
  1192. * call whose return code is saved in DosErr variable.
  1193. *
  1194. * int PtrErr(unsigned msgnum)
  1195. *
  1196. * Args:
  1197. * msgnum = Default message to print if no match
  1198. *
  1199. * Returns:
  1200. * Nothing
  1201. *
  1202. * Notes:
  1203. * msgnum can be passed in as NULL if no msg is to be printed as a
  1204. * default.
  1205. *
  1206. */
  1207. void PrtErr(msgnum)
  1208. unsigned msgnum ;
  1209. {
  1210. unsigned i, /* Temp counter */
  1211. tabmsg = (unsigned)MSG_USE_DEFAULT ; /* Table message found */
  1212. for (i = 0 ; mstabl[i].errnum != 0 ; ++i) {
  1213. if (DosErr == mstabl[i].errnum) {
  1214. tabmsg = mstabl[i].msnum ;
  1215. break ;
  1216. }
  1217. }
  1218. if (tabmsg != (unsigned)MSG_USE_DEFAULT)
  1219. msgnum = tabmsg ;
  1220. if (msgnum)
  1221. PutStdErr(msgnum, NOARGS) ; /* @@ */
  1222. }
  1223. /*** GetMsg - Get a message ***/
  1224. PTCHAR
  1225. GetMsg(unsigned MsgNum, ...)
  1226. {
  1227. PTCHAR Buffer = NULL;
  1228. unsigned int msglen;
  1229. va_list arglist;
  1230. va_start( arglist, MsgNum );
  1231. msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
  1232. | FORMAT_MESSAGE_FROM_SYSTEM
  1233. | FORMAT_MESSAGE_ALLOCATE_BUFFER ,
  1234. NULL,
  1235. MsgNum,
  1236. 0,
  1237. (LPTSTR) &Buffer,
  1238. 0,
  1239. &arglist
  1240. );
  1241. va_end(arglist);
  1242. return Buffer;
  1243. }
  1244. /********************** START OF SPECIFICATIONS **********************/
  1245. /* SUBROUTINE NAME: Copen_Work2 */
  1246. /* */
  1247. /* DESCRIPTIVE NAME: Worker routine to open a file. */
  1248. /* */
  1249. /* FUNCTION: Opens a file or device and saves the handle for */
  1250. /* possible later signal cleanup. Set the extended */
  1251. /* attribute information from the file being opened. */
  1252. /* */
  1253. /* NOTES: Signal cleanup table does not include STDIN, STDOUT or */
  1254. /* STDERR. M017 - Extensively rewritten to use CreateFile */
  1255. /* rather than runtime open(). */
  1256. /* */
  1257. /* ENTRY POINT: Copen_Work2 */
  1258. /* LINKAGE: Copen_Work2(fn, flags, fShareMode, eaop, FSwitch) */
  1259. /* */
  1260. /* INPUT: (PARAMETERS) */
  1261. /* */
  1262. /* filename = ASCIZ filename to open */
  1263. /* flags = Flags controlling type of open to make */
  1264. /* fShareMode = Flags for callers sharing mode */
  1265. /* eaop = Extended attribute buffer pointer. */
  1266. /* FSwitch = Fail if EAs can't be copied */
  1267. /* */
  1268. /* EXIT-NORMAL: */
  1269. /* Return file handle value like C runtime open */
  1270. /* */
  1271. /* EXIT-ERROR: */
  1272. /* Return -1 if open failed */
  1273. /* */
  1274. /* EFFECTS: None. */
  1275. /* */
  1276. /* INTERNAL REFERENCES: */
  1277. /* ROUTINES: */
  1278. /* FileIsDevice - test for file or device via DOSQHANDTYPE */
  1279. /* SetList - add handle from open to cleanup list */
  1280. /* varb:DosErr - global error return variable */
  1281. /* */
  1282. /* EXTERNAL REFERENCES: */
  1283. /* ROUTINES: */
  1284. /* CreateFile - open a file with ability for EA processing */
  1285. /* */
  1286. /*********************** END OF SPECIFICATIONS ***********************/
  1287. CRTHANDLE
  1288. Copen_Work2(fn, flags, fShareMode, FSwitch)
  1289. TCHAR *fn ; /* filename */
  1290. unsigned int flags, fShareMode, FSwitch ; /* flags and special case flags */
  1291. {
  1292. HANDLE handl ; /* Handle ret'd */
  1293. CRTHANDLE rcode; /* return code */
  1294. DWORD fAccess;
  1295. DWORD fCreate;
  1296. SECURITY_ATTRIBUTES sa;
  1297. sa.bInheritHandle = TRUE;
  1298. sa.lpSecurityDescriptor = NULL;
  1299. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  1300. /***************************************************************************/
  1301. /* Note that O_RDONLY being a value of 0, cannot be tested for */
  1302. /* conflicts with any of the write type flags. */
  1303. /***************************************************************************/
  1304. DBG_UNREFERENCED_PARAMETER( FSwitch);
  1305. if (((flags & (O_WRONLY | O_RDWR)) > 2) || /* Flags invalid? */
  1306. ((flags & O_WRONLY) && /* */
  1307. (flags & O_APPEND))) { /* */
  1308. DEBUG((CTGRP, COLVL, "COPEN: Bad flags issued %04x",flags)) ;
  1309. rcode = BADHANDLE; /* set bad handle */
  1310. } else {
  1311. /***************************************************************************/
  1312. /* M024 - Altered so that the only sharing restriction is to deny */
  1313. /* others write permission if this open is for writing. Any other */
  1314. /* sharing is allowed. */
  1315. /***************************************************************************/
  1316. if (flags & (O_WRONLY | O_RDWR)) { /* If Writing, set... */
  1317. fAccess = GENERIC_WRITE;
  1318. if (flags & O_RDWR)
  1319. fAccess |= GENERIC_READ;
  1320. /*
  1321. * deny write only if it is not console
  1322. */
  1323. if (_tcsicmp(fn, TEXT("con"))) {
  1324. fShareMode = FILE_SHARE_READ;
  1325. }
  1326. fCreate = CREATE_ALWAYS;/* ...open if exists, else create */
  1327. } else {
  1328. fAccess = GENERIC_READ;
  1329. fCreate = OPEN_EXISTING;
  1330. if (!_tcsicmp(fn,TEXT("con"))) {
  1331. fShareMode = FILE_SHARE_READ;
  1332. }
  1333. }
  1334. fn = StripQuotes(fn);
  1335. if (fCreate == CREATE_ALWAYS &&
  1336. (handl=CreateFile(fn, fAccess, fShareMode, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) != INVALID_HANDLE_VALUE) {
  1337. rcode = _open_osfhandle((LONG_PTR)handl, _O_APPEND);
  1338. } else if ((handl = CreateFile(fn, fAccess, fShareMode, &sa, fCreate, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) == INVALID_HANDLE_VALUE) {
  1339. DosErr = GetLastError();
  1340. DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
  1341. if (DosErr==ERROR_OPEN_FAILED) {
  1342. DosErr=ERROR_FILE_NOT_FOUND; /* change to another error */
  1343. }
  1344. rcode = BADHANDLE;
  1345. } else {
  1346. rcode = _open_osfhandle((LONG_PTR)handl, _O_APPEND);
  1347. } /* */
  1348. } /* */
  1349. return(rcode ) ; /* return handle to caller */
  1350. }
  1351. /********************** START OF SPECIFICATIONS **********************/
  1352. /* SUBROUTINE NAME: Copen2 */
  1353. /* */
  1354. /* DESCRIPTIVE NAME: Open a destination file with extended attributes*/
  1355. /* */
  1356. /* FUNCTION: Call a worker routine to open a destination file or */
  1357. /* device and set the extended attribute information */
  1358. /* from the source file if this is the first file */
  1359. /* and/or only file and there are extended attributes */
  1360. /* available. */
  1361. /* */
  1362. /* NOTES: */
  1363. /* */
  1364. /* ENTRY POINT: Copen2 */
  1365. /* LINKAGE: Copen2(fn, flags, FSwitch) */
  1366. /* */
  1367. /* INPUT: (PARAMETERS) */
  1368. /* */
  1369. /* fn = ASCIZ filename to open */
  1370. /* flags = Flags controlling type of open to make */
  1371. /* */
  1372. /* */
  1373. /* EXIT-NORMAL: */
  1374. /* Return file handle value like C runtime open */
  1375. /* */
  1376. /* EXIT-ERROR: */
  1377. /* Return -1 if open failed */
  1378. /* */
  1379. /* EFFECTS: None. */
  1380. /* */
  1381. /* INTERNAL REFERENCES: */
  1382. /* ROUTINES: */
  1383. /* Copen_Work2 - worker routine for performing CreateFile */
  1384. /* varb: first_fflag-TRUE = first file FALSE = not first file */
  1385. /* */
  1386. /* */
  1387. /*********************** END OF SPECIFICATIONS ***********************/
  1388. CRTHANDLE
  1389. Copen2(fn, flags, FSwitch)
  1390. TCHAR *fn ; /* file name */
  1391. unsigned int flags ; /* open flags */
  1392. unsigned FSwitch;
  1393. {
  1394. return(Copen_Work2(fn, flags, FILE_SHARE_READ | FILE_SHARE_WRITE, FSwitch));
  1395. }
  1396. /********************** START OF SPECIFICATIONS **********************/
  1397. /* SUBROUTINE NAME: Copen_Copy2 */
  1398. /* */
  1399. /* DESCRIPTIVE NAME: Open a source file with extended attributes. */
  1400. /* */
  1401. /* FUNCTION: Call a worker routine to open a source file or device */
  1402. /* and get the extended attribute information from the */
  1403. /* file if ffirst2 or fnext2 says this is a EA file. */
  1404. /* */
  1405. /* NOTES: */
  1406. /* */
  1407. /* ENTRY POINT: Copen_Copy2 */
  1408. /* LINKAGE: Copen2(fn, flags) */
  1409. /* */
  1410. /* INPUT: (PARAMETERS) */
  1411. /* */
  1412. /* fn = ASCIZ filename to open */
  1413. /* flags = Flags controlling type of open to make */
  1414. /* */
  1415. /* EXIT-NORMAL: */
  1416. /* Return file handle value like C runtime open */
  1417. /* */
  1418. /* EXIT-ERROR: */
  1419. /* Return -1 if open failed */
  1420. /* */
  1421. /* EFFECTS: None. */
  1422. /* */
  1423. /* INTERNAL REFERENCES: */
  1424. /* ROUTINES: */
  1425. /* Copen_Work2 - worker routine for performing CreateFile */
  1426. /* Cclose - close a handle file/device handle opened */
  1427. /* and remove handle from handles to free */
  1428. /* varb: first_file- TRUE = first file FALSE = not first file */
  1429. /* */
  1430. /* */
  1431. /* */
  1432. /* EXTERNAL REFERENCES: */
  1433. /* ROUTINES: */
  1434. /* DOSALLOCSEG - request an amount of ram memory */
  1435. /* DOSFREESEG - free a DOSALLOCSEG segment of ram memory */
  1436. /* DOSQFILEINFO - request EA info for a file using level 2 */
  1437. /* */
  1438. /*********************** END OF SPECIFICATIONS ***********************/
  1439. CRTHANDLE
  1440. Copen_Copy2(fn, flags)
  1441. TCHAR *fn; /* file name */
  1442. unsigned int flags ; /* open flags */
  1443. {
  1444. return(Copen_Work2(fn, flags, FILE_SHARE_READ | FILE_SHARE_WRITE, TRUE));
  1445. }
  1446. CRTHANDLE
  1447. Copen_Copy3(fn)
  1448. TCHAR *fn; /* file name */
  1449. {
  1450. HANDLE handl ; /* Handle ret'd */
  1451. CRTHANDLE rcode; /* return code */
  1452. SECURITY_ATTRIBUTES sa;
  1453. sa.bInheritHandle = TRUE;
  1454. sa.lpSecurityDescriptor = NULL;
  1455. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  1456. fn = StripQuotes(fn);
  1457. handl = CreateFile(fn, GENERIC_WRITE, 0, &sa, TRUNCATE_EXISTING,
  1458. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  1459. if (handl == INVALID_HANDLE_VALUE) {
  1460. DosErr = GetLastError();
  1461. DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
  1462. if (DosErr==ERROR_OPEN_FAILED) {
  1463. DosErr=ERROR_FILE_NOT_FOUND; /* change to another error */
  1464. }
  1465. rcode = BADHANDLE;
  1466. } else {
  1467. rcode = _open_osfhandle((LONG_PTR)handl, _O_APPEND);
  1468. } /* */
  1469. return(rcode ) ; /* return handle to caller */
  1470. }
  1471. TCHAR *
  1472. StripQuotes( TCHAR *wrkstr )
  1473. {
  1474. static TCHAR tempstr[MAXTOKLEN];
  1475. int i,j,slen;
  1476. if ( mystrchr(wrkstr,QUOTE) ) {
  1477. mytcsnset(tempstr, NULLC, MAXTOKLEN);
  1478. slen= mystrlen(wrkstr);
  1479. j=0;
  1480. for (i=0;i<slen;i++) {
  1481. if ( wrkstr[i] != QUOTE )
  1482. tempstr[j++] = wrkstr[i];
  1483. }
  1484. tempstr[j] = NULLC;
  1485. return(tempstr);
  1486. } else
  1487. return(wrkstr);
  1488. }
  1489. TCHAR *
  1490. SkipWhiteSpace( TCHAR *String )
  1491. {
  1492. while (*String && _istspace( *String )) {
  1493. String++;
  1494. }
  1495. return String;
  1496. }
  1497. ULONG
  1498. PromptUser (
  1499. IN PTCHAR szArg,
  1500. IN ULONG msgId,
  1501. IN ULONG responseDataId
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. Prompts user for single letter answer to a question. The prompt can be
  1506. a message plus an optional single argument. Valid letters are defined
  1507. by contents of message specified by responseDataId. Case is not
  1508. significant.
  1509. Arguments:
  1510. pszTok - list of attributes
  1511. Return Value:
  1512. Returns index into response data
  1513. Return: the user response
  1514. --*/
  1515. {
  1516. BOOLEAN fFirst;
  1517. TCHAR chT;
  1518. TCHAR chAnsw = NULLC;
  1519. ULONG dwOutputModeOld;
  1520. ULONG dwOutputModeCur;
  1521. ULONG dwInputModeOld;
  1522. ULONG dwInputModeCur;
  1523. BOOLEAN fOutputModeSet = FALSE;
  1524. BOOLEAN fInputModeSet = FALSE;
  1525. HANDLE hndStdOut = NULL;
  1526. HANDLE hndStdIn = NULL;
  1527. TCHAR responseChoices[16];
  1528. TCHAR *p;
  1529. ULONG iResponse;
  1530. ULONG iMaxResponse;
  1531. DWORD cb;
  1532. PTCHAR Message;
  1533. if (msgId == MSG_MOVE_COPY_OVERWRITE) {
  1534. CRTHANDLE srcptr;
  1535. srcptr = Copen_Copy2(szArg, (unsigned int)O_RDONLY);
  1536. if (srcptr != BADHANDLE) {
  1537. if (FileIsDevice( srcptr )) {
  1538. Cclose(srcptr);
  1539. return 2; // Return All response for devices
  1540. }
  1541. Cclose(srcptr);
  1542. }
  1543. }
  1544. Message = GetMsg( responseDataId );
  1545. if (Message != NULL && _tcslen( Message ) < 16) {
  1546. _tcscpy( responseChoices, Message );
  1547. _tcsupr( responseChoices );
  1548. } else {
  1549. _tcscpy( responseChoices, TEXT("NY") );
  1550. }
  1551. iMaxResponse = _tcslen( responseChoices ) - 1;
  1552. LocalFree( Message );
  1553. hndStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1554. if (GetConsoleMode( hndStdOut, &dwOutputModeOld) ) {
  1555. // make sure CRLF is processed correctly
  1556. dwOutputModeCur = dwOutputModeOld | ENABLE_PROCESSED_OUTPUT;
  1557. fOutputModeSet = TRUE;
  1558. SetConsoleMode(hndStdOut,dwOutputModeCur);
  1559. GetLastError();
  1560. }
  1561. hndStdIn = GetStdHandle(STD_INPUT_HANDLE);
  1562. if (GetConsoleMode( hndStdIn, &dwInputModeOld) ) {
  1563. // make sure input is processed correctly
  1564. dwInputModeCur = dwInputModeOld | ENABLE_LINE_INPUT |
  1565. ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT;
  1566. fInputModeSet = TRUE;
  1567. SetConsoleMode(hndStdIn,dwInputModeCur);
  1568. GetLastError();
  1569. #ifndef WIN95_CMD
  1570. if (lpSetConsoleInputExeName != NULL)
  1571. (*lpSetConsoleInputExeName)( TEXT("<noalias>") );
  1572. #endif
  1573. }
  1574. //
  1575. // Loop till the user answer with a valid character
  1576. //
  1577. while (TRUE) {
  1578. chT = NULLC;
  1579. fFirst = TRUE ;
  1580. if (szArg) {
  1581. PutStdOut(msgId, ONEARG, szArg );
  1582. } else {
  1583. PutStdOut(msgId, NOARGS);
  1584. }
  1585. //
  1586. // Flush keyboard before asking for response
  1587. //
  1588. if (FileIsDevice(STDIN)) {
  1589. FlushConsoleInputBuffer( GetStdHandle(STD_INPUT_HANDLE) );
  1590. }
  1591. //
  1592. // Read till EOL
  1593. //
  1594. while (chT != NLN) {
  1595. if (ReadBufFromInput(
  1596. GetStdHandle(STD_INPUT_HANDLE),
  1597. (TCHAR*)&chT, 1, &cb) == 0 ||
  1598. cb != 1) {
  1599. chAnsw = responseChoices[0];
  1600. cmd_printf(CrLf) ;
  1601. break;
  1602. }
  1603. if (fFirst) {
  1604. chAnsw = (TCHAR) _totupper(chT) ;
  1605. fFirst = FALSE ;
  1606. }
  1607. if (!FileIsDevice(STDIN) || !(flgwd & 1)) {
  1608. cmd_printf(Fmt19,chT) ;
  1609. }
  1610. }
  1611. p = _tcschr(responseChoices, chAnsw);
  1612. if (p != NULL) {
  1613. iResponse = (UINT)(p - responseChoices);
  1614. if (iResponse <= iMaxResponse) {
  1615. break;
  1616. }
  1617. }
  1618. }
  1619. if (fOutputModeSet) {
  1620. SetConsoleMode( hndStdOut, dwOutputModeOld );
  1621. }
  1622. if (fInputModeSet) {
  1623. SetConsoleMode( hndStdIn, dwInputModeOld );
  1624. #ifndef WIN95_CMD
  1625. if (lpSetConsoleInputExeName != NULL)
  1626. (*lpSetConsoleInputExeName)( TEXT("CMD.EXE") );
  1627. #endif
  1628. }
  1629. return(iResponse);
  1630. }
  1631. ULONG LastMsgNo;
  1632. int
  1633. eSpecialHelp(
  1634. IN struct cmdnode *pcmdnode
  1635. )
  1636. {
  1637. TCHAR szHelpStr[] = TEXT("/\0?");
  1638. if (LastMsgNo == MSG_HELP_FOR)
  1639. CheckHelpSwitch(FORTYP, szHelpStr);
  1640. else
  1641. if (LastMsgNo == MSG_HELP_IF)
  1642. CheckHelpSwitch(IFTYP, szHelpStr);
  1643. else
  1644. if (LastMsgNo == MSG_HELP_REM)
  1645. CheckHelpSwitch(REMTYP, szHelpStr);
  1646. else
  1647. PutStdOut( LastMsgNo, NOARGS );
  1648. return SUCCESS;
  1649. }
  1650. BOOLEAN
  1651. CheckHelp (
  1652. IN ULONG jmptblidx,
  1653. IN PTCHAR pszTok,
  1654. IN BOOL fDisplay
  1655. )
  1656. {
  1657. ULONG msgno = JumpTable[jmptblidx].msgno;
  1658. ULONG extmsgno = JumpTable[jmptblidx].extmsgno;
  1659. ULONG noextramsg =JumpTable[jmptblidx].noextramsg;
  1660. if (!pszTok) {
  1661. return( FALSE );
  1662. }
  1663. while (*pszTok) {
  1664. if (*pszTok == SwitChar) {
  1665. //
  1666. // Check for /?. Ignore /? if ? not followed by delimeter and IF command
  1667. // This allows if ./?. == ..
  1668. //
  1669. if (*(pszTok + 2) == QMARK && (jmptblidx != IFTYP || *(pszTok + 3) == NULLC) ) {
  1670. if (msgno == 0 && fEnableExtensions) {
  1671. msgno = extmsgno;
  1672. extmsgno = 0;
  1673. }
  1674. if (msgno == 0) {
  1675. msgno = MSG_SYNERR_GENL;
  1676. extmsgno = 0;
  1677. noextramsg = 0;
  1678. }
  1679. if ( fDisplay ) {
  1680. //
  1681. // Display help now
  1682. //
  1683. BeginHelpPause();
  1684. #define CTRLCBREAK if (CtrlCSeen) break
  1685. do {
  1686. CTRLCBREAK; PutStdOut(msgno, NOARGS);
  1687. if (!fEnableExtensions) break;
  1688. if (extmsgno != 0) {
  1689. CTRLCBREAK; PutStdOut(extmsgno, NOARGS);
  1690. }
  1691. while (!CtrlCSeen && noextramsg--)
  1692. PutStdOut(++extmsgno, NOARGS);
  1693. } while ( FALSE );
  1694. EndHelpPause();
  1695. } else {
  1696. //
  1697. // Remember the message, eSpecicalHelp will display it later.
  1698. // extmsgno will always be zero here
  1699. //
  1700. LastMsgNo = msgno;
  1701. }
  1702. return( TRUE );
  1703. }
  1704. //
  1705. // move over SwitChar, switch value and 2 0's
  1706. //
  1707. pszTok += mystrlen(pszTok) + 1;
  1708. if (*pszTok) {
  1709. pszTok += mystrlen(pszTok) + 1;
  1710. }
  1711. } else
  1712. if (jmptblidx == ECHTYP) {
  1713. //
  1714. // ECHO only supports /? as first token. Allows you echo a string
  1715. // with /? in it (e.g. ECHO Update /?).
  1716. //
  1717. break;
  1718. } else {
  1719. //
  1720. // move over param. and 1 0's
  1721. //
  1722. pszTok += mystrlen(pszTok) + 1;
  1723. }
  1724. }
  1725. return( FALSE );
  1726. }
  1727. BOOLEAN
  1728. TokBufCheckHelp(
  1729. IN PTCHAR pszTokBuf,
  1730. IN ULONG jmptblidx
  1731. )
  1732. {
  1733. TCHAR szT[10];
  1734. PTCHAR pszTok;
  1735. //
  1736. // Tokensize the command line (special delimeters are tokens)
  1737. //
  1738. szT[0] = SwitChar ;
  1739. szT[1] = NULLC ;
  1740. pszTok = TokStr(pszTokBuf, szT, TS_SDTOKENS);
  1741. return CheckHelp(jmptblidx, pszTok, FALSE);
  1742. }
  1743. BOOLEAN
  1744. CheckHelpSwitch (
  1745. IN ULONG jmptblidx,
  1746. IN PTCHAR pszTok
  1747. )
  1748. {
  1749. return CheckHelp( jmptblidx,
  1750. pszTok,
  1751. TRUE
  1752. ) ;
  1753. }
  1754. PTCHAR
  1755. GetTitle(
  1756. IN struct cmdnode *pcmdnode
  1757. )
  1758. {
  1759. PTCHAR tptr, argptr;
  1760. /* Allocate string space for command line */
  1761. /* Command_Head + Optional_Space + Command_Tail + Null + Null */
  1762. if (!(argptr = mkstr(mystrlen(pcmdnode->cmdline)*sizeof(TCHAR)+mystrlen(pcmdnode->argptr)*sizeof(TCHAR)+3*sizeof(TCHAR))))
  1763. return(NULL) ;
  1764. /* The command line is the concatenation of the command head and tail */
  1765. mystrcpy(argptr,pcmdnode->cmdline);
  1766. tptr = argptr+mystrlen(argptr);
  1767. if (mystrlen(pcmdnode->argptr)) {
  1768. if (*pcmdnode->argptr != SPACE) {
  1769. //DbgPrint("GetTitle: first arg char not space %s\n",pcmdnode->argptr);
  1770. *tptr++ = SPACE;
  1771. }
  1772. mystrcpy(tptr,pcmdnode->argptr);
  1773. tptr[mystrlen(tptr)+1] = NULLC; /* Add extra null byte */
  1774. }
  1775. tptr = argptr;
  1776. return( tptr );
  1777. }
  1778. VOID
  1779. SetConTitle(
  1780. IN PTCHAR pszTitle
  1781. )
  1782. {
  1783. ULONG cbNewTitle, cbTitle;
  1784. PTCHAR pszNewTitle, pTmp;
  1785. if (pszTitle == NULL) {
  1786. return;
  1787. }
  1788. if ((!CurrentBatchFile) && (!SingleCommandInvocation)) {
  1789. if ((pszNewTitle = (PTCHAR)HeapAlloc(GetProcessHeap(), 0, (MAX_PATH+2)*sizeof(TCHAR))) == NULL) {
  1790. return;
  1791. }
  1792. cbNewTitle = GetConsoleTitle( pszNewTitle, MAX_PATH );
  1793. if (!cbNewTitle) {
  1794. return;
  1795. }
  1796. cbTitle = mystrlen(pszTitle);
  1797. pTmp = (PTCHAR)HeapReAlloc(GetProcessHeap(), 0, pszNewTitle, (cbNewTitle+cbTitle+cbTitleCurPrefix+10)*sizeof(TCHAR));
  1798. if (pTmp == NULL) {
  1799. HeapFree( GetProcessHeap( ), 0, pszNewTitle );
  1800. return;
  1801. }
  1802. pszNewTitle = pTmp;
  1803. if (fTitleChanged) {
  1804. _tcscpy( pszNewTitle + cbTitleCurPrefix, pszTitle );
  1805. } else {
  1806. _tcscat( pszNewTitle, TEXT(" - ") );
  1807. cbTitleCurPrefix = _tcslen( pszNewTitle );
  1808. _tcscat( pszNewTitle, pszTitle );
  1809. fTitleChanged = TRUE;
  1810. }
  1811. SetConsoleTitle(pszNewTitle);
  1812. HeapFree(GetProcessHeap(), 0, pszNewTitle);
  1813. }
  1814. }
  1815. VOID
  1816. ResetConTitle(
  1817. IN PTCHAR pszTitle
  1818. )
  1819. {
  1820. if (pszTitle == NULL) {
  1821. return;
  1822. }
  1823. if ((!CurrentBatchFile) && (fTitleChanged)) {
  1824. SetConsoleTitle(pszTitle);
  1825. cbTitleCurPrefix = 0;
  1826. fTitleChanged = FALSE;
  1827. }
  1828. }
  1829. /***
  1830. *void ResetConsoleMode( void ) - make sure correct mode bits are set
  1831. *
  1832. *Purpose:
  1833. * Called after each external command or ^C in case they hosed out modes.
  1834. *
  1835. *Entry:
  1836. *Exit:
  1837. *
  1838. *Exceptions:
  1839. *
  1840. *******************************************************************************/
  1841. void
  1842. ResetConsoleMode( void )
  1843. {
  1844. DWORD dwDesiredOutputMode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
  1845. DWORD dwDesiredInputMode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT;
  1846. SetConsoleMode(CRTTONT(STDOUT), dwCurOutputConMode);
  1847. if (GetConsoleMode(CRTTONT(STDOUT), &dwCurOutputConMode)) {
  1848. if ((dwCurOutputConMode & dwDesiredOutputMode) != dwDesiredOutputMode) {
  1849. dwCurOutputConMode |= dwDesiredOutputMode;
  1850. SetConsoleMode(CRTTONT(STDOUT), dwCurOutputConMode);
  1851. }
  1852. }
  1853. if (GetConsoleMode(CRTTONT(STDIN),&dwCurInputConMode)) {
  1854. if ((dwCurInputConMode & dwDesiredInputMode) != dwDesiredInputMode ||
  1855. dwCurInputConMode & ENABLE_MOUSE_INPUT
  1856. ) {
  1857. dwCurInputConMode &= ~ENABLE_MOUSE_INPUT;
  1858. dwCurInputConMode |= dwDesiredInputMode;
  1859. SetConsoleMode(CRTTONT(STDIN), dwCurInputConMode);
  1860. }
  1861. #ifndef WIN95_CMD
  1862. if (lpSetConsoleInputExeName != NULL)
  1863. (*lpSetConsoleInputExeName)( TEXT("CMD.EXE") );
  1864. #endif
  1865. }
  1866. }
  1867. /***
  1868. *void mytcsnset(string, val, count) - set count characters to val
  1869. *
  1870. *Purpose:
  1871. * Sets the first count characters of string the character value.
  1872. *
  1873. *Entry:
  1874. * tchar_t *string - string to set characters in
  1875. * tchar_t val - character to fill with
  1876. * size_t count - count of characters to fill
  1877. *
  1878. *Exit:
  1879. * returns string, now filled with count copies of val.
  1880. *
  1881. *Exceptions:
  1882. *
  1883. *******************************************************************************/
  1884. void mytcsnset (
  1885. PTCHAR string,
  1886. TCHAR val,
  1887. int count
  1888. )
  1889. {
  1890. while (count--)
  1891. *string++ = val;
  1892. return;
  1893. }