Paranoia2/utils/common/conprint.cpp

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
}