/*++ 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; idwSize.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") ); #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; }