forked from FWGS/Paranoia2
312 lines
6.4 KiB
C++
312 lines
6.4 KiB
C++
/*
|
|
conprint.cpp - extended printf function that allows
|
|
colored printing scheme from Quake3
|
|
Copyright (C) 2012 Uncle Mike
|
|
|
|
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 3 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.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "basetypes.h"
|
|
#include "stringlib.h"
|
|
#include "conprint.h"
|
|
#include "stdarg.h"
|
|
#include <time.h>
|
|
|
|
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
|
|
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
|
|
static unsigned short g_color_table[8] =
|
|
{
|
|
FOREGROUND_INTENSITY, // black
|
|
FOREGROUND_RED|FOREGROUND_INTENSITY, // red
|
|
FOREGROUND_GREEN|FOREGROUND_INTENSITY, // green
|
|
FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY, // yellow
|
|
FOREGROUND_BLUE|FOREGROUND_INTENSITY, // blue
|
|
FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY, // cyan
|
|
FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY, // magenta
|
|
FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE, // default color (white)
|
|
};
|
|
#endif
|
|
|
|
static int devloper_level = DEFAULT_DEVELOPER;
|
|
static bool ignore_log = false;
|
|
static FILE *logfile = NULL;
|
|
|
|
void SetDeveloperLevel( int level )
|
|
{
|
|
if( level < D_INFO ) return; // debug messages disabled
|
|
if( level > D_NOTE ) level = D_NOTE;
|
|
devloper_level = level;
|
|
}
|
|
|
|
int GetDeveloperLevel( void )
|
|
{
|
|
return devloper_level;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
SYSTEM LOG
|
|
|
|
===============================================================================
|
|
*/
|
|
void Sys_InitLog( const char *logname )
|
|
{
|
|
logfile = fopen( logname, "w" );
|
|
if( !logfile ) MsgDev( D_ERROR, "Sys_InitLog: can't create log file %s\n", logname );
|
|
}
|
|
|
|
void Sys_InitLogAppend( const char *logname )
|
|
{
|
|
logfile = fopen( logname, "a+" );
|
|
if( !logfile ) MsgDev( D_ERROR, "Sys_InitLog: can't create log file %s\n", logname );
|
|
}
|
|
|
|
void Sys_IgnoreLog( bool ignore )
|
|
{
|
|
ignore_log = ignore;
|
|
}
|
|
|
|
void Sys_CloseLog( void )
|
|
{
|
|
if( !logfile ) return;
|
|
fclose( logfile );
|
|
logfile = NULL;
|
|
}
|
|
|
|
void Sys_PrintLog( const char *pMsg )
|
|
{
|
|
if( !pMsg || ignore_log )
|
|
return;
|
|
|
|
time_t crt_time;
|
|
const struct tm *crt_tm;
|
|
char logtime[32] = "";
|
|
static char lastchar;
|
|
|
|
time( &crt_time );
|
|
crt_tm = localtime( &crt_time );
|
|
|
|
#ifdef __ANDROID__
|
|
__android_log_print( ANDROID_LOG_DEBUG, "Xash", "%s", pMsg );
|
|
#endif
|
|
|
|
if( !lastchar || lastchar == '\n')
|
|
strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); //short time
|
|
|
|
#ifdef COLORIZE_CONSOLE
|
|
{
|
|
char colored[4096];
|
|
const char *msg = pMsg;
|
|
int len = 0;
|
|
while( *msg && ( len < 4090 ) )
|
|
{
|
|
static char q3ToAnsi[ 8 ] =
|
|
{
|
|
'0', // COLOR_BLACK
|
|
'1', // COLOR_RED
|
|
'2', // COLOR_GREEN
|
|
'3', // COLOR_YELLOW
|
|
'4', // COLOR_BLUE
|
|
'6', // COLOR_CYAN
|
|
'5', // COLOR_MAGENTA
|
|
0 // COLOR_WHITE
|
|
};
|
|
|
|
if( IsColorString( msg ) )
|
|
{
|
|
int color;
|
|
|
|
msg++;
|
|
color = q3ToAnsi[ *msg++ % 8 ];
|
|
colored[len++] = '\033';
|
|
colored[len++] = '[';
|
|
if( color )
|
|
{
|
|
colored[len++] = '3';
|
|
colored[len++] = color;
|
|
}
|
|
else
|
|
colored[len++] = '0';
|
|
colored[len++] = 'm';
|
|
}
|
|
else
|
|
colored[len++] = *msg++;
|
|
}
|
|
colored[len] = 0;
|
|
printf( "\033[34m%s\033[0m%s\033[0m", logtime, colored );
|
|
}
|
|
#else
|
|
#if !defined __ANDROID__
|
|
printf( "%s %s", logtime, pMsg );
|
|
fflush( stdout );
|
|
#endif
|
|
#endif
|
|
lastchar = pMsg[strlen(pMsg)-1];
|
|
if( !logfile )
|
|
return;
|
|
|
|
if( !lastchar || lastchar == '\n')
|
|
strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S]", crt_tm ); //full time
|
|
|
|
fprintf( logfile, "%s %s", logtime, pMsg );
|
|
fflush( logfile );
|
|
}
|
|
|
|
/*
|
|
================
|
|
Sys_Print
|
|
|
|
print into win32 console
|
|
================
|
|
*/
|
|
void Sys_Print( const char *pMsg )
|
|
{
|
|
#ifdef _WIN32
|
|
char tmpBuf[8192];
|
|
HANDLE hOut = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
unsigned long cbWritten;
|
|
char *pTemp = tmpBuf;
|
|
|
|
while( pMsg && *pMsg )
|
|
{
|
|
if( IsColorString( pMsg ))
|
|
{
|
|
if(( pTemp - tmpBuf ) > 0 )
|
|
{
|
|
// dump accumulated text before change color
|
|
*pTemp = 0; // terminate string
|
|
WriteFile( hOut, tmpBuf, strlen( tmpBuf ), &cbWritten, 0 );
|
|
Sys_PrintLog( tmpBuf );
|
|
pTemp = tmpBuf;
|
|
}
|
|
|
|
// set new color
|
|
SetConsoleTextAttribute( hOut, g_color_table[ColorIndex( *(pMsg + 1))] );
|
|
pMsg += 2; // skip color info
|
|
}
|
|
else if(( pTemp - tmpBuf ) < sizeof( tmpBuf ) - 1 )
|
|
{
|
|
*pTemp++ = *pMsg++;
|
|
}
|
|
else
|
|
{
|
|
// temp buffer is full, dump it now
|
|
*pTemp = 0; // terminate string
|
|
WriteFile( hOut, tmpBuf, strlen( tmpBuf ), &cbWritten, 0 );
|
|
Sys_PrintLog( tmpBuf );
|
|
pTemp = tmpBuf;
|
|
}
|
|
}
|
|
|
|
// check for last portion
|
|
if(( pTemp - tmpBuf ) > 0 )
|
|
{
|
|
// dump accumulated text
|
|
*pTemp = 0; // terminate string
|
|
WriteFile( hOut, tmpBuf, strlen( tmpBuf ), &cbWritten, 0 );
|
|
Sys_PrintLog( tmpBuf );
|
|
pTemp = tmpBuf;
|
|
}
|
|
#else
|
|
Sys_PrintLog( pMsg );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
================
|
|
Msg
|
|
|
|
formatted message
|
|
================
|
|
*/
|
|
void Msg( const char *pMsg, ... )
|
|
{
|
|
va_list argptr;
|
|
char text[8192];
|
|
|
|
va_start( argptr, pMsg );
|
|
Q_vsnprintf( text, sizeof( text ), pMsg, argptr );
|
|
va_end( argptr );
|
|
|
|
Sys_Print( text );
|
|
}
|
|
|
|
/*
|
|
================
|
|
MsgDev
|
|
|
|
formatted developer message
|
|
================
|
|
*/
|
|
void MsgDev( int level, const char *pMsg, ... )
|
|
{
|
|
va_list argptr;
|
|
char text[8192];
|
|
|
|
if( devloper_level < level ) return;
|
|
|
|
va_start( argptr, pMsg );
|
|
Q_vsnprintf( text, sizeof( text ), pMsg, argptr );
|
|
va_end( argptr );
|
|
|
|
switch( level )
|
|
{
|
|
case D_WARN:
|
|
Sys_Print( va( "^3Warning:^7 %s", text ));
|
|
break;
|
|
case D_ERROR:
|
|
Sys_Print( va( "^1Error:^7 %s", text ));
|
|
break;
|
|
case D_INFO:
|
|
case D_NOTE:
|
|
case D_REPORT:
|
|
Sys_Print( text );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MsgAnim( int level, const char *pMsg, ... )
|
|
{
|
|
#ifdef _WIN32
|
|
va_list argptr;
|
|
char text[1024];
|
|
char empty[1024];
|
|
|
|
if( devloper_level < level ) return;
|
|
|
|
va_start( argptr, pMsg );
|
|
Q_vsnprintf( text, sizeof( text ), pMsg, argptr );
|
|
va_end( argptr );
|
|
|
|
// fill clear string
|
|
for( int j = 0; j < Q_strlen( text ); j++ )
|
|
empty[j] = ' ';
|
|
empty[j] = '\r';
|
|
empty[j+1] = '\0';
|
|
|
|
// do animation
|
|
for( int i = 0; i < 8; i++ )
|
|
{
|
|
Sys_IgnoreLog( i < 7 );
|
|
if( i & 1 ) Sys_Print( text );
|
|
else Sys_Print( empty );
|
|
Sleep( 150 );
|
|
}
|
|
Msg( "^7\n" );
|
|
#endif
|
|
}
|