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.

981 lines
24 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. ctools3.c
  5. Abstract:
  6. Low level utilities
  7. --*/
  8. #include "cmd.h"
  9. struct envdata CmdEnv ; /* Holds info need to manipulate Cmd's environment */
  10. extern unsigned tywild; /* type is wild flag @@5@J1 */
  11. extern TCHAR CurDrvDir[], PathChar, Delimiters[] ;
  12. extern TCHAR VolSrch[] ; /* M009 */
  13. extern TCHAR BSlash ;
  14. extern unsigned DosErr ;
  15. /*** FullPath - build a full path name
  16. *
  17. * Purpose:
  18. * See below.
  19. *
  20. * int FullPath(TCHAR * buf, TCHAR *fname)
  21. *
  22. * Args:
  23. * buf - buffer to write full pathname into. (M017)
  24. * fname - a file name and/or partial path
  25. *
  26. * Returns: (M017)
  27. * FAILURE if malformed pathname (erroneous '.' or '..')
  28. * SUCCESS otherwise
  29. *
  30. * Notes:
  31. * - '.' and '..' are removed from the translated string (M017)
  32. * - VERY BIG GOTCHA! Note that the 509 change can cause
  33. * this rountine to modify the input filename (fname), because
  34. * it strips quotes and copies it over the input filename.
  35. *
  36. */
  37. int FullPath(
  38. TCHAR *buf,
  39. TCHAR *fname,
  40. ULONG sizpath
  41. )
  42. {
  43. unsigned rc = SUCCESS; /* prime with good rc */
  44. unsigned buflen; /* buffer length */
  45. TCHAR *filepart;
  46. DWORD rv;
  47. mystrcpy(fname, StripQuotes(fname) );
  48. if (*fname == NULLC) {
  49. GetDir(buf,GD_DEFAULT);
  50. buf += 2; /* Inc past drivespec */
  51. buflen = mystrlen(buf); /* Is curdir root only? */
  52. if (buflen >= MAX_PATH-3) { /* If too big then stop */
  53. DosErr = ERROR_PATH_NOT_FOUND;
  54. rc = FAILURE;
  55. } else if (buflen != 1) { /* if not root then append */
  56. *(buf+buflen++) = PathChar; /* ...a pathchar and... */
  57. *(buf+buflen) = NULLC ; /* ...a null byte... */
  58. } /* */
  59. } else {
  60. if ((mystrlen(fname) == 2) && (*(fname + 1) == COLON)) {
  61. GetDir(buf,*fname); /* Get curdrvdir */
  62. if ((buflen = mystrlen(buf)) > 3) {
  63. *(buf+buflen++) = PathChar; /* ...a pathchar and... */
  64. *(buf+buflen) = NULLC ; /* ...a null byte... */
  65. }
  66. } else {
  67. DWORD dwOldMode;
  68. dwOldMode = SetErrorMode(0);
  69. SetErrorMode(SEM_FAILCRITICALERRORS);
  70. rv = GetFullPathName( fname, sizpath, buf, &filepart );
  71. SetErrorMode(dwOldMode);
  72. if (!rv || rv > sizpath ) {
  73. DosErr = ERROR_FILENAME_EXCED_RANGE;
  74. rc = FAILURE;
  75. }
  76. }
  77. }
  78. return(rc);
  79. }
  80. /*** FileIsDevice - check a handle to see if it references a device
  81. *
  82. * Purpose:
  83. * Return a nonzero value if fh is the file handle for a device.
  84. * Otherwise, return 0.
  85. *
  86. * int FileIsDevice(int fh)
  87. *
  88. * Args:
  89. * fh - the file handle to check
  90. *
  91. * Returns:
  92. * See above.
  93. *
  94. */
  95. unsigned int flgwd;
  96. int FileIsDevice( CRTHANDLE fh )
  97. {
  98. HANDLE hFile;
  99. DWORD dwMode;
  100. unsigned htype ;
  101. hFile = CRTTONT(fh);
  102. htype = GetFileType( hFile );
  103. htype &= ~FILE_TYPE_REMOTE;
  104. if (htype == FILE_TYPE_CHAR) {
  105. //
  106. // Simulate old behavior of this routine of setting the flgwd
  107. // global variable with either 0, 1 or 2 to indicate if the
  108. // passed handle is NOT a CON handle or is a CON input handle or
  109. // is a CON output handle.
  110. //
  111. switch ( fh ) {
  112. case STDIN:
  113. hFile = GetStdHandle(STD_INPUT_HANDLE);
  114. break;
  115. case STDOUT:
  116. hFile = GetStdHandle(STD_OUTPUT_HANDLE);
  117. break;
  118. case STDERR:
  119. hFile = GetStdHandle(STD_ERROR_HANDLE);
  120. break;
  121. }
  122. if (GetConsoleMode(hFile,&dwMode)) {
  123. if (dwMode & (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT)) {
  124. flgwd = 1;
  125. } else if (dwMode & (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT)) {
  126. flgwd = 2;
  127. }
  128. } else {
  129. flgwd = 0;
  130. }
  131. return TRUE;
  132. } else {
  133. flgwd = 0;
  134. return FALSE;
  135. }
  136. }
  137. int FileIsPipe( CRTHANDLE fh )
  138. {
  139. unsigned htype ;
  140. htype = GetFileType( CRTTONT(fh) );
  141. htype &= ~FILE_TYPE_REMOTE;
  142. flgwd = 0;
  143. return( htype == FILE_TYPE_PIPE ) ; /* @@4 */
  144. }
  145. int FileIsRemote( LPTSTR FileName )
  146. {
  147. LPTSTR p;
  148. TCHAR Drive[MAX_PATH*2];
  149. DWORD Length;
  150. Length = GetFullPathName( FileName, sizeof(Drive)/sizeof(TCHAR), Drive, &p );
  151. if (Length != 0 && Length < MAX_PATH * 2) {
  152. Drive[3] = 0;
  153. if (GetDriveType( Drive ) == DRIVE_REMOTE) {
  154. return TRUE;
  155. }
  156. }
  157. return FALSE;
  158. }
  159. int FileIsConsole(CRTHANDLE fh)
  160. {
  161. unsigned htype ;
  162. DWORD dwMode;
  163. HANDLE hFile;
  164. hFile = CRTTONT(fh);
  165. if (hFile == INVALID_HANDLE_VALUE) {
  166. return FALSE;
  167. }
  168. htype = GetFileType( hFile );
  169. htype &= ~FILE_TYPE_REMOTE;
  170. if ( htype == FILE_TYPE_CHAR ) {
  171. switch ( fh ) {
  172. case STDIN:
  173. hFile = GetStdHandle(STD_INPUT_HANDLE);
  174. break;
  175. case STDOUT:
  176. hFile = GetStdHandle(STD_OUTPUT_HANDLE);
  177. break;
  178. case STDERR:
  179. hFile = GetStdHandle(STD_ERROR_HANDLE);
  180. break;
  181. }
  182. if (GetConsoleMode(hFile,&dwMode)) {
  183. return TRUE;
  184. }
  185. }
  186. return FALSE;
  187. }
  188. /*** GetDir - get a current directory string
  189. *
  190. * Purpose:
  191. * Get the current directory of the specified drive and put it in str.
  192. *
  193. * int GetDir(TCHAR *str, TCHAR dlet)
  194. *
  195. * Args:
  196. * str - place to store the directory string
  197. * dlet - the drive letter or 0 for the default drive
  198. *
  199. * Returns:
  200. * 0 or 1 depending on the value of the carry flag after the CURRENTDIR
  201. * system call/
  202. *
  203. * Notes:
  204. * - M024 - If dlet is invalid, we leave the buffer as simply the
  205. * null terminated root directory string.
  206. *
  207. */
  208. int GetDir(TCHAR *str, TCHAR dlet)
  209. {
  210. TCHAR denvname[ 4 ];
  211. TCHAR *denvvalue;
  212. if (dlet == GD_DEFAULT) {
  213. GetCurrentDirectory(MAX_PATH, str);
  214. return( SUCCESS );
  215. }
  216. denvname[ 0 ] = EQ;
  217. denvname[ 1 ] = (TCHAR)_totupper(dlet);
  218. denvname[ 2 ] = COLON;
  219. denvname[ 3 ] = NULLC;
  220. denvvalue = GetEnvVar( denvname );
  221. if (!denvvalue) {
  222. *str++ = (TCHAR)_totupper(dlet);
  223. *str++ = COLON;
  224. *str++ = BSLASH;
  225. *str = NULLC;
  226. return(FAILURE);
  227. } else {
  228. mystrcpy( str, denvvalue );
  229. return(SUCCESS);
  230. }
  231. }
  232. BOOL
  233. FixupPath(
  234. TCHAR *path,
  235. BOOL fShortNames
  236. )
  237. {
  238. TCHAR c, *src, *dst, *s;
  239. int n, n1, length;
  240. WIN32_FIND_DATA FindFileData;
  241. HANDLE hFind;
  242. length = _tcslen( path );
  243. if (length > MAX_PATH) {
  244. return FALSE;
  245. }
  246. src = path + 3; // Skip root directory.
  247. dst = path + 3;
  248. do {
  249. c = *src;
  250. if (!c || c == PathChar) {
  251. *src = NULLC;
  252. hFind = FindFirstFile( path, &FindFileData );
  253. *src = c;
  254. if (hFind != INVALID_HANDLE_VALUE) {
  255. FindClose( hFind );
  256. if (FindFileData.cAlternateFileName[0] &&
  257. (fShortNames ||
  258. (!_tcsnicmp( FindFileData.cAlternateFileName, dst, (UINT)(src - dst)) &&
  259. _tcsicmp( FindFileData.cFileName, FindFileData.cAlternateFileName)
  260. )
  261. )
  262. )
  263. //
  264. // Use short name if requested or
  265. // if input is explicitly using it and short name differs from long name
  266. //
  267. s = FindFileData.cAlternateFileName;
  268. else
  269. s = FindFileData.cFileName;
  270. n = _tcslen( s );
  271. n1 = n - (int)(src - dst);
  272. //
  273. // Make sure we don't overflow name
  274. //
  275. if (length + n1 > MAX_PATH) {
  276. return FALSE;
  277. } else {
  278. length += n1;
  279. }
  280. if (n1 > 0) {
  281. memmove( src+n1, src, _tcslen(src)*sizeof(TCHAR) );
  282. src += n1;
  283. }
  284. _tcsncpy( dst, s, n );
  285. dst += n;
  286. _tcscpy( dst, src );
  287. dst += 1;
  288. src = dst;
  289. } else {
  290. src += 1;
  291. dst = src;
  292. }
  293. }
  294. src += 1;
  295. }
  296. while (c != NULLC);
  297. return TRUE;
  298. }
  299. /*** ChangeDirectory - change a current directory
  300. *
  301. * Purpose:
  302. * Change the current directory on a drive. We do this either
  303. * via changing the associated environment variable, or
  304. * by changing the Win32 drive and directory.
  305. *
  306. * Args:
  307. * newdir - directory (optionally w/drive)
  308. * op - what operation should be performed
  309. * CD_SET_DRIVE_DIRECTORY - set the Win32 current directory and drive
  310. * CD_SET_DIRECTORY - set the Win32 current directory if the same drive
  311. * CD_SET_ENV - set the environment variables for the current directory
  312. * on a drive that's not the default drive.
  313. *
  314. * Returns:
  315. * SUCCESS if the directory was changed.
  316. * FAILURE otherwise.
  317. */
  318. int ChangeDirectory(
  319. TCHAR *newdir,
  320. CHANGE_OP op
  321. )
  322. {
  323. TCHAR denvname[ 4 ];
  324. TCHAR newpath[ MAX_PATH + MAX_PATH ];
  325. TCHAR denvvalue[ MAX_PATH ];
  326. TCHAR c, *s;
  327. DWORD attr;
  328. DWORD newdirlength,length;
  329. //
  330. // UNC paths are not allowed
  331. //
  332. if (newdir[0] == PathChar && newdir[1] == PathChar)
  333. return MSG_NO_UNC_CURDIR;
  334. //
  335. // truncate trailing spaces on ..
  336. //
  337. if (newdir[0] == DOT && newdir[1] == DOT) {
  338. DWORD i, fNonBlank;
  339. fNonBlank = 0;
  340. newdirlength = mystrlen(newdir);
  341. for (i=2; i<newdirlength; i++) {
  342. if (newdir[i] != SPACE) {
  343. fNonBlank = 1;
  344. break;
  345. }
  346. }
  347. if ( ! fNonBlank) {
  348. newdir[2] = NULLC;
  349. }
  350. }
  351. //
  352. // Get current drive and directory in order to
  353. // set up for forming the environment variable
  354. //
  355. GetCurrentDirectory( MAX_PATH, denvvalue );
  356. c = (TCHAR)_totupper( denvvalue[ 0 ] );
  357. //
  358. // Convention for environment form is:
  359. // Name of variable =d:
  360. // value is full path including drive
  361. //
  362. denvname[ 0 ] = EQ;
  363. if (_istalpha(*newdir) && newdir[1] == COLON) {
  364. denvname[ 1 ] = (TCHAR)_totupper(*newdir);
  365. newdir += 2;
  366. } else {
  367. denvname[ 1 ] = c;
  368. }
  369. denvname[ 2 ] = COLON;
  370. denvname[ 3 ] = NULLC;
  371. newdirlength = mystrlen(newdir);
  372. if (*newdir == PathChar) {
  373. if ((newdirlength+2) > sizeof(newpath)/sizeof( TCHAR )) {
  374. return ERROR_FILENAME_EXCED_RANGE;
  375. }
  376. newpath[ 0 ] = denvname[ 1 ]; // drive
  377. newpath[ 1 ] = denvname[ 2 ]; // colon
  378. mystrcpy( &newpath[ 2 ], newdir );
  379. } else {
  380. if (s = GetEnvVar( denvname )) {
  381. mystrcpy( newpath, s );
  382. } else {
  383. newpath[ 0 ] = denvname[ 1 ]; // drive
  384. newpath[ 1 ] = denvname[ 2 ]; // colon
  385. newpath[ 2 ] = NULLC;
  386. }
  387. //
  388. // Make sure there's exactly one backslash between newpath and newdir
  389. //
  390. s = lastc( newpath );
  391. //
  392. // s points to the last character or point to NUL (if newpath was
  393. // zero length to begin with). A NULL means we drop in a path char
  394. // over the NUL. A non-path char means we append a path char.
  395. //
  396. if (*s == NULLC) {
  397. *s++ = PathChar;
  398. } else if (*s != PathChar) {
  399. s[1] = PathChar;
  400. s += 2;
  401. }
  402. if (newdirlength + (s - newpath) > sizeof( newpath ) / sizeof( TCHAR )) {
  403. return ERROR_FILENAME_EXCED_RANGE;
  404. }
  405. mystrcpy( s, newdir );
  406. }
  407. denvvalue[(sizeof( denvvalue )-1)/sizeof( TCHAR )] = NULLC;
  408. //
  409. // form the full path name
  410. //
  411. if ((length = GetFullPathName( newpath, (sizeof( denvvalue )-1)/sizeof( TCHAR ), denvvalue, &s ))==0) {
  412. return( ERROR_ACCESS_DENIED );
  413. }
  414. //
  415. // Remove any trailing backslash
  416. //
  417. if (s == NULL) {
  418. s = denvvalue + _tcslen( denvvalue );
  419. }
  420. if (*s == NULLC && s > &denvvalue[ 3 ] && s[ -1 ] == PathChar) {
  421. *--s = NULLC;
  422. }
  423. //
  424. // Verify that there won't be (initially) disk errors when we touch
  425. // the directory
  426. //
  427. attr = GetFileAttributes( denvvalue );
  428. if (attr == -1) {
  429. attr = GetLastError( );
  430. if (attr != ERROR_FILE_NOT_FOUND &&
  431. attr != ERROR_PATH_NOT_FOUND &&
  432. attr != ERROR_INVALID_NAME) {
  433. return attr;
  434. }
  435. }
  436. //
  437. // If extensions are enabled, fixup the path to have the same case as
  438. // on disk
  439. //
  440. if (fEnableExtensions) {
  441. if (!FixupPath( denvvalue, FALSE )) {
  442. return ERROR_FILENAME_EXCED_RANGE;
  443. }
  444. }
  445. if (op != CD_SET_ENV) {
  446. attr = GetFileAttributes( denvvalue );
  447. if (attr == (DWORD)-1 ||
  448. !(attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT))
  449. ) {
  450. if ( attr == -1 ) {
  451. attr = GetLastError();
  452. if ( attr == ERROR_FILE_NOT_FOUND ) {
  453. attr = ERROR_PATH_NOT_FOUND;
  454. }
  455. return attr;
  456. }
  457. return( ERROR_DIRECTORY );
  458. }
  459. }
  460. //
  461. // If we're always setting the directory or
  462. // if we're setting the directory if the drives are the same and
  463. // the drives ARE the same
  464. //
  465. if (op == CD_SET_DRIVE_DIRECTORY
  466. || (op == CD_SET_DIRECTORY
  467. && c == denvname[ 1 ])) {
  468. if (!SetCurrentDirectory( denvvalue )) {
  469. return GetLastError();
  470. }
  471. }
  472. if (SetEnvVar(denvname,denvvalue,&CmdEnv)) {
  473. return( ERROR_NOT_ENOUGH_MEMORY );
  474. }
  475. GetDir(CurDrvDir, GD_DEFAULT) ;
  476. return SUCCESS;
  477. }
  478. /*** ChangeDir2 - change a current directory
  479. *
  480. * Purpose:
  481. * To change to the directory specified in newdir on the drive specified
  482. * in newdir. If no drive is given, the default drive is used. If the
  483. * directory of the current drive is changed, the global variable
  484. * CurDrvDir is updated.
  485. *
  486. * This routine is used by RestoreCurrentDirectories
  487. *
  488. * int ChangeDir2(BYTE *newdir, BOOL )
  489. *
  490. * Args:
  491. * newdir - directory to change to
  492. * BOOL - current drive
  493. *
  494. * Returns:
  495. * SUCCESS if the directory was changed.
  496. * FAILURE otherwise.
  497. *
  498. */
  499. int ChangeDir2(
  500. TCHAR *newdir,
  501. BOOL CurrentDrive
  502. )
  503. {
  504. return ChangeDirectory( newdir, CurrentDrive ? CD_SET_DRIVE_DIRECTORY : CD_SET_ENV );
  505. }
  506. /*** ChangeDir - change a current directory
  507. *
  508. * Purpose:
  509. * To change to the directory specified in newdir on the drive specified
  510. * in newdir. If no drive is given, the default drive is used. If the
  511. * directory of the current drive is changed, the global variable
  512. * CurDrvDir is updated.
  513. *
  514. * int ChangeDir(TCHAR *newdir)
  515. *
  516. * Args:
  517. * newdir - directory to change to
  518. *
  519. * Returns:
  520. * SUCCESS if the directory was changed.
  521. * FAILURE otherwise.
  522. *
  523. */
  524. int ChangeDir(
  525. TCHAR *newdir
  526. )
  527. {
  528. return ChangeDirectory( newdir, CD_SET_DIRECTORY );
  529. }
  530. /*** exists - Determine if a given file exists
  531. *
  532. * Purpose:
  533. * To test the existence of a named file.
  534. *
  535. * int exists(TCHAR *filename)
  536. *
  537. * Args:
  538. * filename - the filespec to test
  539. *
  540. * Returns:
  541. * TRUE if file exists
  542. * FALSE if it does not.
  543. *
  544. * Notes:
  545. * M020 - Now uses ffirst to catch devices, directories and wildcards.
  546. */
  547. exists(filename)
  548. TCHAR *filename;
  549. {
  550. WIN32_FIND_DATA buf ; /* Use for ffirst/fnext */
  551. HANDLE hn ;
  552. int i ; /* tmp */
  553. TCHAR FullPath[ 2 * MAX_PATH ];
  554. TCHAR *p, *p1, SaveChar;
  555. p = StripQuotes(filename);
  556. i = GetFullPathName( p, 2 * MAX_PATH, FullPath, &p1 );
  557. if (i) {
  558. p = FullPath;
  559. if (!_tcsncmp( p, TEXT("\\\\.\\"), 4 )) {
  560. //
  561. // If they gave us a device name, then see if they put something
  562. // in front of it.
  563. //
  564. p += 4;
  565. p1 = p;
  566. if ((p1 = _tcsstr( filename, p )) && p1 > filename) {
  567. //
  568. // Something in front of the device name, so truncate the input
  569. // path at the device name and see if that exists.
  570. //
  571. SaveChar = *p1;
  572. *p1 = NULLC;
  573. i = (int)GetFileAttributes( filename );
  574. *p1 = SaveChar;
  575. if (i != 0xFFFFFFFF) {
  576. return i;
  577. } else {
  578. return 0;
  579. }
  580. } else {
  581. //
  582. // Just a device name given. See if it is valid.
  583. //
  584. i = (int)GetFileAttributes( filename );
  585. if (i != 0xFFFFFFFF) {
  586. return i;
  587. } else {
  588. return 0;
  589. }
  590. }
  591. }
  592. if (p1 == NULL || *p1 == NULLC) {
  593. i = (int)(GetFileAttributes( p ) != 0xFFFFFFFF);
  594. } else {
  595. i = ffirst( p, A_ALL, &buf, &hn );
  596. findclose(hn);
  597. if ( i == 0 ) {
  598. //
  599. // ffirst handles files & directories, but not
  600. // root drives, so do special check for them.
  601. //
  602. if ( *(p+1) == (TCHAR)'\\' ||
  603. (*(p+1) == (TCHAR)':' &&
  604. *(p+2) == (TCHAR)'\\' &&
  605. *(p+3) == (TCHAR)0
  606. )
  607. ) {
  608. UINT t;
  609. t = GetDriveType( p );
  610. if ( t > 1 ) {
  611. i = 1;
  612. }
  613. }
  614. }
  615. }
  616. }
  617. return i;
  618. }
  619. /*** exists_ex - Determine if a given executable file exists @@4
  620. *
  621. * Purpose:
  622. * To test the existence of a named executable file.
  623. *
  624. * int exists_ex(TCHAR *filename)
  625. *
  626. * Args:
  627. * filename - the filespec to test
  628. * checkformeta - if TRUE, check for wildcard char
  629. *
  630. * Returns:
  631. * TRUE if file exists
  632. * FALSE if it does not.
  633. *
  634. * Notes:
  635. * @@4 - Now uses ffirst to catch only files .
  636. */
  637. exists_ex(filename,checkformeta) /*@@4*/
  638. TCHAR *filename; /*@@4*/
  639. BOOL checkformeta;
  640. { /*@@4*/
  641. WIN32_FIND_DATA buf; /* use for ffirst/fnext */
  642. HANDLE hn;
  643. int i;
  644. TCHAR *ptr;
  645. /* can not execute wild card files, so check for those first */
  646. if (checkformeta && (mystrchr( filename, STAR ) || mystrchr( filename, QMARK ))) {
  647. DosErr = 3;
  648. i = 0;
  649. } else {
  650. /* see if the file exists, do not include Directory, volume, or */
  651. /* hidden files */
  652. i = ((ffirst( filename , A_AEDV, &buf, &hn))) ;
  653. if ( i ) {
  654. findclose(hn) ;
  655. /* if the file exists then copy the file name, to get the case */
  656. ptr = mystrrchr( filename, BSLASH );
  657. if ( ptr == NULL ) {
  658. ptr = filename;
  659. if ( mystrlen( ptr ) > 2 && ptr[1] == COLON ) {
  660. ptr = &filename[2];
  661. }
  662. } else {
  663. ptr++;
  664. }
  665. mystrcpy( ptr, buf.cFileName);
  666. } else if ( DosErr == 18 ) {
  667. DosErr = 2;
  668. }
  669. }
  670. return(i) ; /*@@4*/
  671. } /*@@4*/
  672. /*** FixPChar - Fix up any leading path in a string
  673. *
  674. * Purpose:
  675. * To insure that paths match the current Swit/Pathchar setting
  676. *
  677. * void FixPChar(TCHAR *str, TCHAR PChar)
  678. *
  679. * Args:
  680. * str - the string to fixup
  681. * Pchar - character to replace
  682. *
  683. * Returns:
  684. * Nothing
  685. *
  686. */
  687. void FixPChar(TCHAR *str, TCHAR PChar)
  688. {
  689. TCHAR *sptr1, /* Index for string */
  690. *sptr2 ; /* Change marker */
  691. sptr1 = str ; /* Init to start of string */
  692. while (sptr2 = mystrchr(sptr1,PChar)) {
  693. *sptr2++ = PathChar ;
  694. sptr1 = sptr2 ;
  695. } ;
  696. }
  697. /*** FlushKB - Remove extra unwanted input from Keyboard
  698. *
  699. * Purpose:
  700. * To perform a keyboard flush up to the next CR/LF.
  701. *
  702. * FlushKB()
  703. *
  704. * Args:
  705. * None
  706. *
  707. * Returns:
  708. * Nothing
  709. *
  710. */
  711. void FlushKB()
  712. {
  713. DWORD cnt;
  714. TCHAR IgnoreBuffer[128];
  715. while (ReadBufFromInput( GetStdHandle(STD_INPUT_HANDLE), IgnoreBuffer, 128, &cnt )) {
  716. if (mystrchr( IgnoreBuffer, CR ))
  717. return ;
  718. }
  719. }
  720. /*** DriveIsFixed - Determine if drive is removeable media
  721. *
  722. * Purpose: @@4
  723. * To determine if the input drive is a removeable media.
  724. *
  725. * DriveIsFixed(TCHAR *drive_ptr )
  726. *
  727. * Args:
  728. * drive_ptr - pointer to a file name that contains a drive
  729. * specification.
  730. *
  731. * Returns:
  732. * 1 - if error or non removeable media
  733. * 0 - if no error and removeable media
  734. */
  735. int
  736. DriveIsFixed( TCHAR *drive_ptr )
  737. {
  738. unsigned rc = 0;
  739. TCHAR drive_spec[3];
  740. drive_spec[0] = *drive_ptr;
  741. drive_spec[1] = COLON;
  742. drive_spec[2] = NULLC;
  743. // FIX, FIX - use GetVolumeInfo, disabling hard errors?
  744. if ((*drive_ptr == TEXT('A')) || (*drive_ptr == TEXT('B'))) {
  745. rc = 0;
  746. } else {
  747. rc = 1;
  748. }
  749. return( rc );
  750. }
  751. int
  752. CmdPutChars(
  753. PTCHAR String,
  754. int Length
  755. )
  756. {
  757. int rc = SUCCESS; /* return code */
  758. int bytesread; /* bytes to write count */
  759. int byteswrit; /* bytes written count */
  760. BOOL flag;
  761. if (Length > 0) {
  762. if (FileIsConsole(STDOUT)) {
  763. if (!(flag=WriteConsole(CRTTONT(STDOUT), String, Length, &byteswrit, NULL)))
  764. rc = GetLastError();
  765. } else {
  766. Length *= sizeof(TCHAR);
  767. flag = MyWriteFile( STDOUT, (CHAR *)String, Length, &byteswrit);
  768. }
  769. //
  770. // If the write failed or unable to output all the data
  771. //
  772. if (flag == 0 || byteswrit != Length) {
  773. rc = GetLastError();
  774. //
  775. // No error => DiskFull
  776. //
  777. if (rc == 0) {
  778. rc = ERROR_DISK_FULL;
  779. }
  780. if (FileIsDevice(STDOUT)) {
  781. //
  782. // If the we were writing to a device then the error is a device
  783. // write fault.
  784. //
  785. PutStdErr( ERROR_WRITE_FAULT, NOARGS );
  786. } else if (FileIsPipe(STDOUT)) {
  787. //
  788. // If the we were writing to a pipe, then the error is an invalid
  789. // pipe error.
  790. //
  791. PutStdErr(MSG_CMD_INVAL_PIPE, NOARGS);
  792. return(FAILURE);
  793. } else {
  794. //
  795. // Just output the error we found
  796. //
  797. PrtErr(rc);
  798. return(FAILURE);
  799. }
  800. }
  801. }
  802. return(rc);
  803. }
  804. int
  805. CmdPutString(
  806. PTCHAR String
  807. )
  808. {
  809. return CmdPutChars( String, _tcslen( String ));
  810. }
  811. int
  812. cmd_printf(
  813. TCHAR *fmt,
  814. ...
  815. )
  816. {
  817. int Length;
  818. va_list arg_ptr;
  819. va_start(arg_ptr,fmt);
  820. Length = _vsntprintf( MsgBuf, MAXCBMSGBUFFER, fmt, arg_ptr );
  821. va_end(arg_ptr);
  822. return CmdPutChars( MsgBuf, Length );
  823. }