#include <freetype/freetype.h>
#include <freetype/ftlogging.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftobjs.h>
#ifdef FT_DEBUG_LOGGING
static const char* ft_default_trace_level = NULL;
static FILE* ft_fileptr = NULL;
static const char* ft_component = NULL;
static FT_Bool ft_component_flag = FALSE;
static FT_Bool ft_timestamp_flag = FALSE;
static FT_Bool ft_have_newline_char = TRUE;
static const char* ft_custom_trace_level = NULL;
dlg_handler ft_default_log_handler = NULL;
FT_Custom_Log_Handler custom_output_handler = NULL;
#endif
#ifdef FT_DEBUG_LEVEL_ERROR
FT_BASE_DEF( void )
FT_Message( const char* fmt,
... )
{
va_list ap;
va_start( ap, fmt );
vfprintf( stderr, fmt, ap );
va_end( ap );
}
FT_BASE_DEF( void )
FT_Panic( const char* fmt,
... )
{
va_list ap;
va_start( ap, fmt );
vfprintf( stderr, fmt, ap );
va_end( ap );
exit( EXIT_FAILURE );
}
FT_BASE_DEF( int )
FT_Throw( FT_Error error,
int line,
const char* file )
{
#if 0
fprintf( stderr,
"%s:%d: error 0x%02x: %s\n",
file,
line,
error,
FT_Error_String( error ) );
#else
FT_UNUSED( error );
FT_UNUSED( line );
FT_UNUSED( file );
#endif
return 0;
}
#endif
#ifdef FT_DEBUG_LEVEL_TRACE
static int ft_trace_levels_enabled[trace_count];
static int ft_trace_levels_disabled[trace_count];
int* ft_trace_levels;
#define FT_TRACE_DEF …
static const char* ft_trace_toggles[trace_count + 1] =
{
#include <freetype/internal/fttrace.h>
NULL
};
#undef FT_TRACE_DEF
FT_BASE_DEF( FT_Int )
FT_Trace_Get_Count( void )
{
return trace_count;
}
FT_BASE_DEF( const char * )
FT_Trace_Get_Name( FT_Int idx )
{
int max = FT_Trace_Get_Count();
if ( idx < max )
return ft_trace_toggles[idx];
else
return NULL;
}
FT_BASE_DEF( void )
FT_Trace_Disable( void )
{
ft_trace_levels = ft_trace_levels_disabled;
}
FT_BASE_DEF( void )
FT_Trace_Enable( void )
{
ft_trace_levels = ft_trace_levels_enabled;
}
FT_BASE_DEF( void )
ft_debug_init( void )
{
const char* ft2_debug = NULL;
#ifdef FT_DEBUG_LOGGING
if ( ft_custom_trace_level != NULL )
ft2_debug = ft_custom_trace_level;
else
ft2_debug = ft_default_trace_level;
#else
ft2_debug = ft_getenv( "FT2_DEBUG" );
#endif
if ( ft2_debug )
{
const char* p = ft2_debug;
const char* q;
for ( ; *p; p++ )
{
if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
continue;
#ifdef FT_DEBUG_LOGGING
if ( *p == '-' )
{
const char* r = ++p;
if ( *r == 'v' )
{
const char* s = ++r;
ft_component_flag = TRUE;
if ( *s == 't' )
{
ft_timestamp_flag = TRUE;
p++;
}
p++;
}
else if ( *r == 't' )
{
const char* s = ++r;
ft_timestamp_flag = TRUE;
if ( *s == 'v' )
{
ft_component_flag = TRUE;
p++;
}
p++;
}
}
#endif
q = p;
while ( *p && *p != ':' )
p++;
if ( !*p )
break;
if ( *p == ':' && p > q )
{
FT_Int n, i, len = (FT_Int)( p - q );
FT_Int level = -1, found = -1;
for ( n = 0; n < trace_count; n++ )
{
const char* toggle = ft_trace_toggles[n];
for ( i = 0; i < len; i++ )
{
if ( toggle[i] != q[i] )
break;
}
if ( i == len && toggle[i] == 0 )
{
found = n;
break;
}
}
p++;
if ( *p )
{
level = *p - '0';
if ( level < 0 || level > 7 )
level = -1;
}
if ( found >= 0 && level >= 0 )
{
if ( found == trace_any )
{
for ( n = 0; n < trace_count; n++ )
ft_trace_levels_enabled[n] = level;
}
else
ft_trace_levels_enabled[found] = level;
}
}
}
}
ft_trace_levels = ft_trace_levels_enabled;
}
#else
FT_BASE_DEF( void )
ft_debug_init( void )
{ … }
FT_BASE_DEF( FT_Int )
FT_Trace_Get_Count( void )
{ … }
FT_BASE_DEF( const char * )
FT_Trace_Get_Name( FT_Int idx )
{ … }
FT_BASE_DEF( void )
FT_Trace_Disable( void )
{ … }
FT_BASE_DEF( void )
FT_Trace_Enable( void )
{ … }
#endif
#ifdef FT_DEBUG_LOGGING
FT_BASE_DEF( void )
ft_logging_init( void )
{
ft_default_log_handler = ft_log_handler;
ft_default_trace_level = ft_getenv( "FT2_DEBUG" );
if ( ft_getenv( "FT_LOGGING_FILE" ) )
ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" );
else
ft_fileptr = stderr;
ft_debug_init();
dlg_set_handler( ft_default_log_handler, NULL );
}
FT_BASE_DEF( void )
ft_logging_deinit( void )
{
if ( ft_fileptr != stderr )
ft_fclose( ft_fileptr );
}
FT_BASE_DEF( void )
ft_log_handler( const struct dlg_origin* origin,
const char* string,
void* data )
{
char features_buf[128];
char* bufp = features_buf;
FT_UNUSED( data );
if ( ft_have_newline_char )
{
const char* features = NULL;
size_t features_length = 0;
#define FEATURES_TIMESTAMP …
#define FEATURES_COMPONENT …
#define FEATURES_TIMESTAMP_COMPONENT …
if ( ft_timestamp_flag && ft_component_flag )
{
features = FEATURES_TIMESTAMP_COMPONENT;
features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT );
}
else if ( ft_timestamp_flag )
{
features = FEATURES_TIMESTAMP;
features_length = sizeof ( FEATURES_TIMESTAMP );
}
else if ( ft_component_flag )
{
features = FEATURES_COMPONENT;
features_length = sizeof ( FEATURES_COMPONENT );
}
if ( ft_component_flag || ft_timestamp_flag )
{
ft_strncpy( features_buf, features, features_length );
bufp += features_length - 1;
}
if ( ft_component_flag )
{
size_t tag_length = ft_strlen( *origin->tags );
size_t i;
for ( i = 0;
i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length;
i++ )
*bufp++ = ' ';
}
}
*bufp++ = '%';
*bufp++ = 'c';
*bufp = '\0';
dlg_generic_outputf_stream( ft_fileptr,
(const char*)features_buf,
origin,
string,
dlg_default_output_styles,
true );
if ( ft_strrchr( string, '\n' ) )
ft_have_newline_char = TRUE;
else
ft_have_newline_char = FALSE;
}
FT_BASE_DEF( void )
ft_add_tag( const char* tag )
{
ft_component = tag;
dlg_add_tag( tag, NULL );
}
FT_BASE_DEF( void )
ft_remove_tag( const char* tag )
{
dlg_remove_tag( tag, NULL );
}
FT_EXPORT_DEF( void )
FT_Trace_Set_Level( const char* level )
{
ft_component_flag = FALSE;
ft_timestamp_flag = FALSE;
ft_custom_trace_level = level;
ft_debug_init();
}
FT_EXPORT_DEF( void )
FT_Trace_Set_Default_Level( void )
{
ft_component_flag = FALSE;
ft_timestamp_flag = FALSE;
ft_custom_trace_level = NULL;
ft_debug_init();
}
FT_EXPORT_DEF( void )
FT_Set_Log_Handler( FT_Custom_Log_Handler handler )
{
custom_output_handler = handler;
}
FT_EXPORT_DEF( void )
FT_Set_Default_Log_Handler( void )
{
custom_output_handler = NULL;
}
FT_BASE_DEF( void )
FT_Logging_Callback( const char* fmt,
... )
{
va_list ap;
va_start( ap, fmt );
custom_output_handler( ft_component, fmt, ap );
va_end( ap );
}
#else
FT_EXPORT_DEF( void )
FT_Trace_Set_Level( const char* level )
{ … }
FT_EXPORT_DEF( void )
FT_Trace_Set_Default_Level( void )
{ … }
FT_EXPORT_DEF( void )
FT_Set_Log_Handler( FT_Custom_Log_Handler handler )
{ … }
FT_EXPORT_DEF( void )
FT_Set_Default_Log_Handler( void )
{ … }
#endif