|
|
/*++
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 */
struct envdata CmdEnv ; /* Holds info need to manipulate Cmd's environment */
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;
extern TCHAR ShortMondayName[]; extern TCHAR ShortTuesdayName[]; extern TCHAR ShortWednesdayName[]; extern TCHAR ShortThursdayName[]; extern TCHAR ShortFridayName[]; extern TCHAR ShortSaturdayName[]; extern TCHAR ShortSundayName[];
//
// 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;
unsigned msglen; /* @@@@@@@@@@@@@@ */
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,&CmdEnv); 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 ); 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; 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; }
/**** dayptr - return pointer to day of the week
* * Purpose: * To return a pointer to the string representing the current day of * the week. * * Args: * dow - number representing the day of the week. * */
TCHAR *dayptr( dow ) unsigned dow; { switch ( dow ) { case 0: return ShortSundayName; case 1: return ShortMondayName; case 2: return ShortTuesdayName; case 3: return ShortWednesdayName; case 4: return ShortThursdayName; case 5: return ShortFridayName; default: return ShortSaturdayName; } }
/********************** 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; }
|