Files
2026-06-01 12:46:52 +02:00

274 lines
5.2 KiB
C++

#pragma once
// 가상 콘솔.
//
// 일정 크기의 버퍼를 가지고 있고 거기다 Printf() 로 찍어댈수 있으며,
// 화면 출력을 위해 ScreenXXX() 계열 함수를 지원한다.
//
// . _cprint( "blah blah" ); 라고 하면 언제 어디에서나 찍을 수 있다.
//
// 2004/02/14
// by Testors
#include <cstdio>
#include <cstdarg>
#include "ILock.h"
class XConsole
{
public:
XConsole( int nWidth = 120, int nHeight = 50 ) : m_Lock( "XConsole" )
{
m_nWidth = nWidth;
m_nScreenHeight = m_nHeight = nHeight;
bIsFull = false;
m_nCount = 0;
m_nNewAdjust = m_nScreenAdjust = 0;
m_pLines = new char*[nHeight];
for ( int i = 0; i < nHeight; i++ )
{
m_pLines[i] = new char[nWidth+1];
memset( m_pLines[i], 0, sizeof( char ) * (nWidth+1) );
}
m_nX = m_nY = 0;
}
~XConsole()
{
for ( int i = 0; i < m_nHeight; i++ ) delete [] m_pLines[i];
delete [] m_pLines;
}
void Write( const char *str )
{
_Printf( str );
}
void Printf( const char *str, ... )
{
THREAD_SYNCHRONIZE( &m_Lock );
char szBuf[2048];
va_list va;
va_start( va, str );
s_vsprintf( szBuf, _countof(szBuf), str, va );
va_end( va );
_Printf( szBuf );
}
void PrintfWithTimestamp( const char *str, ... )
{
THREAD_SYNCHRONIZE( &m_Lock );
char szBuf[2048];
SYSTEMTIME st;
GetLocalTime( &st );
int nWrittenCount = s_sprintf( szBuf, _countof( szBuf ), "%04d/%02d/%02d %02d:%02d:%02d ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
va_list va;
va_start( va, str );
s_vsprintf( szBuf + nWrittenCount, _countof(szBuf) - nWrittenCount, str, va );
va_end( va );
_Printf( szBuf );
}
const char* GetLine( unsigned line )
{
m_Lock.Lock();
if ( line > (unsigned)m_nHeight )
{
m_Lock.UnLock();
return "~";
}
int nl = line;
if ( bIsFull )
{
nl = m_nY + line;
nl %= m_nHeight;
}
m_Lock.UnLock();
return m_pLines[nl];
}
int GetWidth() const { return m_nWidth; };
int GetHeight() const { return m_nHeight; };
// 현재 저장중인 라인 수를 리턴
int GetCount() const { return m_nCount; }
void SetScreenHeight( unsigned height ) { m_nScreenHeight = height; };
int GetScreenHeight() const { return m_nScreenHeight; };
void ScreenUp() { onScreenPos( m_nScreenAdjust - 1 ); }
void ScreenDown() { onScreenPos( m_nScreenAdjust + 1 ); }
void ScreenPageUp() { onScreenPos( m_nScreenAdjust - m_nScreenHeight / 3 ); }
void ScreenPageDown() { onScreenPos( m_nScreenAdjust + m_nScreenHeight / 3 ); }
void ScreenHome() { onScreenPos( 0 - m_nCount + m_nScreenHeight - 1 ); }
void ScreenEnd() { m_nScreenAdjust = 0; }
const char* GetScreenLine( unsigned l ) { return GetLine( l + m_nScreenAdjust ); }
void Clear()
{
m_nCount = 0;
for ( int i = 0; i < m_nHeight; i++ ) m_pLines[i][0] = 0;
m_nX = m_nY = 0;
bIsFull = false;
}
static XConsole & Inst( const char *szFileName = NULL );
static XConsole & ErrorInst( const char *szFileName = NULL );
private:
XConsole( const XConsole& );
XConsole& operator=( const XConsole& );
private:
int m_nCount;
int m_nWidth, m_nHeight;
int m_nX, m_nY;
bool bIsFull;
int m_nScreenHeight;
int m_nScreenAdjust;
int m_nNewAdjust;
void _Printf( const char *szBuf )
{
unsigned feed;
char *p = const_cast< char* >( szBuf );
char *sp = p;
for ( ;;*p++)
{
if ( *p == '\n' )
{
feed = putString( sp, (unsigned)(p - sp) );
sp = p;
addY();
m_pLines[m_nY][0] = 0;
if ( feed )
{
sp -= feed;
_Printf( sp );
return;
}
sp++;
continue;
}
if ( !*p )
{
if ( p - sp )
{
feed = putString( sp, (unsigned)(p - sp) );
if ( feed )
{
addY();
_Printf( sp + feed );
}
}
break;
}
}
}
unsigned putString( const char *str, unsigned len )
{
int y = m_nY;
unsigned newlen = len;
if ( m_nX + len >= (unsigned)m_nWidth )
{
newlen = m_nWidth - m_nX;
}
s_strncpy( &m_pLines[y][m_nX], (m_nWidth-m_nX)+1, str, newlen );
m_nX += len;
return len - newlen;
}
void addY()
{
m_nX = 0;
if ( ++m_nY == m_nHeight )
{
m_nY = 0;
bIsFull = true;
}
if ( m_nCount < m_nHeight ) ++m_nCount;
}
void onScreenPos( int nNewAdjust )
{
m_Lock.Lock();
// 위로 튕기는것
if ( m_nCount - m_nScreenHeight + nNewAdjust < 0 )
{
nNewAdjust = 0 - m_nCount + m_nScreenHeight - 1;
}
// 아래로 튕기는것
if ( nNewAdjust > 0 ) nNewAdjust = 0;
m_nScreenAdjust = nNewAdjust;
m_Lock.UnLock();
}
XCriticalSection m_Lock;
char **m_pLines;
};
#define _cprint XConsole::Inst().Printf
#define _ctprint XConsole::Inst().PrintfWithTimestamp
inline void _lprint( const char *szFileName, const char *str, ... )
{
FILE *fp = NULL;
if( fopen_s( &fp, szFileName, "a+" ) != 0 )
{
return;
}
if ( !fp ) return;
char szBuf[2048];
va_list va;
va_start( va, str );
s_vsprintf( szBuf, _countof(szBuf), str, va );
va_end( va );
// print time
SYSTEMTIME st;
GetLocalTime( &st );
fprintf( fp, "%04d/%02d/%02d %02d:%02d:%02d ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
fwrite( szBuf, strlen( szBuf ), 1, fp );
XConsole::Inst().Write( szBuf );
fclose( fp );
}