#include "console.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
/*****************************************************************************
* CConsole *
*****************************************************************************/
CConsole::CConsole()
{
m_refs = 0;
m_con_x = 0;
m_con_y = 0;
m_width = m_height = 0;
m_attrib = 0x0700;
m_esc = 0;
}
// IUnknown methods
HRESULT CConsole::QueryInterface(REFIID iid, void ** ppvObject)
{
//wprintf(L"QI");
if (InlineIsEqualGUID(iid, IID_IUnknown) ||
InlineIsEqualGUID(iid, IID_IDevice))
{
//wprintf(L"(IDevice)\n");
AddRef();
*ppvObject = (IDevice*) this;
return S_OK;
}
else if (InlineIsEqualGUID(iid, IID_IStream))
{
//wprintf(L"(IStream)\n");
AddRef();
*ppvObject = (IStream*) new CStream(this);
return S_OK;
}
/*wprintf(L"(fail) %p %p {%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x} %p\n",
this,
iid.Data1, iid.Data2, iid.Data3,
iid.Data4[0],
iid.Data4[1],
iid.Data4[2],
iid.Data4[3],
iid.Data4[4],
iid.Data4[5],
iid.Data4[6],
iid.Data4[7],
ppvObject);*/
*ppvObject = NULL;
return E_FAIL;
}
ULONG CConsole::AddRef()
{
return ++m_refs;
}
ULONG CConsole::Release()
{
if (m_refs == 0)
{
delete this;
return 0;
}
else
return --m_refs;
}
// IDevice method
HRESULT CConsole::GetInfo(device_t* buf)
{
if (buf->size < sizeof(device_t))
return E_FAIL;
wcscpy(buf->name, L"Console");
return S_OK;
}
HRESULT CConsole::DeviceOpen()
{
return S_OK;
}
void CConsole::WriteCharacter(dword mode, wchar_t c)
{
if (mode == ioRaw)
{
Output(m_con_x, m_con_y, c, 0);
m_con_x++;
if (m_con_x >= m_width)
{
m_con_x = 0;
m_con_y++;
}
}
else
{
if (m_esc == 1)
{
if (c == L'[')
{
m_esc++;
m_esc1 = 0;
return;
}
}
else if (m_esc == 2)
{
if (iswdigit(c))
{
m_esc1 = m_esc1 * 10 + c - L'0';
return;
}
else if (c == ';')
{
m_esc++;
m_esc2 = 0;
return;
}
else if (c == 'J')
{
if (m_esc1 == 2)
Clear();
}
else if (c == 'm')
SetAttrib(m_esc1);
m_esc = 0;
return;
}
else if (m_esc == 3)
{
if (iswdigit(c))
{
m_esc2 = m_esc2 * 10 + c - '0';
return;
}
else if(c == ';')
{
m_esc++; /* ESC[num1;num2; */
m_esc3 = 0;
return;
}
/* ESC[num1;num2H -- move cursor to num1,num2 */
else if(c == 'H')
{
if(m_esc2 < m_width)
m_con_x = m_esc2;
if(m_esc1 < m_height)
m_con_y = m_esc1;
}
/* ESC[num1;num2m -- set attributes num1,num2 */
else if(c == 'm')
{
SetAttrib(m_esc1);
SetAttrib(m_esc2);
}
m_esc = 0;
return;
}
/* ESC[num1;num2;num3 */
else if(m_esc == 4)
{
if (iswdigit(c))
{
m_esc3 = m_esc3 * 10 + c - '0';
return;
}
/* ESC[num1;num2;num3m -- set attributes num1,num2,num3 */
else if(c == 'm')
{
SetAttrib(m_esc1);
SetAttrib(m_esc2);
SetAttrib(m_esc3);
}
m_esc = 0;
return;
}
m_esc = 0;
switch (c)
{
case L'\n':
m_con_x = 0;
m_con_y++;
break;
case L'\r':
m_con_x = 0;
break;
case L'\t':
m_con_x = (m_con_x + 4) & ~3;
break;
case L'\b':
if (m_con_x > 0)
m_con_x--;
break;
case 27:
m_esc = 1;
break;
default:
Output(m_con_x, m_con_y, c, m_attrib);
m_con_x++;
if (m_con_x >= m_width)
{
m_con_x = 0;
m_con_y++;
}
}
}
while (m_con_y >= m_height)
{
m_con_y--;
Scroll(0, -1);
}
}
void CConsole::SetAttrib(byte att)
{
static const char ansi_to_vga[] =
{
0, 4, 2, 6, 1, 5, 3, 7
};
unsigned char new_att;
new_att = m_attrib >> 8;
if(att == 0)
new_att &= ~0x08; /* bold off */
else if(att == 1)
new_att |= 0x08; /* bold on */
else if(att >= 30 && att <= 37)
{
att = ansi_to_vga[att - 30];
new_att = (new_att & ~0x07) | att;/* fg color */
}
else if(att >= 40 && att <= 47)
{
att = ansi_to_vga[att - 40] << 4;
new_att = (new_att & ~0x70) | att;/* bg color */
}
m_attrib = new_att << 8;
}
/*****************************************************************************
* CConsole::CStream *
*****************************************************************************/
CConsole::CStream::CStream(CConsole* con)
{
m_con = con;
m_con->AddRef();
m_mode = ioUnicode;
m_refs = 0;
}
CConsole::CStream::~CStream()
{
if (m_con)
m_con->Release();
}
// IUnknown methods
HRESULT CConsole::CStream::QueryInterface(REFIID iid, void ** ppvObject)
{
//wprintf(L"QI");
if (InlineIsEqualGUID(iid, IID_IUnknown) ||
InlineIsEqualGUID(iid, IID_IStream))
{
//wprintf(L"(IDevice)\n");
AddRef();
*ppvObject = (IStream*) this;
return S_OK;
}
else if (InlineIsEqualGUID(iid, IID_IDevice))
{
//wprintf(L"(IStream)\n");
m_con->AddRef();
*ppvObject = (IDevice*) m_con;
return S_OK;
}
//wprintf(L"(fail)\n");
*ppvObject = NULL;
return E_FAIL;
}
ULONG CConsole::CStream::AddRef()
{
return ++m_refs;
}
ULONG CConsole::CStream::Release()
{
if (m_refs == 0)
{
delete this;
return 0;
}
else
return --m_refs;
}
// IStream methods
size_t CConsole::CStream::Read(void* buffer, size_t length)
{
return 0;
}
size_t CConsole::CStream::Write(const void* buffer, size_t length)
{
word* ch;
size_t written = 0;
for (ch = (word*) buffer; written < length; )
{
switch (m_mode)
{
case ioRaw:
case ioUnicode:
m_con->WriteCharacter(m_mode, *ch);
ch++;
written += sizeof(wchar_t);
break;
case ioAnsi:
m_con->WriteCharacter(m_mode, (char) *ch);
ch = (word*) ((char*) ch + 1);
written += sizeof(char);
break;
}
}
m_con->UpdateCursor();
return written;
}
HRESULT CConsole::CStream::SetIoMode(dword mode)
{
m_mode = mode;
return S_OK;
}
HRESULT CConsole::CStream::IsReady()
{
return S_OK;
}
HRESULT CConsole::CStream::Stat(folderitem_t* buf)
{
return E_FAIL;
}
HRESULT CConsole::CStream::Seek(long offset, int origin)
{
return E_FAIL;
}