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.

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