You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
496 lines
11 KiB
496 lines
11 KiB
// TermCap.cpp : This file contains the
|
|
// Created: Dec '97
|
|
// Author : a-rakeba
|
|
// History:
|
|
// Copyright (C) 1997 Microsoft Corporation
|
|
// All rights reserved.
|
|
// Microsoft Confidential
|
|
|
|
|
|
#include <StdLib.h>
|
|
#include <Debug.h>
|
|
#include <DbgLvl.h>
|
|
#include <TermCap.h>
|
|
#include <w4warn.h>
|
|
#include <TelnetD.h>
|
|
#include <TlntUtils.h>
|
|
|
|
|
|
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;
|
|
}
|