📄 main.cpp
字号:
// _screen.SetColor(wOriginalAttr);
return(0);
}
void SendText(const char *pszText, BOOL bAppendCR)
{
if (!_bConnected)
{
PrintMessage("No Session Active.");
return;
}
if (!_bUsingModem)
{
int nNumSent = send(_hActiveSocket,pszText,strlen(pszText),0);
if (nNumSent == SOCKET_ERROR)
{
PrintError();
return;
}
if (bAppendCR)
{
if (send(_hActiveSocket,"\r\n",2,0) == SOCKET_ERROR)
{
PrintError();
return;
}
}
}
else
{
int nNumSent = _modem.Send(pszText);
if (!nNumSent)
{
// have an error.
return;
}
if (bAppendCR)
{
if (!_modem.Send("\r\n"))
{
// have an error.
return;
}
}
}
}
extern "C" void DllCallback(const char *pszText)
{
CString strText;
strText = pszText;
_debugStack.Push(0,STACK_TYPE_DLL_CALLBACK);
HandleInput(strText);
_debugStack.Pop();
}
void HandleInput(CString &strLine)
{
if (strLine.IsEmpty())
{
if (_config.bEcho)
{
BOOL bActionsState = _terminal.ActionsState();
if (bActionsState)
_terminal.ActionsOff();
_terminal.Print("\n");
if (bActionsState)
_terminal.ActionsOn();
_tiUserInput.SetFocus();
}
SendText("\r\n",FALSE);
return;
}
if (strLine.GetAt(0) == '!')
strLine = _strLastLine;
int nLen = strLine.GetLength();
// If the first character is a the command char, and the next
// character is a digit, then it is a line to be repeated.
if (strLine.GetAt(0) == _config.chCommand && nLen > 2 && isdigit(strLine.GetAt(1)))
{
int nIndex = strLine.Find(' ');
if (nIndex != -1)
{
CString strTemp(strLine.Right(nLen-nIndex-1));
CString strText;
int nReps = atoi(((const char *)strLine)+1);
for (int i=0;i<nReps;i++)
{
// have to keep copying it in fresh because I'm passing
// the CStrings by value to keep from having to copy
// them over and over to work with them. But this means
// the contents of the string passed down can and will
// be corrupted by the time it gets back.
strText = strTemp;
HandleInput(strText);
}
return;
}
else
{
PrintMessage("Invalid Command.",TRUE,TRUE);
_debugStack.DumpStack(_config.nDebugDepth);
return;
}
}
CString strTemp;
int nStatementCount = 0;
int nIndex = 0;
while(nIndex < nLen)
{
if (strLine[nIndex] == _config.chBlockStart)
nStatementCount++;
if (strLine[nIndex] == _config.chBlockEnd)
nStatementCount--;
// Check for the escape character.
if (strLine[nIndex] == _config.chEscape)
{
// Need to check and see what next character is.
// Make sure there is still 1 more to read.
nIndex++;
if (nIndex < nLen)
{
if (strLine[nIndex] == _config.chEscape)
strTemp += _config.chEscape;
else
if (strLine[nIndex] == _config.chSeparator)
strTemp += _config.chSeparator;
else
{
strTemp += _config.chEscape;
strTemp += strLine[nIndex];
}
}
else
strTemp += _config.chEscape;
nIndex++;
continue;
}
// Only process a semi-colon if not within a statement block.
if (strLine[nIndex] == _config.chSeparator && !nStatementCount)
{
if (!strTemp.IsEmpty())
{
if (strTemp.GetLength() > 2 && strTemp.GetAt(0) == _config.chCommand && isdigit(strTemp.GetAt(1)))
HandleInput(strTemp);
else
ProcessLine(strTemp);
strTemp.Empty();
}
nIndex++;
continue;
}
strTemp += strLine[nIndex];
nIndex++;
}
if (!strTemp.IsEmpty())
{
if (strTemp.GetLength() > 2 && strTemp.GetAt(0) == _config.chCommand && isdigit(strTemp.GetAt(1)))
HandleInput(strTemp);
else
ProcessLine(strTemp);
}
}
void FindStatement(CString &strText, CString &strResult)
{
strResult.Empty();
strText.TrimRight();
strText.TrimLeft();
if (strText.IsEmpty())
return;
char chEndChar = _config.chBlockEnd;
char chStartChar = _config.chBlockStart;
int nBlockCount = 0;
if (strText[0] != _config.chBlockStart)
{
chEndChar = ' ';
chStartChar = ' ';
// If we are using spaces for parameter separators we
// need to start it at one since we will never encounter
// a starting space.
nBlockCount = 1;
}
char ch;
int nProcCount = 0;
int nIndex = 0;
int nLen = strText.GetLength();
while(nIndex < nLen)
{
ch = strText[nIndex];
if (ch == _config.chEscape && nIndex+1 < nLen && strText[nIndex+1] == '@')
{
strResult += "\\@";
nIndex += 2;
continue;
}
// Need to watch for procedures. Each time we find a procedure
// we need to look for a matched set of parens.
if (ch == '@')
{
nProcCount++;
nIndex++;
strResult += ch;
continue;
}
// If the user wants to print a closing paren while inside
// a procedure definition, they need to use the escape char.
if (ch == _config.chEscape && nIndex+1 < nLen && strText[nIndex+1] == ')')
{
strResult += "\\)";
nIndex++;
continue;
}
if (ch == ')' && nProcCount)
nProcCount--;
if (ch == chEndChar && !nProcCount)
{
nBlockCount--;
if (!nBlockCount)
break;
}
// If this is the first block symbol we need to skip over it, it should not
// be part of our result string.
if (ch == chStartChar && !nBlockCount)
{
nBlockCount++;
nIndex++;
continue;
}
if (ch == chStartChar && !nProcCount)
nBlockCount++;
strResult += ch;
nIndex++;
}
if (nIndex+1 < nLen)
strText = strText.Right(nLen-nIndex-1);
else
strText.Empty();
}
void ProcessLine(CString &strLine)
{
if (strLine.IsEmpty())
return;
if ((strLine[0] != _config.chCommand && strLine[0] != '@') ||
(strLine[0] == _config.chCommand && strLine[1] == _config.chCommand))
{
// Get rid of the first command char if doubled up.
if (strLine[0] == _config.chCommand && strLine[1] == _config.chCommand)
strLine = strLine.Right(strLine.GetLength()-1);
ReplaceVariables(strLine);
if (!_config.bIgnoreAliases)
{
ALIAS_MAP *pMap = _aliases.FindMatch(strLine);
if (pMap != NULL)
{
CString strText(pMap->strText);
_debugStack.Push(_aliases.GetFindIndex(),STACK_TYPE_ALIAS);
HandleInput(strText);
_debugStack.Pop();
return;
}
}
if (_config.bSpeedWalk && strLine.GetLength() > 1 && IsWalkable(strLine))
{
DoSpeedWalk(strLine);
return;
}
if (_config.bEcho)
{
BOOL bActionsState = _terminal.ActionsState();
if (bActionsState)
_terminal.ActionsOff();
_terminal.Print(strLine+"\n");
if (bActionsState)
_terminal.ActionsOn();
_tiUserInput.SetFocus();
}
// For the aliases that take a parameter and no param is passed
// I think the trailing spaces are upsetting the mud. So trim
// the string first.
strLine.TrimRight();
if (strLine.IsEmpty())
SendText("\r\n",FALSE);
else
SendText(strLine);
return;
}
if (strLine[0] == '@')
{
if (DoProcedure(strLine))
return;
ReplaceVariables(strLine);
CString strTemp(strLine);
HandleInput(strTemp);
return;
}
// Must have a space between the command and the first {
CString strCommand;
int nIndex = strLine.Find(' ');
if (nIndex == -1)
{
strCommand = ((const char *)strLine)+1;
strLine.Empty();
}
else
{
strCommand = strLine.Mid(1,nIndex-1);
strLine = strLine.Right(strLine.GetLength()-nIndex-1);
}
strCommand.MakeLower();
const char *pszCommand = (const char *)strCommand;
HASHITEM *phi = _htCommands[*pszCommand];
if (!phi || phi->nStart == HASHITEM_EMPTY || phi->nEnd == HASHITEM_EMPTY)
{
PrintMessage("Invalid Command.",TRUE,TRUE);
_debugStack.DumpStack(_config.nDebugDepth);
return;
}
for (int i=phi->nStart;i<=phi->nEnd && _commandList[i].proc;i++)
{
if (!_commandList[i].bWholeMatch)
{
if (IsPartial(pszCommand,_commandList[i].szCommand))
{
(_commandList[i].proc)(strLine);
return;
}
}
else
{
// Complete text match only. Used to protect sensitive commands
// from being accidentally triggered.
if (!strcmp(pszCommand,_commandList[i].szCommand))
{
(_commandList[i].proc)(strLine);
return;
}
}
}
PrintMessage("Invalid Command.",TRUE,TRUE);
_debugStack.DumpStack(_config.nDebugDepth);
}
void GetSocketError(CString &strError)
{
long lError = WSAGetLastError();
switch(lError)
{
case WSAECONNREFUSED :
strError = "Connection Refused";
break;
case WSAENETUNREACH :
strError = "Host Unreachable";
break;
case WSAETIMEDOUT :
strError = "Connection Timed Out";
break;
case WSAEISCONN :
strError = "Already Connected";
break;
case WSAEWOULDBLOCK :
strError = "Would Block";
break;
case WSANOTINITIALISED :
strError = "WSAStartup Not Called";
break;
case WSAENETDOWN :
strError = "Network Subsytem Failed";
break;
case WSAEADDRNOTAVAIL :
strError = "Host Unreachable";
break;
case WSAECONNRESET :
strError = "Connect Reset by Remote Host";
break;
case WSAEADDRINUSE :
strError = "Address already in use.";
break;
default :
strError.Format("Unknown (%ld)",lError);
break;
}
}
void Connect(const char *pszName, const char *pszAddress, const char *pszPort)
{
if (_bConnected)
{
PrintMessage("Already Connected.");
return;
}
SOCKADDR_IN sockAddr;
memset(&sockAddr,0,sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = inet_addr(pszAddress);
sockAddr.sin_port = htons((u_short)atoi(pszPort));
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
{
CString strMessage("Looking up host: ");
strMessage += pszAddress;
strMessage += "...";
PrintMessage(strMessage);
LPHOSTENT lphost;
lphost = gethostbyname(pszAddress);
if (lphost != NULL)
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
else
{
PrintMessage("Error: Unable to find host.");
return;
}
}
// Get a socket handle.
_hActiveSocket = socket(PF_INET,SOCK_STREAM,0);
if (_hActiveSocket == INVALID_SOCKET)
{
PrintMessage("Error: Unable to get a socket handle.");
return;
}
// Make sure it is a non-blocking socket.
unsigned long lNonBlocking = 1;
ioctlsocket(_hActiveSocket,FIONBIO,&lNonBlocking);
CString strMessage("Connecting to ");
strMessage += pszAddress;
strMessage += " (ESC to abort) ...";
PrintMessage(strMessage);
int nResult = connect(_hActiveSocket,(SOCKADDR*)&sockAddr, sizeof(sockAddr));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -