Windows NT 4.0 source code leak
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.

2181 lines
65 KiB

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