Windows-Server-2003/base/cmd/ctools2.c

2285 lines
66 KiB
C

/*++
Copyright (c) 1988-1999 Microsoft Corporation
Module Name:
ctools2.c
Abstract:
Low level utilities
--*/
#include "cmd.h"
#pragma hdrstop
#include "ctable.h"
#define MSG_USE_DEFAULT -1 /* M031 */
extern TCHAR PathChar ;
extern TCHAR CurDrvDir[] ;
#define DAYLENGTH 3
extern TCHAR Delimiters[] ;
extern TCHAR SwitChar ;
extern int Ctrlc;
//
// flag if control-c was seen
//
extern BOOL CtrlCSeen;
extern int ExtCtrlc; /* @@4 */
extern TCHAR Fmt19[];
extern unsigned flgwd ;
unsigned int DosErr = 0 ;
unsigned long OHTbl[3] = {0,0,0} ;
extern BOOLEAN fPrintCtrlC;
unsigned int cbTitleCurPrefix;
extern BOOLEAN fTitleChanged;
//
// Used to set and reset ctlcseen flag
//
VOID SetCtrlC();
VOID ResetCtrlC();
//
// console mode at program startup time. Used to reset mode
// after running another process.
//
extern DWORD dwCurInputConMode;
extern DWORD dwCurOutputConMode;
struct msentry { /* M027 */
unsigned errnum ;
unsigned msnum ;
} ;
struct msentry mstabl[] = {
{(unsigned)ERROR_INVALID_FUNCTION, (unsigned)MSG_USE_DEFAULT}, /* 1 */
{ERROR_FILE_NOT_FOUND, ERROR_FILE_NOT_FOUND}, /* 2 */
{ERROR_PATH_NOT_FOUND, ERROR_PATH_NOT_FOUND}, /* 3 */
{ERROR_TOO_MANY_OPEN_FILES, ERROR_TOO_MANY_OPEN_FILES}, /* 4 */
{ERROR_ACCESS_DENIED, ERROR_ACCESS_DENIED}, /* 5 */
{ERROR_INVALID_HANDLE, ERROR_INVALID_HANDLE}, /* 6 */
{ERROR_NOT_ENOUGH_MEMORY, ERROR_NOT_ENOUGH_MEMORY}, /* 8 */
{(unsigned)ERROR_INVALID_ACCESS, (unsigned)MSG_USE_DEFAULT}, /* 12 */
{ERROR_NO_MORE_FILES, ERROR_FILE_NOT_FOUND}, /* 18 */
{ERROR_SECTOR_NOT_FOUND, ERROR_SECTOR_NOT_FOUND}, /* 27 */
{ERROR_SHARING_VIOLATION, ERROR_SHARING_VIOLATION}, /* 32 */
{ERROR_LOCK_VIOLATION, ERROR_LOCK_VIOLATION}, /* 33 */
{ERROR_FILE_EXISTS, ERROR_FILE_EXISTS}, /* 80 */
{ERROR_CANNOT_MAKE, ERROR_CANNOT_MAKE}, /* 82 */
{(unsigned)ERROR_INVALID_PARAMETER, (unsigned)MSG_USE_DEFAULT}, /* 87 */
{ERROR_OPEN_FAILED, ERROR_OPEN_FAILED}, /* 110 */
{ERROR_DISK_FULL, ERROR_DISK_FULL}, /* 112 */
{0,0} /* End of Table */
} ;
/*** OnOffCheck - check an argument string for "ON" or "OFF"
*
* Purpose:
* To check str for the word "ON" or the word "OFF". If flag is nonzero,
* an error message will be printed if str contains anything other than
* just "ON", "OFF", or an empty string.
*
* int OnOffCheck(TCHAR *str, int flag)
*
* Args:
* str - the string to check
* flag - nonzero if error checking is to be done
*
* Returns:
* OOC_EMPTY if str was empty.
* OOC_ON if just "ON" was found.
* OOC_OFF if just "OFF" was found.
* OOC_OTHER if anything else was found.
*
*/
int OnOffCheck( TCHAR *str, int flag )
{
TCHAR *tas ; /* Tokenized arg string */
int retval = OOC_OTHER ; /* Return value */
TCHAR SavedChar;
if (str == NULL) {
return OOC_EMPTY;
}
//
// Ignore leading spaces
//
tas = str = SkipWhiteSpace( str );
if (*tas == NULLC) {
return OOC_EMPTY;
}
//
// Find end of first non-blank token
//
while (*tas && !_istspace(*tas))
tas += 1;
//
// If there's another token beyond the first token
// then we can't have ON/OFF
//
if (*SkipWhiteSpace( tas ) != NULLC) {
return retval;
}
SavedChar = *tas;
*tas = NULLC;
if (_tcsicmp( str, TEXT( "on" )) == 0) /* M015 */
retval = OOC_ON ;
else if (_tcsicmp(str,TEXT( "off" )) == 0) /* M015 */
retval = OOC_OFF ;
*tas = SavedChar;
if (retval == OOC_OTHER && flag == OOC_ERROR)
PutStdErr(MSG_BAD_PARM1, NOARGS);
return(retval) ;
}
/*** ChangeDrive - change Command's current drive
*
* Purpose:
* To change Command's default drive.
*
* ChangeDrive(int drvnum)
*
* Args:
* drvnum - the drive number to change to (M010 - 1 == A, etc.)
*
*/
void ChangeDrive(drvnum)
int drvnum ;
{
TCHAR denvname[ 4 ];
TCHAR denvvalue[ MAX_PATH ];
TCHAR *s;
BOOLEAN fSet;
UINT OldErrorMode;
denvname[ 0 ] = EQ;
denvname[ 1 ] = (TEXT('A') + (drvnum-1));
denvname[ 2 ] = COLON;
denvname[ 3 ] = NULLC;
fSet = FALSE;
s = NULL;
if (s = GetEnvVar( denvname )) {
fSet = (BOOLEAN)SetCurrentDirectory( s );
}
//
// if the drive was not at current position then
// reset. If it was a mapped drive then it may have
// been disconnected and then reconnected and so
// we should reset to root.
//
if (!fSet) {
//
// In the case where the drive letter was not in the environment
// ans so did not do the first SetCurrentDirectory then do not
// turn off error pop-up
//
if (s != NULL) {
OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
}
denvvalue[ 0 ] = denvname[ 1 ];
denvvalue[ 1 ] = denvname[ 2 ];
denvvalue[ 2 ] = PathChar;
denvvalue[ 3 ] = NULLC;
SetEnvVar(denvname,denvvalue );
if (!SetCurrentDirectory( denvvalue )) {
//
// Could not set the drive at all give an error
//
PutStdErr( GetLastError( ), NOARGS );
}
if (s != NULL) {
SetErrorMode( OldErrorMode );
}
}
GetDir(CurDrvDir, GD_DEFAULT) ;
}
/*** PutStdOut - Print a message to STDOUT
*
* Purpose:
* Calls PutMsg sending STDOUT as the handle to which the message
* will be written.
*
* int PutStdOut(unsigned MsgNum, unsigned NumOfArgs, ...)
*
* Args:
* MsgNum - the number of the message to print
* NumOfArgs - the number of total arguments
* ... - the additional arguments for the message
*
* Returns:
* Return value from PutMsg() M026
*
*/
PutStdOut(unsigned int MsgNum, unsigned int NumOfArgs, ...)
{
int Result;
va_list arglist;
va_start(arglist, NumOfArgs);
Result = PutMsg(MsgNum, STDOUT, NumOfArgs, &arglist);
va_end(arglist);
return Result;
}
/*** PutStdErr - Print a message to STDERR
*
* Purpose:
* Calls PutMsg sending STDERR as the handle to which the message
* will be written.
*
* int PutStdErr(unsigned MsgNum, unsigned NumOfArgs, ...)
*
* Args:
* MsgNum - the number of the message to print
* NumOfArgs - the number of total arguments
* ... - the additonal arguments for the message
*
* Returns:
* Return value from PutMsg() M026
*
*/
int
PutStdErr(unsigned int MsgNum, unsigned int NumOfArgs, ...)
{
int Result;
va_list arglist;
va_start(arglist, NumOfArgs);
Result = PutMsg(MsgNum, STDERR, NumOfArgs, &arglist);
va_end(arglist);
return Result;
}
int
FindMsg(unsigned MsgNum, PTCHAR NullArg, unsigned NumOfArgs, va_list *arglist)
{
unsigned msglen;
TCHAR *Inserts[ 2 ];
CHAR numbuf[ 32 ];
#ifdef UNICODE
TCHAR wnumbuf[ 32 ];
#endif
#if DBG
int error;
#endif
//
// find message without doing argument substitution
//
if (MsgNum == ERROR_MR_MID_NOT_FOUND) {
msglen = 0;
} else {
msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
MsgNum,
0,
MsgBuf,
sizeof(MsgBuf) / sizeof(TCHAR),
NULL
);
}
if (msglen == 0) {
#if DBG
error = GetLastError();
DEBUG((CTGRP, COLVL, "FindMsg: FormatMessage #2 error %d",error)) ;
#endif
//
// didn't find message
//
_ultoa( MsgNum, numbuf, 16 );
#ifdef UNICODE
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, numbuf, -1, wnumbuf, 32);
Inserts[ 0 ]= wnumbuf;
#else
Inserts[ 0 ]= numbuf;
#endif
Inserts[ 1 ]= (MsgNum >= MSG_FIRST_CMD_MSG_ID ?
TEXT("Application") : TEXT("System"));
MsgNum = ERROR_MR_MID_NOT_FOUND;
msglen = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
MsgNum,
0,
MsgBuf,
sizeof(MsgBuf) / sizeof(TCHAR),
(va_list *)Inserts
);
#if DBG
if (msglen == 0) {
error = GetLastError();
DEBUG((CTGRP, COLVL, "FindMsg: FormatMessage #3 error %d",error)) ;
}
#endif
} else {
// see how many arguments are expected and make sure we have enough
PTCHAR tmp;
ULONG count;
tmp=MsgBuf;
count = 0;
while (tmp = mystrchr(tmp, PERCENT)) {
tmp++;
if (*tmp >= TEXT('1') && *tmp <= TEXT('9')) {
count += 1;
} else if (*tmp == PERCENT) {
tmp++;
}
}
if (count > NumOfArgs) {
PTCHAR *LocalArgList;
ULONG i;
LocalArgList = (PTCHAR*)HeapAlloc(GetProcessHeap(), 0, sizeof(PTCHAR) * count);
if (LocalArgList == NULL) {
return 0;
}
for (i=0; i<count; i++) {
if (i < NumOfArgs) {
LocalArgList[i] = (PTCHAR)va_arg( *arglist, UINT_PTR );
} else {
LocalArgList[i] = NullArg;
}
}
msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
MsgNum,
0,
MsgBuf,
sizeof(MsgBuf) / sizeof(TCHAR),
(va_list *)LocalArgList
);
HeapFree(GetProcessHeap(), 0, LocalArgList);
} else {
msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_FROM_SYSTEM ,
NULL,
MsgNum,
0,
MsgBuf,
sizeof(MsgBuf) / sizeof(TCHAR),
arglist
);
}
#if DBG
if (msglen == 0) {
error = GetLastError();
DEBUG((CTGRP, COLVL, "FindMsg: FormatMessage error %d",error)) ;
}
#endif
}
return msglen;
}
BOOLEAN fHelpPauseEnabled;
DWORD crowCur;
PTCHAR PauseMsg;
DWORD PauseMsgLen;
void
BeginHelpPause( void )
{
fHelpPauseEnabled = TRUE;
crowCur = 0;
PauseMsgLen = FindMsg(MSG_STRIKE_ANY_KEY, TEXT(" "), NOARGS, NULL);
PauseMsg = gmkstr((PauseMsgLen+2) * sizeof(TCHAR));
_tcscpy(PauseMsg, MsgBuf);
_tcscat(PauseMsg, TEXT("\r"));
return;
}
void
EndHelpPause( void )
{
fHelpPauseEnabled = FALSE;
crowCur = 0;
return;
}
/*** PutMsg - Print a message to a handle
*
* Purpose:
* PutMsg is the work routine which interfaces command.com with the
* DOS message retriever. This routine is called by PutStdOut and
* PutStdErr.
*
* int PutMsg(unsigned MsgNum, unsigned Handle, unsigned NumOfArgs, ...)
*
* Args:
* MsgNum - the number of the message to print
* NumOfArgs - the number of total arguments
* Handle - the handle to print to
* Arg1 [Arg2...] - the additonal arguments for the message
*
* Returns:
* Return value from DOSPUTMESSAGE M026
*
* Notes:
* - PutMsg builds an argument table which is passed to DOSGETMESSAGE;
* this table contains the variable information which the DOS routine
* inserts into the message.
* - If more than one Arg is sent into PutMsg, it (or they) are taken
* from the stack in the first for loop.
* - M020 MsgBuf is a static array of 2K length. It is temporary and
* will be replaced by a more efficient method when decided upon.
*
*/
DWORD GetCursorDiff(CONSOLE_SCREEN_BUFFER_INFO* ConInfo, CONSOLE_SCREEN_BUFFER_INFO* ConCurrentInfo)
{
return(DWORD)ConCurrentInfo->dwSize.X * ConCurrentInfo->dwCursorPosition.Y + ConCurrentInfo->dwCursorPosition.X -
(DWORD)ConInfo->dwSize.X * ConInfo->dwCursorPosition.Y + ConInfo->dwCursorPosition.X;
}
int
PutMsg(unsigned int MsgNum, CRTHANDLE Handle, unsigned int NumOfArgs, va_list *arglist)
{
unsigned msglen,writelen;
unsigned rc;
TCHAR c;
PTCHAR msgptr, s, sEnd;
PTCHAR NullArg = TEXT(" ");
DWORD cb;
HANDLE hConsole;
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
DWORD crowMax, dwMode;
if (FileIsConsole(Handle)) {
hConsole = CRTTONT(Handle);
if (!GetConsoleScreenBufferInfo(hConsole, &ConInfo)) {
hConsole = NULL;
} else {
crowMax = ConInfo.srWindow.Bottom - ConInfo.srWindow.Top - 1;
}
} else {
hConsole = NULL;
}
rc = 0; /* live with */
msglen = FindMsg(MsgNum,NullArg,NumOfArgs,arglist);
msgptr = MsgBuf;
writelen = msglen;
for (msgptr=MsgBuf ; msglen!=0 ; msgptr+=writelen,msglen-=writelen) {
if (hConsole != NULL) {
if (fHelpPauseEnabled) {
if (crowCur >= crowMax) {
crowCur = 0;
if (GetConsoleScreenBufferInfo(hConsole, &ConInfo)) {
if (WriteConsole(hConsole, PauseMsg, PauseMsgLen, &rc, NULL)) {
CONSOLE_SCREEN_BUFFER_INFO ConCurrentInfo;
FlushConsoleInputBuffer( GetStdHandle(STD_INPUT_HANDLE) );
GetConsoleMode(hConsole, &dwMode);
SetConsoleMode(hConsole, 0);
c = (TCHAR)_getch();
SetConsoleMode(hConsole, dwMode);
GetConsoleScreenBufferInfo(hConsole, &ConCurrentInfo);
//
// Clear the pause message
//
FillConsoleOutputCharacter(hConsole,
TEXT(' '),
GetCursorDiff(&ConInfo, &ConCurrentInfo),
ConInfo.dwCursorPosition,
&rc
);
SetConsoleCursorPosition(hConsole, ConInfo.dwCursorPosition);
if (c == 0x3) {
SetCtrlC();
return NO_ERROR;
}
}
}
}
s = msgptr;
sEnd = s + msglen;
while (s < sEnd && crowCur < crowMax) {
if (*s++ == TEXT('\n'))
crowCur += 1;
}
writelen = (UINT)(s - msgptr);
} else {
//
// write a maximum of MAXTOWRITE chars at a time so ctrl-s works
//
writelen = min(MAXTOWRITE,msglen);
}
if (!WriteConsole(hConsole, msgptr, writelen, &rc, NULL)) {
rc = GetLastError();
} else {
rc = 0;
continue;
}
} else
if (MyWriteFile(Handle, msgptr, writelen*sizeof(TCHAR), &cb) == 0 ||
cb != writelen*sizeof(TCHAR)
) {
rc = GetLastError();
break;
} else {
rc = 0;
}
}
//
// If the writefile failed, we need to see what else is at work here. If
// we're trying to write to stderr and we can't, we simply exit. After all,
// we can't even put out a message saying why we failed.
//
if ( rc && Handle == STDERR ) {
CMDexit( FAILURE );
}
return rc;
}
/*** argstr1 - Create formatted message in memory
*
* Purpose:
* Uses sprintf to create a formatted text string in memory to
* use in message output.
*
* TCHAR *argstr1(TCHAR *format, UINT_PTR arg)
*
* Args:
* Format - the format string
* arg - the arguments for the message
*
* Returns:
* Pointer to the formatted message text
*
*/
PTCHAR argstr1(format, arg)
TCHAR *format;
ULONG_PTR arg;
{
static TCHAR ArgStr1Buffer[MAX_PATH];
_sntprintf( ArgStr1Buffer, MAX_PATH, format, arg );
ArgStr1Buffer[MAX_PATH - 1] = TEXT( '\0' );
return ArgStr1Buffer;
}
/*** Copen - CMD.EXE open function (M014)
*
* Purpose:
* Opens a file or device and saves the handle for possible later
* signal cleanup.
*
* int Copen(TCHAR *fn, int flags)
*
* Args:
* fn = ASCIZ filename to open
* flags = Flags controlling type of open to make
* fShareMode = Flags for callers sharing mode
*
* Returns:
* Return value from C runtime open
*
* Notes:
* Signal cleanup table does not include STDIN, STDOUT or STDERR.
* M017 - Extensively rewritten to use CreateFile rather than
* runtime open().
*
*/
CRTHANDLE
Copen_Work(fn, flags, fShareMode)
TCHAR *fn ;
unsigned int flags, fShareMode;
{
TCHAR c;
DWORD fAccess;
DWORD fCreate;
HANDLE handle ;
DWORD cb;
LONG high;
CRTHANDLE fh;
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
/* Note that O_RDONLY being a value of 0, cannot be tested for
* conflicts with any of the write type flags.
*/
if (((flags & (O_WRONLY | O_RDWR)) > 2) || /* Flags invalid? */
((flags & O_WRONLY) && (flags & O_APPEND))) {
DEBUG((CTGRP, COLVL, "COPEN: Bad flags issued %04x",flags)) ;
return(BADHANDLE) ;
};
/* M024 - Altered so that the only sharing restriction is to deny
* others write permission if this open is for writing. Any other
* sharing is allowed.
*/
if (flags & (O_WRONLY | O_RDWR)) { /* If Writing, set... */
fAccess = GENERIC_WRITE;
/*
* deny write only if it is not console
*/
if (_tcsicmp(fn, TEXT("con"))) {
fShareMode = FILE_SHARE_READ;
}
fCreate = CREATE_ALWAYS;/* ...open if exists, else create */
} else {
fAccess = GENERIC_READ;
fCreate = OPEN_EXISTING;
}
if (flags == OP_APPEN) {
//
// When opening for append to a device, we must specify OPEN_EXISTING
// (according to MSDN docs).
//
// If this fails, due to some error, attempt to open with OPEN_ALWAYS
//
if ((handle = CreateFile(fn, fAccess|GENERIC_READ, fShareMode, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
if ((handle = CreateFile(fn, fAccess, fShareMode, &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
DosErr = GetLastError();
DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
if ( DosErr == ERROR_OPEN_FAILED ) {
DosErr = ERROR_FILE_NOT_FOUND;
} /* endif */
return(BADHANDLE) ;
}
}
} else if ((handle = CreateFile(fn, fAccess, fShareMode, &sa, fCreate, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
DosErr = GetLastError();
DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
if ( DosErr == ERROR_OPEN_FAILED ) {
DosErr = ERROR_FILE_NOT_FOUND;
} /* endif */
return(BADHANDLE) ;
}
fh = _open_osfhandle((LONG_PTR)handle, _O_APPEND);
if ((flags & O_APPEND) &&
!FileIsDevice(fh) &&
GetFileSize(handle,NULL) != 0) {
c = NULLC ;
high = -1;
fCreate = SetFilePointer(handle, -1L, &high, FILE_END) ;
if (fCreate == 0xffffffff &&
(DosErr = GetLastError()) != NO_ERROR) {
DEBUG((CTGRP,COLVL,"COPEN: SetFilePointer error %d",DosErr)) ;
// should close CRT handle, not OS handle
if (fh != BADHANDLE) {
_close(fh);
}
return BADHANDLE;
}
fCreate = ReadFile(handle, &c, 1, &cb, NULL) ;
if (fCreate == 0) {
high = 0;
SetFilePointer(handle, 0L, &high, FILE_END) ; /* ...back up 1 */
DEBUG((CTGRP,COLVL,"COPEN: ReadFile error %d",GetLastError())) ;
}
DEBUG((CTGRP,COLVL, "COPEN: Moving file ptr")) ;
if (c == CTRLZ) { /* If end=^Z... */
high = -1;
SetFilePointer(handle, -1L, &high, FILE_END) ; /* ...back up 1 */
}
};
SetList(fh) ;
return(fh) ;
}
CRTHANDLE
Copen(fn, flags)
TCHAR *fn ;
unsigned int flags ;
{
return( Copen_Work(fn, flags, FILE_SHARE_READ | FILE_SHARE_WRITE ) ); /* deny nothing */
}
/*** InSetList - Determine if handle is in signal cleanup table
*
* Purpose:
* To determine if the input handle exsists in the cleanup table.
*
* int InSetList(unsigned int fh)
*
* Args:
* fh = File handle to check.
*
* Returns:
* TRUE: if handle is in table.
* FALSE: if handle is not in table.
*
* Notes:
* - Signal cleanup table does not include STDIN, STDOUT or STDERR.
*
*/
unsigned long InSetList(
IN CRTHANDLE fh
)
{
int cnt = 0 ;
if (fh > STDERR && fh < 95) {
while (fh > 31) {
fh -= 32 ;
++cnt ;
} ;
return( (OHTbl[cnt]) & ((unsigned long)1 << fh) );
};
return( FALSE );
}
/*** Cdup - CMD.EXE dup function (M014)
*
* Purpose:
* Duplicates the supplied handle and saves the new handle for
* possible signal cleanup.
*
* int Cdup(unsigned int fh)
*
* Args:
* fh = Handle to be duplicated
*
* Returns:
* The handle returned by the C runtime dup function
*
* Notes:
* Signal cleanup table does not include STDIN, STDOUT or STDERR.
*
*/
CRTHANDLE
Cdup( CRTHANDLE fh )
{
CRTHANDLE NewHandle ;
if ((int)(NewHandle = _dup(fh)) != BADHANDLE)
if ( InSetList( fh ) )
SetList(NewHandle) ;
return(NewHandle) ;
}
/*** Cdup2 - CMD.EXE dup2 function (M014)
*
* Purpose:
* Duplicates the supplied handle and saves the new handle for
* possible signal cleanup.
*
* HANDLE Cdup2(unsigned int fh1, unsigned int fh2)
*
* Args:
* fh = Handle to be duplicated
*
* Returns:
* The handle returned by the C runtime dup2 function
*
* Notes:
* Signal cleanup table does not include STDIN, STDOUT or STDERR.
*
*/
CRTHANDLE
Cdup2( CRTHANDLE fh1, CRTHANDLE fh2)
{
unsigned int retcode ;
int cnt = 0 ;
unsigned int fuse ;
if ((int)(retcode = (unsigned)_dup2(fh1,fh2)) != -1) {
if ((fuse = fh2) > STDERR && fuse < 95) {
while (fuse > 31) {
fuse -= 32 ;
++cnt ;
}
OHTbl[cnt] &= ~((unsigned long)1 << fuse) ;
}
if ( InSetList( fh1 ) )
SetList(fh2) ;
}
return(retcode) ;
}
/*** Cclose - CMD.EXE close handle function (M014)
*
* Purpose:
* Closes an open file or device and removes the handle from the
* signal cleanup table.
*
* int Cclose(unsigned int fh)
*
* Args:
* fh = File handle to be closed.
*
* Returns:
* return code from C runtime close
*
* Notes:
* - Signal cleanup table does not include STDIN, STDOUT or STDERR.
* - M023 * Revised to use bit map instead of malloc'd space.
*
*/
int
Cclose( CRTHANDLE fh )
{
int cnt = 0 ;
unsigned int fuse ;
int ret_val;
if (fh == BADHANDLE)
return(0);
if ((fuse = fh) > STDERR && fuse < 95) {
while (fuse > 31) {
fuse -= 32 ;
++cnt ;
}
OHTbl[cnt] &= ~((unsigned long)1 << fuse) ;
}
ret_val = _close(fh); /* Delete file handle */
return(ret_val);
}
/*** SetList - Place open handle in signal cleanup list (M014)
*
* Purpose:
* Places a handle number in the signal cleanup table for use
* during signal's closing of files.
*
* int SetList(unsigned int fh)
*
* Args:
* fh = File handle to install.
*
* Returns:
* nothing
*
* Notes:
* - Signal cleanup table does not include STDIN, STDOUT or STDERR.
* - M023 * Revised to use bit map instead of malloc'd space.
*
*/
void
SetList(
IN CRTHANDLE fh
)
{
int cnt = 0 ;
if (fh > STDERR && fh < 95) {
while (fh > 31) {
fh -= 32 ;
++cnt ;
} ;
OHTbl[cnt] |= ((unsigned long)1 << fh) ;
};
}
/*** GetFuncPtr - return the i-th function pointer in JumpTable (M015)
*
* int (*GetFuncPtr(int i))()
*
* Args:
* i - the index of the JumpTable entry containing the function pointer
* to be returned
*
* Returns:
* The i-th function pointer in JumpTable.
*
* Notes:
* It is assumed that i is valid.
*
*/
int
(*GetFuncPtr(i))(struct cmdnode *)
int i ;
{
return(JumpTable[i].func) ;
}
/*** FindCmd - search JumpTable for a particular command (M015)
*
* Purpose:
* Check the command name string pointers in each of the JumpTable
* entries for one which matches the name in the string supplied by
* the caller.
*
* int FindCmd(int entries, TCHAR *sname, TCHAR *sflags)
*
* Args:
* entries - M009 - This value is highest entry to be checked. One
* must be added for this to become a count of entries to
* check.
* sname - pointer to the command name to search for
* sflags - if the command is found, store the command's flags here
*
* Returns:
* If the entry is found, the entry's JumpTable index.
* Otherwise, -1.
*
*/
int FindCmd(
int entries,
const TCHAR *sname,
TCHAR *sflags)
{
int i ;
for (i=0 ; i <= entries ; i++) { /* search through all entries */
if (_tcsicmp(sname,JumpTable[i].name) == 0) { /* test for cmd in table @inx */
/* */
if (!(JumpTable[i].flags & EXTENSCMD) || fEnableExtensions) {
*sflags = JumpTable[i].flags; /* M017 */
cmdfound = i; /* @@5 save current cmd index */
return(i); /* return not found index */
}
} /* */
} /* */
cmdfound = -1; /* @@5 save not found index */
return(-1) ; /* return not found index */
}
/********************* START OF SPECIFICATION **************************/
/* */
/* SUBROUTINE NAME: KillProc */
/* */
/* DESCRIPTIVE NAME: Kill process and wait for it to die */
/* */
/* FUNCTION: This routine kills a specified process during signal */
/* handling. */
/* */
/* NOTES: If the process is started by DosExecPgm, DosKillProcess */
/* is called to kill the process and all its child processes.*/
/* WaitProc is also called to wait for the termination of */
/* the process and child processes. */
/* If the process is started by DosStartSession, */
/* DosStopSession is called to stop the specified session and*/
/* its child sessions. WaitTermQProc is also called to wait */
/* for the termination of the session. */
/* */
/* All of CMD's kills are done on the entire subtree and that */
/* is assumed by this function. For single PID kills, use */
/* DOSKILLPROCESS direct. */
/* */
/* */
/* ENTRY POINT: KillProc */
/* LINKAGE: NEAR */
/* */
/* INPUT: Process ID / Session ID - to kill */
/* Wait - indicates if we should wait here or not */
/* */
/* OUTPUT: None */
/* */
/* EXIT-NORMAL: No error return code from WaitProc or WaitTermQProc */
/* */
/* */
/* EXIT-ERROR: Error return code from DosKillProcess or */
/* DosStopSession. Or error code from WaitProc or */
/* */
/* EFFECTS: None. */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* WaitProc - wait for the termination of the specified process, */
/* its child process, and related pipelined */
/* processes. */
/* */
/* */
/* EXTERNAL REFERENCES: */
/* ROUTINES: */
/* DOSKILLPROCESS - Kill the process and its child processes */
/* DOSSTOPSESSION - Stop the session and its child sessions */
/* WINCHANGESWITCHENTRY - Change switch list entry */
/* */
/********************** END OF SPECIFICATION **************************/
KillProc(pid, wait)
HANDLE pid ;
int wait;
{
unsigned i = 0;
DEBUG((CTGRP,COLVL, "KillProc: Entered PID = %d", pid)) ;
if (!TerminateProcess((HANDLE)pid, 1)) {
DosErr = GetLastError();
}
if (wait) {
i = WaitProc(pid) ; /* wait for the related process to end */
}
return( i );
}
/*** WaitProc - Wait for a command subtree to terminate (M019)
*
* Purpose:
* Provides a means of waiting for a process and all of its
* children to terminate.
*
* int WaitProc(unsigned pid)
*
* Args:
* pid - The process ID to be waited on
*
* Returns:
* Retcode of the head process of the subtree
*
* Notes:
* All of CMD's waits are done on the entire subtree and CMD
* will always wait until someone terminates. That is assumed
* by this function. For single PID waits, use DOSCWAIT direct.
*
*/
WaitProc(pid)
HANDLE pid ;
{
unsigned FinalRCode; /* Return value from this function */
DEBUG((CTGRP,COLVL, "WaitProc: Entered PID = %d", pid)) ;
//
// Do not allow printint of ctrl-c in ctrl-c thread while
// waiting for another process. The main loop will handle
// this if the process exits due to ctrl-c.
//
fPrintCtrlC = FALSE;
WaitForSingleObject( (HANDLE)pid, INFINITE );
GetExitCodeProcess( (HANDLE)pid, (LPDWORD)&FinalRCode );
//if (CtrlCSeen & (FinalRCode == CONTROL_C_EXIT)) {
// how do we ever get here???
if (FinalRCode == CONTROL_C_EXIT) {
SetCtrlC();
fprintf( stderr, "^C" );
fflush( stderr );
}
fPrintCtrlC = TRUE;
DEBUG((CTGRP, COLVL, "WaitProc: Returned handle %d, FinalRCode %d", pid, FinalRCode));
CloseHandle( (HANDLE)pid );
DEBUG((CTGRP,COLVL,"WaitProc:Complete and returning %d", FinalRCode)) ;
return(FinalRCode) ;
}
/*** ParseLabel - Parse a batch file label statement (M020)
*
* Purpose:
* Simulates the lexer's handling of labels in GOTO arguments.
*
* int ParseLabel(TCHAR *lab, TCHAR buf[],unsigned flag)
*
* Args:
* lab - The batch file label to parse
* buf - The buffer to hold the parsed label
* flag - TRUE if this is a source label (already parsed once)
* - FALSE if this is a test target label.
*
* Returns:
* Nothing useful
*
* Notes:
* Note that source labels (those in the GOTO statement itself),
* have already been parsed by the normal method with ESCHAR's
* and other operator tokens presumably processed. Such char's
* still in the label can be assumed to have been ESC'd already,
* and therefore, we ignore them. Target labels, however, are
* raw strings and we must simulate the parser's actions.
*
*/
void
ParseLabel(
TCHAR *lab,
TCHAR buf[],
ULONG cbBufMax,
BOOLEAN flag
)
{
ULONG i ;
TCHAR c ;
lab = EatWS(lab,NULL) ; /* Strip normal whitespace */
if ((c = *lab) == COLON || c == PLUS) /* Eat first : or + ... */
++lab ; /* ...only */
if (!flag) /* If target strip... */
lab = EatWS(lab,NULL) ; /* ... any add'l WS */
for (i = 0, c = *lab ; i < cbBufMax ; c = *(++lab)) {
DEBUG((CTGRP,COLVL,"ParseLabel: Current Char = %04x", *lab)) ;
if ((flag && mystrchr(Delimiters, c)) ||
//mystrchr("+:\n\r\x20", c)) {
mystrchr( TEXT("+:\n\r\t "), c)) { //change from \x20 to space bug
// mips compiler
DEBUG((CTGRP,COLVL,"ParseLabel: Found terminating delim.")) ;
break ;
};
if (!flag) {
if (mystrchr(TEXT("&<|>"), c)) {
DEBUG((CTGRP,COLVL,
"ParseLabel: Found operator in target!")) ;
break ;
};
if (c == ESCHAR) {
DEBUG((CTGRP,COLVL,
"ParseLabel: Found '^' adding %04x",
*(lab+1))) ;
buf[i++] = *(++lab) ;
continue ;
};
};
DEBUG((CTGRP,COLVL,"ParseLabel: Adding %02x",c)) ;
buf[i++] = c ;
} ;
buf[i] = NULLC ;
DEBUG((CTGRP,COLVL,"ParseLabel: Exitted with label %ws", buf)) ;
}
/*** EatWS - Strip leading whitespace and other special chars (M020)
*
* Purpose:
* Remove leading whitespace and any special chars from the string.
*
* TCHAR *EatWS(TCHAR *str, TCHAR *spec)
*
* Args:
* str - The string to eat from
* spec - Additional delimiters to eat
*
* Returns:
* Updated character pointer
*
* Notes:
*
*/
PTCHAR
EatWS(
TCHAR *str,
TCHAR *spec )
{
TCHAR c ;
if (str != NULL) {
while ((_istspace(c = *str) && c != NLN) ||
(mystrchr(Delimiters, c) && c) ||
(spec && mystrchr(spec,c) && c))
++str ;
}
return(str) ;
}
/*** IsValidDrv - Check drive validity
*
* Purpose:
* Check validity of passed drive letter.
*
* int IsValidDrv(TCHAR drv)
*
* Args:
* drv - The letter of the drive to check
*
* Returns:
* TRUE if drive is valid
* FALSE if not
*
* Notes:
*
*/
IsValidDrv(TCHAR drv)
{
TCHAR temp[4];
temp[ 0 ] = drv;
temp[ 1 ] = COLON;
temp[ 2 ] = PathChar;
temp[ 3 ] = NULLC;
//
// return of 0 or 1 mean can't determine or root
// does not exists.
//
if (GetDriveType(temp) <= 1)
return( FALSE );
else {
return( TRUE );
}
}
/*** IsDriveLocked - Check For Drive Locked Condition
*
* Purpose:
* The real purpose is to check for a drive locked, but since this
* could be the first time that the disk get hit we will just return
* the Dos Error Code
*
* int IsDriveLocked(TCHAR drv)
*
* Args:
* drv - The letter of the drive to check
*
* Returns:
* 0 if no errors
* Dos Error number if failure
*
* Notes:
*
*/
IsDriveLocked( TCHAR drv )
{
DWORD Vsn[2];
TCHAR szVolName[MAX_PATH];
TCHAR szVolRoot[5];
DWORD rc;
szVolRoot[ 0 ] = drv;
szVolRoot[ 1 ] = COLON;
szVolRoot[ 2 ] = PathChar;
szVolRoot[ 3 ] = NULLC;
//
// If floppy and locked will get this.
//
if ( (rc = GetDriveType(szVolRoot)) <= 1) {
return( TRUE );
}
//
// If removable check if access to vol. info allowed.
// if not then assume it is locked.
//
if ((rc != DRIVE_REMOVABLE) && (rc != DRIVE_CDROM)) {
if (!GetVolumeInformation(szVolRoot,
szVolName,
MAX_PATH,
Vsn,
NULL,
NULL,
NULL,
0)) {
if ( GetLastError() == ERROR_ACCESS_DENIED) {
return( TRUE );
}
}
}
return( FALSE );
}
/*** PtrErr - Print Error resulting from last recorded system call
*
* Purpose:
* Prints appropriate error message resulting from last system
* call whose return code is saved in DosErr variable.
*
* int PtrErr(unsigned msgnum)
*
* Args:
* msgnum = Default message to print if no match
*
* Returns:
* Nothing
*
* Notes:
* msgnum can be passed in as NULL if no msg is to be printed as a
* default.
*
*/
void PrtErr(msgnum)
unsigned msgnum ;
{
unsigned i, /* Temp counter */
tabmsg = (unsigned)MSG_USE_DEFAULT ; /* Table message found */
for (i = 0 ; mstabl[i].errnum != 0 ; ++i) {
if (DosErr == mstabl[i].errnum) {
tabmsg = mstabl[i].msnum ;
break ;
}
}
if (tabmsg != (unsigned)MSG_USE_DEFAULT)
msgnum = tabmsg ;
if (msgnum)
PutStdErr(msgnum, NOARGS) ; /* @@ */
}
/*** GetMsg - Get a message ***/
PTCHAR
GetMsg(unsigned MsgNum, ...)
{
PTCHAR Buffer = NULL;
unsigned int msglen;
va_list arglist;
va_start( arglist, MsgNum );
msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER ,
NULL,
MsgNum,
0,
(LPTSTR) &Buffer,
0,
&arglist
);
va_end(arglist);
return Buffer;
}
/********************** START OF SPECIFICATIONS **********************/
/* SUBROUTINE NAME: Copen_Work2 */
/* */
/* DESCRIPTIVE NAME: Worker routine to open a file. */
/* */
/* FUNCTION: Opens a file or device and saves the handle for */
/* possible later signal cleanup. Set the extended */
/* attribute information from the file being opened. */
/* */
/* NOTES: Signal cleanup table does not include STDIN, STDOUT or */
/* STDERR. M017 - Extensively rewritten to use CreateFile */
/* rather than runtime open(). */
/* */
/* ENTRY POINT: Copen_Work2 */
/* LINKAGE: Copen_Work2(fn, flags, fShareMode, eaop, FSwitch) */
/* */
/* INPUT: (PARAMETERS) */
/* */
/* filename = ASCIZ filename to open */
/* flags = Flags controlling type of open to make */
/* fShareMode = Flags for callers sharing mode */
/* eaop = Extended attribute buffer pointer. */
/* FSwitch = Fail if EAs can't be copied */
/* */
/* EXIT-NORMAL: */
/* Return file handle value like C runtime open */
/* */
/* EXIT-ERROR: */
/* Return -1 if open failed */
/* */
/* EFFECTS: None. */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* FileIsDevice - test for file or device via DOSQHANDTYPE */
/* SetList - add handle from open to cleanup list */
/* varb:DosErr - global error return variable */
/* */
/* EXTERNAL REFERENCES: */
/* ROUTINES: */
/* CreateFile - open a file with ability for EA processing */
/* */
/*********************** END OF SPECIFICATIONS ***********************/
CRTHANDLE
Copen_Work2(fn, flags, fShareMode, FSwitch)
TCHAR *fn ; /* filename */
unsigned int flags, fShareMode, FSwitch ; /* flags and special case flags */
{
HANDLE handl ; /* Handle ret'd */
CRTHANDLE rcode; /* return code */
DWORD fAccess;
DWORD fCreate;
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
/***************************************************************************/
/* Note that O_RDONLY being a value of 0, cannot be tested for */
/* conflicts with any of the write type flags. */
/***************************************************************************/
DBG_UNREFERENCED_PARAMETER( FSwitch);
if (((flags & (O_WRONLY | O_RDWR)) > 2) || /* Flags invalid? */
((flags & O_WRONLY) && /* */
(flags & O_APPEND))) { /* */
DEBUG((CTGRP, COLVL, "COPEN: Bad flags issued %04x",flags)) ;
rcode = BADHANDLE; /* set bad handle */
} else {
/***************************************************************************/
/* M024 - Altered so that the only sharing restriction is to deny */
/* others write permission if this open is for writing. Any other */
/* sharing is allowed. */
/***************************************************************************/
if (flags & (O_WRONLY | O_RDWR)) { /* If Writing, set... */
fAccess = GENERIC_WRITE;
if (flags & O_RDWR)
fAccess |= GENERIC_READ;
/*
* deny write only if it is not console
*/
if (_tcsicmp(fn, TEXT("con"))) {
fShareMode = FILE_SHARE_READ;
}
fCreate = CREATE_ALWAYS;/* ...open if exists, else create */
} else {
fAccess = GENERIC_READ;
fCreate = OPEN_EXISTING;
if (!_tcsicmp(fn,TEXT("con"))) {
fShareMode = FILE_SHARE_READ;
}
}
fn = StripQuotes(fn);
if (fCreate == CREATE_ALWAYS &&
(handl=CreateFile(fn, fAccess, fShareMode, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) != INVALID_HANDLE_VALUE) {
rcode = _open_osfhandle((LONG_PTR)handl, _O_APPEND);
} else if ((handl = CreateFile(fn, fAccess, fShareMode, &sa, fCreate, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) == INVALID_HANDLE_VALUE) {
DosErr = GetLastError();
DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
if (DosErr==ERROR_OPEN_FAILED) {
DosErr=ERROR_FILE_NOT_FOUND; /* change to another error */
}
rcode = BADHANDLE;
} else {
rcode = _open_osfhandle((LONG_PTR)handl, _O_APPEND);
} /* */
} /* */
return(rcode ) ; /* return handle to caller */
}
/********************** START OF SPECIFICATIONS **********************/
/* SUBROUTINE NAME: Copen2 */
/* */
/* DESCRIPTIVE NAME: Open a destination file with extended attributes*/
/* */
/* FUNCTION: Call a worker routine to open a destination file or */
/* device and set the extended attribute information */
/* from the source file if this is the first file */
/* and/or only file and there are extended attributes */
/* available. */
/* */
/* NOTES: */
/* */
/* ENTRY POINT: Copen2 */
/* LINKAGE: Copen2(fn, flags, FSwitch) */
/* */
/* INPUT: (PARAMETERS) */
/* */
/* fn = ASCIZ filename to open */
/* flags = Flags controlling type of open to make */
/* */
/* */
/* EXIT-NORMAL: */
/* Return file handle value like C runtime open */
/* */
/* EXIT-ERROR: */
/* Return -1 if open failed */
/* */
/* EFFECTS: None. */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* Copen_Work2 - worker routine for performing CreateFile */
/* varb: first_fflag-TRUE = first file FALSE = not first file */
/* */
/* */
/*********************** END OF SPECIFICATIONS ***********************/
CRTHANDLE
Copen2(fn, flags, FSwitch)
TCHAR *fn ; /* file name */
unsigned int flags ; /* open flags */
unsigned FSwitch;
{
return(Copen_Work2(fn, flags, FILE_SHARE_READ | FILE_SHARE_WRITE, FSwitch));
}
/********************** START OF SPECIFICATIONS **********************/
/* SUBROUTINE NAME: Copen_Copy2 */
/* */
/* DESCRIPTIVE NAME: Open a source file with extended attributes. */
/* */
/* FUNCTION: Call a worker routine to open a source file or device */
/* and get the extended attribute information from the */
/* file if ffirst2 or fnext2 says this is a EA file. */
/* */
/* NOTES: */
/* */
/* ENTRY POINT: Copen_Copy2 */
/* LINKAGE: Copen2(fn, flags) */
/* */
/* INPUT: (PARAMETERS) */
/* */
/* fn = ASCIZ filename to open */
/* flags = Flags controlling type of open to make */
/* */
/* EXIT-NORMAL: */
/* Return file handle value like C runtime open */
/* */
/* EXIT-ERROR: */
/* Return -1 if open failed */
/* */
/* EFFECTS: None. */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* Copen_Work2 - worker routine for performing CreateFile */
/* Cclose - close a handle file/device handle opened */
/* and remove handle from handles to free */
/* varb: first_file- TRUE = first file FALSE = not first file */
/* */
/* */
/* */
/* EXTERNAL REFERENCES: */
/* ROUTINES: */
/* DOSALLOCSEG - request an amount of ram memory */
/* DOSFREESEG - free a DOSALLOCSEG segment of ram memory */
/* DOSQFILEINFO - request EA info for a file using level 2 */
/* */
/*********************** END OF SPECIFICATIONS ***********************/
CRTHANDLE
Copen_Copy2(fn, flags)
TCHAR *fn; /* file name */
unsigned int flags ; /* open flags */
{
return(Copen_Work2(fn, flags, FILE_SHARE_READ | FILE_SHARE_WRITE, TRUE));
}
CRTHANDLE
Copen_Copy3(fn)
TCHAR *fn; /* file name */
{
HANDLE handl ; /* Handle ret'd */
CRTHANDLE rcode; /* return code */
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
fn = StripQuotes(fn);
handl = CreateFile(fn, GENERIC_WRITE, 0, &sa, TRUNCATE_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (handl == INVALID_HANDLE_VALUE) {
DosErr = GetLastError();
DEBUG((CTGRP,COLVL, "COPEN: CreateFile ret'd %d",DosErr)) ;
if (DosErr==ERROR_OPEN_FAILED) {
DosErr=ERROR_FILE_NOT_FOUND; /* change to another error */
}
rcode = BADHANDLE;
} else {
rcode = _open_osfhandle((LONG_PTR)handl, _O_APPEND);
} /* */
return(rcode ) ; /* return handle to caller */
}
TCHAR *
StripQuotes( TCHAR *wrkstr )
{
static TCHAR tempstr[MAXTOKLEN];
int i,j,slen;
if ( mystrchr(wrkstr,QUOTE) ) {
mytcsnset(tempstr, NULLC, MAXTOKLEN);
slen= mystrlen(wrkstr);
j=0;
for (i=0;i<slen;i++) {
if ( wrkstr[i] != QUOTE )
tempstr[j++] = wrkstr[i];
}
tempstr[j] = NULLC;
return(tempstr);
} else
return(wrkstr);
}
TCHAR *
SkipWhiteSpace( TCHAR *String )
{
while (*String && _istspace( *String )) {
String++;
}
return String;
}
ULONG
PromptUser (
IN PTCHAR szArg,
IN ULONG msgId,
IN ULONG responseDataId
)
/*++
Routine Description:
Prompts user for single letter answer to a question. The prompt can be
a message plus an optional single argument. Valid letters are defined
by contents of message specified by responseDataId. Case is not
significant.
Arguments:
pszTok - list of attributes
Return Value:
Returns index into response data
Return: the user response
--*/
{
BOOLEAN fFirst;
TCHAR chT;
TCHAR chAnsw = NULLC;
ULONG dwOutputModeOld;
ULONG dwOutputModeCur;
ULONG dwInputModeOld;
ULONG dwInputModeCur;
BOOLEAN fOutputModeSet = FALSE;
BOOLEAN fInputModeSet = FALSE;
HANDLE hndStdOut = NULL;
HANDLE hndStdIn = NULL;
TCHAR responseChoices[16];
TCHAR *p;
ULONG iResponse;
ULONG iMaxResponse;
DWORD cb;
PTCHAR Message;
if (msgId == MSG_MOVE_COPY_OVERWRITE) {
CRTHANDLE srcptr;
srcptr = Copen_Copy2(szArg, (unsigned int)O_RDONLY);
if (srcptr != BADHANDLE) {
if (FileIsDevice( srcptr )) {
Cclose(srcptr);
return 2; // Return All response for devices
}
Cclose(srcptr);
}
}
Message = GetMsg( responseDataId );
if (Message != NULL && _tcslen( Message ) < 16) {
_tcscpy( responseChoices, Message );
_tcsupr( responseChoices );
} else {
_tcscpy( responseChoices, TEXT("NY") );
}
iMaxResponse = _tcslen( responseChoices ) - 1;
LocalFree( Message );
hndStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (GetConsoleMode( hndStdOut, &dwOutputModeOld) ) {
// make sure CRLF is processed correctly
dwOutputModeCur = dwOutputModeOld | ENABLE_PROCESSED_OUTPUT;
fOutputModeSet = TRUE;
SetConsoleMode(hndStdOut,dwOutputModeCur);
GetLastError();
}
hndStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (GetConsoleMode( hndStdIn, &dwInputModeOld) ) {
// make sure input is processed correctly
dwInputModeCur = dwInputModeOld | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT;
fInputModeSet = TRUE;
SetConsoleMode(hndStdIn,dwInputModeCur);
GetLastError();
#ifndef WIN95_CMD
if (lpSetConsoleInputExeName != NULL)
(*lpSetConsoleInputExeName)( TEXT("<noalias>") );
#endif
}
//
// Loop till the user answer with a valid character
//
while (TRUE) {
chT = NULLC;
fFirst = TRUE ;
if (szArg) {
PutStdOut(msgId, ONEARG, szArg );
} else {
PutStdOut(msgId, NOARGS);
}
//
// Flush keyboard before asking for response
//
if (FileIsDevice(STDIN)) {
FlushConsoleInputBuffer( GetStdHandle(STD_INPUT_HANDLE) );
}
//
// Read till EOL
//
while (chT != NLN) {
if (ReadBufFromInput(
GetStdHandle(STD_INPUT_HANDLE),
(TCHAR*)&chT, 1, &cb) == 0 ||
cb != 1) {
chAnsw = responseChoices[0];
cmd_printf(CrLf) ;
break;
}
if (fFirst) {
chAnsw = (TCHAR) _totupper(chT) ;
fFirst = FALSE ;
}
if (!FileIsDevice(STDIN) || !(flgwd & 1)) {
cmd_printf(Fmt19,chT) ;
}
}
p = _tcschr(responseChoices, chAnsw);
if (p != NULL) {
iResponse = (UINT)(p - responseChoices);
if (iResponse <= iMaxResponse) {
break;
}
}
}
if (fOutputModeSet) {
SetConsoleMode( hndStdOut, dwOutputModeOld );
}
if (fInputModeSet) {
SetConsoleMode( hndStdIn, dwInputModeOld );
#ifndef WIN95_CMD
if (lpSetConsoleInputExeName != NULL)
(*lpSetConsoleInputExeName)( TEXT("CMD.EXE") );
#endif
}
return(iResponse);
}
ULONG LastMsgNo;
int
eSpecialHelp(
IN struct cmdnode *pcmdnode
)
{
TCHAR szHelpStr[] = TEXT("/\0?");
if (LastMsgNo == MSG_HELP_FOR)
CheckHelpSwitch(FORTYP, szHelpStr);
else
if (LastMsgNo == MSG_HELP_IF)
CheckHelpSwitch(IFTYP, szHelpStr);
else
if (LastMsgNo == MSG_HELP_REM)
CheckHelpSwitch(REMTYP, szHelpStr);
else
PutStdOut( LastMsgNo, NOARGS );
return SUCCESS;
}
BOOLEAN
CheckHelp (
IN ULONG jmptblidx,
IN PTCHAR pszTok,
IN BOOL fDisplay
)
{
ULONG msgno = JumpTable[jmptblidx].msgno;
ULONG extmsgno = JumpTable[jmptblidx].extmsgno;
ULONG noextramsg =JumpTable[jmptblidx].noextramsg;
if (!pszTok) {
return( FALSE );
}
while (*pszTok) {
if (*pszTok == SwitChar) {
//
// Check for /?. Ignore /? if ? not followed by delimeter and IF command
// This allows if ./?. == ..
//
if (*(pszTok + 2) == QMARK && (jmptblidx != IFTYP || *(pszTok + 3) == NULLC) ) {
if (msgno == 0 && fEnableExtensions) {
msgno = extmsgno;
extmsgno = 0;
}
if (msgno == 0) {
msgno = MSG_SYNERR_GENL;
extmsgno = 0;
noextramsg = 0;
}
if ( fDisplay ) {
//
// Display help now
//
BeginHelpPause();
#define CTRLCBREAK if (CtrlCSeen) break
do {
CTRLCBREAK; PutStdOut(msgno, NOARGS);
if (!fEnableExtensions) break;
if (extmsgno != 0) {
CTRLCBREAK; PutStdOut(extmsgno, NOARGS);
}
while (!CtrlCSeen && noextramsg--)
PutStdOut(++extmsgno, NOARGS);
} while ( FALSE );
EndHelpPause();
} else {
//
// Remember the message, eSpecicalHelp will display it later.
// extmsgno will always be zero here
//
LastMsgNo = msgno;
}
return( TRUE );
}
//
// move over SwitChar, switch value and 2 0's
//
pszTok += mystrlen(pszTok) + 1;
if (*pszTok) {
pszTok += mystrlen(pszTok) + 1;
}
} else
if (jmptblidx == ECHTYP) {
//
// ECHO only supports /? as first token. Allows you echo a string
// with /? in it (e.g. ECHO Update /?).
//
break;
} else {
//
// move over param. and 1 0's
//
pszTok += mystrlen(pszTok) + 1;
}
}
return( FALSE );
}
BOOLEAN
TokBufCheckHelp(
IN PTCHAR pszTokBuf,
IN ULONG jmptblidx
)
{
TCHAR szT[10];
PTCHAR pszTok;
//
// Tokensize the command line (special delimeters are tokens)
//
szT[0] = SwitChar ;
szT[1] = NULLC ;
pszTok = TokStr(pszTokBuf, szT, TS_SDTOKENS);
return CheckHelp(jmptblidx, pszTok, FALSE);
}
BOOLEAN
CheckHelpSwitch (
IN ULONG jmptblidx,
IN PTCHAR pszTok
)
{
return CheckHelp( jmptblidx,
pszTok,
TRUE
) ;
}
PTCHAR
GetTitle(
IN struct cmdnode *pcmdnode
)
{
PTCHAR tptr, argptr;
/* Allocate string space for command line */
/* Command_Head + Optional_Space + Command_Tail + Null + Null */
if (!(argptr = mkstr(mystrlen(pcmdnode->cmdline)*sizeof(TCHAR)+mystrlen(pcmdnode->argptr)*sizeof(TCHAR)+3*sizeof(TCHAR))))
return(NULL) ;
/* The command line is the concatenation of the command head and tail */
mystrcpy(argptr,pcmdnode->cmdline);
tptr = argptr+mystrlen(argptr);
if (mystrlen(pcmdnode->argptr)) {
if (*pcmdnode->argptr != SPACE) {
//DbgPrint("GetTitle: first arg char not space %s\n",pcmdnode->argptr);
*tptr++ = SPACE;
}
mystrcpy(tptr,pcmdnode->argptr);
tptr[mystrlen(tptr)+1] = NULLC; /* Add extra null byte */
}
tptr = argptr;
return( tptr );
}
VOID
SetConTitle(
IN PTCHAR pszTitle
)
{
ULONG cbNewTitle, cbTitle;
PTCHAR pszNewTitle, pTmp;
if (pszTitle == NULL) {
return;
}
if ((!CurrentBatchFile) && (!SingleCommandInvocation)) {
if ((pszNewTitle = (PTCHAR)HeapAlloc(GetProcessHeap(), 0, (MAX_PATH+2)*sizeof(TCHAR))) == NULL) {
return;
}
cbNewTitle = GetConsoleTitle( pszNewTitle, MAX_PATH );
if (!cbNewTitle) {
return;
}
cbTitle = mystrlen(pszTitle);
pTmp = (PTCHAR)HeapReAlloc(GetProcessHeap(), 0, pszNewTitle, (cbNewTitle+cbTitle+cbTitleCurPrefix+10)*sizeof(TCHAR));
if (pTmp == NULL) {
HeapFree( GetProcessHeap( ), 0, pszNewTitle );
return;
}
pszNewTitle = pTmp;
if (fTitleChanged) {
_tcscpy( pszNewTitle + cbTitleCurPrefix, pszTitle );
} else {
_tcscat( pszNewTitle, TEXT(" - ") );
cbTitleCurPrefix = _tcslen( pszNewTitle );
_tcscat( pszNewTitle, pszTitle );
fTitleChanged = TRUE;
}
SetConsoleTitle(pszNewTitle);
HeapFree(GetProcessHeap(), 0, pszNewTitle);
}
}
VOID
ResetConTitle(
IN PTCHAR pszTitle
)
{
if (pszTitle == NULL) {
return;
}
if ((!CurrentBatchFile) && (fTitleChanged)) {
SetConsoleTitle(pszTitle);
cbTitleCurPrefix = 0;
fTitleChanged = FALSE;
}
}
/***
*void ResetConsoleMode( void ) - make sure correct mode bits are set
*
*Purpose:
* Called after each external command or ^C in case they hosed out modes.
*
*Entry:
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void
ResetConsoleMode( void )
{
DWORD dwDesiredOutputMode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
DWORD dwDesiredInputMode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT;
SetConsoleMode(CRTTONT(STDOUT), dwCurOutputConMode);
if (GetConsoleMode(CRTTONT(STDOUT), &dwCurOutputConMode)) {
if ((dwCurOutputConMode & dwDesiredOutputMode) != dwDesiredOutputMode) {
dwCurOutputConMode |= dwDesiredOutputMode;
SetConsoleMode(CRTTONT(STDOUT), dwCurOutputConMode);
}
}
if (GetConsoleMode(CRTTONT(STDIN),&dwCurInputConMode)) {
if ((dwCurInputConMode & dwDesiredInputMode) != dwDesiredInputMode ||
dwCurInputConMode & ENABLE_MOUSE_INPUT
) {
dwCurInputConMode &= ~ENABLE_MOUSE_INPUT;
dwCurInputConMode |= dwDesiredInputMode;
SetConsoleMode(CRTTONT(STDIN), dwCurInputConMode);
}
#ifndef WIN95_CMD
if (lpSetConsoleInputExeName != NULL)
(*lpSetConsoleInputExeName)( TEXT("CMD.EXE") );
#endif
}
}
/***
*void mytcsnset(string, val, count) - set count characters to val
*
*Purpose:
* Sets the first count characters of string the character value.
*
*Entry:
* tchar_t *string - string to set characters in
* tchar_t val - character to fill with
* size_t count - count of characters to fill
*
*Exit:
* returns string, now filled with count copies of val.
*
*Exceptions:
*
*******************************************************************************/
void mytcsnset (
PTCHAR string,
TCHAR val,
int count
)
{
while (count--)
*string++ = val;
return;
}