/* * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * In addition, as a special exception, the author gives permission to * link the code of this program with the Half-Life Game Engine ("HL * Engine") and Modified Game Libraries ("MODs") developed by Valve, * L.L.C ("Valve"). You must obey the GNU General Public License in all * respects for all of the code used other than the HL Engine and MODs * from Valve. If you modify this file, you may extend this exception * to your version of the file, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. * */ #include "precompiled.h" bool CTextConsole::Init(IBaseSystem *system) { // NULL or a valid base system interface m_System = system; Q_memset(m_szConsoleText, 0, sizeof(m_szConsoleText)); m_nConsoleTextLen = 0; m_nCursorPosition = 0; Q_memset(m_szSavedConsoleText, 0, sizeof(m_szSavedConsoleText)); m_nSavedConsoleTextLen = 0; Q_memset(m_aszLineBuffer, 0, sizeof(m_aszLineBuffer)); m_nTotalLines = 0; m_nInputLine = 0; m_nBrowseLine = 0; // these are log messages, not related to console Sys_Printf("\n"); Sys_Printf("Console initialized.\n"); m_ConsoleVisible = true; return true; } void CTextConsole::InitSystem(IBaseSystem *system) { m_System = system; } void CTextConsole::SetVisible(bool visible) { m_ConsoleVisible = visible; } bool CTextConsole::IsVisible() { return m_ConsoleVisible; } void CTextConsole::ShutDown() { ; } void CTextConsole::Print(char *pszMsg) { if (m_nConsoleTextLen) { int nLen = m_nConsoleTextLen; while (nLen--) { PrintRaw("\b \b"); } } PrintRaw(pszMsg); if (m_nConsoleTextLen) { PrintRaw(m_szConsoleText, m_nConsoleTextLen); } UpdateStatus(); } int CTextConsole::ReceiveNewline() { int nLen = 0; Echo("\n"); if (m_nConsoleTextLen) { nLen = m_nConsoleTextLen; m_szConsoleText[ m_nConsoleTextLen ] = '\0'; m_nConsoleTextLen = 0; m_nCursorPosition = 0; // cache line in buffer, but only if it's not a duplicate of the previous line if ((m_nInputLine == 0) || (Q_strcmp(m_aszLineBuffer[ m_nInputLine - 1 ], m_szConsoleText))) { Q_strncpy(m_aszLineBuffer[ m_nInputLine ], m_szConsoleText, MAX_CONSOLE_TEXTLEN); m_nInputLine++; if (m_nInputLine > m_nTotalLines) m_nTotalLines = m_nInputLine; if (m_nInputLine >= MAX_BUFFER_LINES) m_nInputLine = 0; } m_nBrowseLine = m_nInputLine; } return nLen; } void CTextConsole::ReceiveBackspace() { int nCount; if (m_nCursorPosition == 0) { return; } m_nConsoleTextLen--; m_nCursorPosition--; Echo("\b"); for (nCount = m_nCursorPosition; nCount < m_nConsoleTextLen; ++nCount) { m_szConsoleText[ nCount ] = m_szConsoleText[ nCount + 1 ]; Echo(m_szConsoleText + nCount, 1); } Echo(" "); nCount = m_nConsoleTextLen; while (nCount >= m_nCursorPosition) { Echo("\b"); nCount--; } m_nBrowseLine = m_nInputLine; } void CTextConsole::ReceiveTab() { if (!m_System) return; ObjectList matches; m_szConsoleText[ m_nConsoleTextLen ] = '\0'; m_System->GetCommandMatches(m_szConsoleText, &matches); if (matches.IsEmpty()) return; if (matches.CountElements() == 1) { char *pszCmdName = (char *)matches.GetFirst(); char *pszRest = pszCmdName + Q_strlen(m_szConsoleText); if (pszRest) { Echo(pszRest); Q_strlcat(m_szConsoleText, pszRest); m_nConsoleTextLen += Q_strlen(pszRest); Echo(" "); Q_strlcat(m_szConsoleText, " "); m_nConsoleTextLen++; } } else { int nLongestCmd = 0; int nSmallestCmd = 0; int nCurrentColumn; int nTotalColumns; char szCommonCmd[256]; // Should be enough. char szFormatCmd[256]; char *pszSmallestCmd; char *pszCurrentCmd = (char *)matches.GetFirst(); nSmallestCmd = Q_strlen(pszCurrentCmd); pszSmallestCmd = pszCurrentCmd; while (pszCurrentCmd) { if ((int)Q_strlen(pszCurrentCmd) > nLongestCmd) { nLongestCmd = Q_strlen(pszCurrentCmd); } if ((int)Q_strlen(pszCurrentCmd) < nSmallestCmd) { nSmallestCmd = Q_strlen(pszCurrentCmd); pszSmallestCmd = pszCurrentCmd; } pszCurrentCmd = (char *)matches.GetNext(); } nTotalColumns = (GetWidth() - 1) / (nLongestCmd + 1); nCurrentColumn = 0; Echo("\n"); Q_strcpy(szCommonCmd, pszSmallestCmd); // Would be nice if these were sorted, but not that big a deal pszCurrentCmd = (char *)matches.GetFirst(); while (pszCurrentCmd) { if (++nCurrentColumn > nTotalColumns) { Echo("\n"); nCurrentColumn = 1; } Q_snprintf(szFormatCmd, sizeof(szFormatCmd), "%-*s ", nLongestCmd, pszCurrentCmd); Echo(szFormatCmd); for (char *pCur = pszCurrentCmd, *pCommon = szCommonCmd; (*pCur && *pCommon); pCur++, pCommon++) { if (*pCur != *pCommon) { *pCommon = 0; break; } } pszCurrentCmd = (char *)matches.GetNext(); } Echo("\n"); if (Q_strcmp(szCommonCmd, m_szConsoleText)) { Q_strcpy(m_szConsoleText, szCommonCmd); m_nConsoleTextLen = Q_strlen(szCommonCmd); } Echo(m_szConsoleText); } m_nCursorPosition = m_nConsoleTextLen; m_nBrowseLine = m_nInputLine; } void CTextConsole::ReceiveStandardChar(const char ch) { int nCount; // If the line buffer is maxed out, ignore this char if (m_nConsoleTextLen >= (sizeof(m_szConsoleText) - 2)) { return; } nCount = m_nConsoleTextLen; while (nCount > m_nCursorPosition) { m_szConsoleText[ nCount ] = m_szConsoleText[ nCount - 1 ]; nCount--; } m_szConsoleText[ m_nCursorPosition ] = ch; Echo(m_szConsoleText + m_nCursorPosition, m_nConsoleTextLen - m_nCursorPosition + 1); m_nConsoleTextLen++; m_nCursorPosition++; nCount = m_nConsoleTextLen; while (nCount > m_nCursorPosition) { Echo("\b"); nCount--; } m_nBrowseLine = m_nInputLine; } void CTextConsole::ReceiveUpArrow() { int nLastCommandInHistory = m_nInputLine + 1; if (nLastCommandInHistory > m_nTotalLines) nLastCommandInHistory = 0; if (m_nBrowseLine == nLastCommandInHistory) return; if (m_nBrowseLine == m_nInputLine) { if (m_nConsoleTextLen > 0) { // Save off current text Q_strncpy(m_szSavedConsoleText, m_szConsoleText, m_nConsoleTextLen); // No terminator, it's a raw buffer we always know the length of } m_nSavedConsoleTextLen = m_nConsoleTextLen; } m_nBrowseLine--; if (m_nBrowseLine < 0) { m_nBrowseLine = m_nTotalLines - 1; } // delete old line while (m_nConsoleTextLen--) { Echo("\b \b"); } // copy buffered line Echo(m_aszLineBuffer[ m_nBrowseLine ]); Q_strncpy(m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN); m_nConsoleTextLen = Q_strlen(m_aszLineBuffer[ m_nBrowseLine ]); m_nCursorPosition = m_nConsoleTextLen; } void CTextConsole::ReceiveDownArrow() { if (m_nBrowseLine == m_nInputLine) return; if (++m_nBrowseLine > m_nTotalLines) m_nBrowseLine = 0; // delete old line while (m_nConsoleTextLen--) { Echo("\b \b"); } if (m_nBrowseLine == m_nInputLine) { if (m_nSavedConsoleTextLen > 0) { // Restore current text Q_strncpy(m_szConsoleText, m_szSavedConsoleText, m_nSavedConsoleTextLen); // No terminator, it's a raw buffer we always know the length of Echo(m_szConsoleText, m_nSavedConsoleTextLen); } m_nConsoleTextLen = m_nSavedConsoleTextLen; } else { // copy buffered line Echo(m_aszLineBuffer[ m_nBrowseLine ]); Q_strncpy(m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN); m_nConsoleTextLen = Q_strlen(m_aszLineBuffer[ m_nBrowseLine ]); } m_nCursorPosition = m_nConsoleTextLen; } void CTextConsole::ReceiveLeftArrow() { if (m_nCursorPosition == 0) return; Echo("\b"); m_nCursorPosition--; } void CTextConsole::ReceiveRightArrow() { if (m_nCursorPosition == m_nConsoleTextLen) return; Echo(m_szConsoleText + m_nCursorPosition, 1); m_nCursorPosition++; }