// TermCap.cpp : This file contains the // Created: Dec '97 // Author : a-rakeba // History: // Copyright (C) 1997 Microsoft Corporation // All rights reserved. // Microsoft Confidential #include #include #include #include #include #include #include using namespace _Utils; using CDebugLevel::TRACE_DEBUGGING; using CDebugLevel::TRACE_HANDLE; using CDebugLevel::TRACE_SOCKET; CTermCap* CTermCap::m_pInstance = 0; int CTermCap::m_iRefCount = 0; PCHAR CTermCap::m_pszFileName = 0; extern HANDLE g_hSyncCloseHandle; // makes sure that there is only one instance of CTermCap created CTermCap* CTermCap::Instance() { if( 0 == m_pInstance ) { m_pInstance = new CTermCap; m_iRefCount ++; } return m_pInstance; } CTermCap::CTermCap() { m_lpBuffer = new CHAR[BUFF_SIZE3]; } CTermCap::~CTermCap() { delete [] m_pszFileName; delete [] m_lpBuffer; if(0 == (m_iRefCount --)) { delete [] m_pInstance; } } // // This function sits on top of FindEntry so that we have the // flexibility (in future) to look for the TERMCAP entry in // areas other than the "termcap" file // bool CTermCap::LoadEntry( LPSTR lpszTermName ) { bool bReturn = false; if( 0 == lpszTermName ) return ( false ); #if 0 // try to move m_hFile's file pointer to the beginning LONG lDistance = 0; DWORD dwPointer = SetFilePointer( m_hFile, lDistance, NULL, FILE_BEGIN ); // if we failed ... if( dwPointer == 0xFFFFFFFF ) { // obtain the error code DWORD dwError = GetLastError() ; // deal with that failure _TRACE( TRACE_DEBUGGING, "SetFilePointer() failed %d" , dwError ); } #endif m_hFile = CreateFileA( m_pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( m_hFile == INVALID_HANDLE_VALUE ) return false ; //Fix for HANDLE LEAK : close the handle in the caller function. bReturn = FindEntry( lpszTermName); TELNET_CLOSE_HANDLE(m_hFile); return bReturn; } // // This function reads blocks of data from the termcap file. // Then it looks at each character. If it is a new line // preceded by a '\' then it continues reading the characters. // Else, it knows that it has successfully read a complete // termcap "entry" ( which is stored in m_lpBuffer). // Then it calls LookForTermName(). If LookForTermName() // is successful, then the job is done and we have the correct // "entry" in the m_lpBuffer. Else, ie. if LookForTermName() // fails, then we repeat the whole process again by reading // the next block of data in the termcap file. // bool CTermCap::FindEntry(LPSTR lpszTermName) { if(0 == lpszTermName) { return ( false ); } _chASSERT( m_lpBuffer != 0 ); PCHAR lpBuf; WORD c; WORD i = 0; DWORD dwBytesRead = 0; PCHAR lpInBuffer = new CHAR[BUFF_SIZE3]; BOOL fResult; bool ret=false; if( !lpInBuffer ) { return false; } SfuZeroMemory(lpInBuffer,BUFF_SIZE3); for(;;) { lpBuf = m_lpBuffer; for(;;) { if( i >= dwBytesRead ) { fResult = ReadFile( m_hFile, lpInBuffer, BUFF_SIZE3, &dwBytesRead, NULL ); if( fResult && dwBytesRead == 0 ) { ret = false; goto _cleanup; } i = 0; } c = lpInBuffer[i++]; if( '\r' == c ) c = lpInBuffer[i++]; if( '\n' == c ) { if( lpBuf > m_lpBuffer && lpBuf[-1] == '\\' ) { lpBuf--; continue; } break; } //if( lpBuf >= m_lpBuffer + BUFF_SIZE3 ) if( (lpBuf - m_lpBuffer) >= BUFF_SIZE3 ) { _TRACE(CDebugLevel::TRACE_DEBUGGING, "error: TERMCAP entry is way too big"); dwBytesRead =0; i = 0; break; } else *lpBuf++ = (CHAR)c; } *lpBuf = 0; if( LookForTermName( lpszTermName )) { ret = true; goto _cleanup; } } _cleanup: delete [] lpInBuffer; return ( ret ); } bool CTermCap::LookForTermName( LPSTR lpszTermName ) { if( 0 == lpszTermName ) return ( false ); _chASSERT( m_lpBuffer != 0 ); PCHAR lpName; PCHAR lpBuf = m_lpBuffer; if('#' == *lpBuf) return ( false ); for(;;) { for( lpName = lpszTermName; *lpName && toupper( *lpBuf ) == toupper( *lpName ); lpBuf++, lpName++ ) { continue; } if(*lpName == 0 && (*lpBuf == '|' || *lpBuf == ':' || *lpBuf == 0)) { return ( true ); } while(*lpBuf && *lpBuf != ':' && *lpBuf != '|') { lpBuf++; } if(*lpBuf == 0 || *lpBuf == ':') { return ( false ); } lpBuf++; } } #if 0 WORD CTermCap::GetNumber( LPCSTR lpszCapabilityName ) { if( 0 == lpszCapabilityName ) return ( ( WORD ) -1 ); _chASSERT( m_lpBuffer != 0 ); PCHAR lpBuf = m_lpBuffer; for(;;) { lpBuf = SkipToNextField( lpBuf ); if( NULL == lpBuf ) return ( ( WORD ) -1 ); if( *lpBuf++ != lpszCapabilityName[0] || *lpBuf == 0 || *lpBuf++ != lpszCapabilityName[1]) { continue; } if( *lpBuf != '#' ) return ( ( WORD ) -1 ); lpBuf++; WORD i = 0; while( isdigit( *lpBuf )) { i = i*10 + *lpBuf - '0'; lpBuf++; } return ( i ); } } #endif bool CTermCap::CheckFlag(LPCSTR lpszCapabilityName) { if( NULL == lpszCapabilityName ) return ( false ); // _chASSERT( m_lpBuffer != 0 ); PCHAR lpBuf = m_lpBuffer; for(;lpBuf;) { lpBuf = SkipToNextField( lpBuf ); if( !*lpBuf ) { break; } if( *lpBuf++ == lpszCapabilityName[0] && *lpBuf != 0 && *lpBuf++ == lpszCapabilityName[1] ) { if(!*lpBuf || *lpBuf == ':') { return ( true ); } else { break; } } } return false; } PCHAR CTermCap::SkipToNextField( PCHAR lpBuf ) { if( NULL == lpBuf ) return ( NULL ); while( *lpBuf && *lpBuf != ':' ) lpBuf++; if( *lpBuf == ':' ) lpBuf++; return ( lpBuf ); } LPSTR CTermCap::GetString( LPCSTR lpszCapabilityName ) { if( NULL == lpszCapabilityName ) return ( NULL ); // _chASSERT( m_lpBuffer != 0 ); PCHAR pBuf = m_lpBuffer; for(;pBuf;) { pBuf = SkipToNextField( pBuf ); if( !*pBuf ) return ( NULL ); if( *pBuf++ != lpszCapabilityName[0] || *pBuf == 0 || *pBuf++ != lpszCapabilityName[1] ) { continue; } if( *pBuf != '=' ) return ( NULL ); pBuf++; return ( ParseString( pBuf )); } return ( NULL ); } LPSTR CTermCap::ParseString( PCHAR pBuf ) { if( NULL == pBuf ) return ( NULL ); LPSTR lpszStr = new CHAR[25]; PCHAR p = lpszStr; WORD c; if( !lpszStr ) { return ( NULL ); } if( *pBuf != '^' ) { for( c = *pBuf++; ( c && c != ':' ); c = *pBuf++) { *p++ = (CHAR)c; } } else { //Single control character. pBuf++; *p++ = *pBuf - '@' ; } *p++ = 0; return ( lpszStr ); } // Notes: take care of other options, escapes, codes. // LPSTR CTermCap::CursorMove( LPSTR lpszCursMotionStr, WORD wHorPos, WORD wVertPos ) { if( NULL == lpszCursMotionStr ) return ( NULL ); PCHAR pCms = lpszCursMotionStr; LPSTR lpszCmsResult = new CHAR[BUFF_SIZE1]; PCHAR pCmsResult = lpszCmsResult; WORD c, wNum = 0; bool fIsColumn = false; WORD wPos = wHorPos; if( !lpszCmsResult ) { return NULL; } for( c = *pCms++; c ; c = *pCms++ ) { if( c != '%' ) { *pCmsResult++ = (CHAR)c; continue; } switch( c = *pCms++ ) { case 'd': _itoa( wPos, pCmsResult, 10 ); while( *pCmsResult != '\0' ) { pCmsResult++; } fIsColumn = !fIsColumn; wPos = fIsColumn ? wVertPos : wHorPos; continue; break; case '+': /* %. output value as in printf %c * %+x add x to value, then do %. */ wNum = ( wPos - 1 ) + *pCms++; sprintf( pCmsResult, "%c", wNum ); // NO BO here - BaskarK pCmsResult += strlen( pCmsResult ); wPos = wVertPos; break; case 'i': //wHorPos++; //wVertPos++; continue; default: delete [] lpszCmsResult; return NULL; } } *pCmsResult = 0; return ( lpszCmsResult ); } //this funtion is sort a of a kludge //if and when we decide to support //padding then we need to revisit this //piece of code. //we assume that the string sent in //conatins a padding number followed //by \E //it basically strips the padding //number in the string. //It also substitutes \033 for \E void CTermCap::ProcessString( LPSTR* lplpszStr ) { LPSTR lpszStr = *lplpszStr; if(lpszStr == NULL) { return; } PCHAR pStr = new char[ strlen( lpszStr ) + 2 ]; if( !pStr ) { return; } strcpy( pStr, "\033" ); // NO BO - Baskar PCHAR pChar = lpszStr; //strip padding while( (*pChar != '\0') && isdigit( *pChar ) ) { pChar++; } //strip \E if(*pChar != '\0' ) { pChar++; if (*pChar != '\0' ) pChar++; } strcat( pStr, pChar ); delete [] lpszStr; *lplpszStr = pStr; }