(root)/
freetype-2.13.2/
builds/
windows/
ftdebug.c
       1  /****************************************************************************
       2   *
       3   * ftdebug.c
       4   *
       5   *   Debugging and logging component for Win32 (body).
       6   *
       7   * Copyright (C) 1996-2023 by
       8   * David Turner, Robert Wilhelm, and Werner Lemberg.
       9   *
      10   * This file is part of the FreeType project, and may only be used,
      11   * modified, and distributed under the terms of the FreeType project
      12   * license, LICENSE.TXT.  By continuing to use, modify, or distribute
      13   * this file you indicate that you have read the license and
      14   * understand and accept it fully.
      15   *
      16   */
      17  
      18  
      19    /**************************************************************************
      20     *
      21     * This component contains various macros and functions used to ease the
      22     * debugging of the FreeType engine.  Its main purpose is in assertion
      23     * checking, tracing, and error detection.
      24     *
      25     * There are now three debugging modes:
      26     *
      27     * - trace mode
      28     *
      29     *   Error and trace messages are sent to the log file (which can be the
      30     *   standard error output).
      31     *
      32     * - error mode
      33     *
      34     *   Only error messages are generated.
      35     *
      36     * - release mode:
      37     *
      38     *   No error message is sent or generated.  The code is free from any
      39     *   debugging parts.
      40     *
      41     */
      42  
      43  
      44  #include <freetype/freetype.h>
      45  #include <freetype/ftlogging.h>
      46  #include <freetype/internal/ftdebug.h>
      47  #include <freetype/internal/ftobjs.h>
      48  
      49  
      50  #ifdef FT_DEBUG_LOGGING
      51  
      52    /**************************************************************************
      53     *
      54     * Variables used to control logging.
      55     *
      56     * 1. `ft_default_trace_level` stores the value of trace levels, which are
      57     *    provided to FreeType using the `FT2_DEBUG` environment variable.
      58     *
      59     * 2. `ft_fileptr` stores the `FILE*` handle.
      60     *
      61     * 3. `ft_component` is a string that holds the name of `FT_COMPONENT`.
      62     *
      63     * 4. The flag `ft_component_flag` prints the name of `FT_COMPONENT` along
      64     *    with the actual log message if set to true.
      65     *
      66     * 5. The flag `ft_timestamp_flag` prints time along with the actual log
      67     *    message if set to ture.
      68     *
      69     * 6. `ft_have_newline_char` is used to differentiate between a log
      70     *    message with and without a trailing newline character.
      71     *
      72     * 7. `ft_custom_trace_level` stores the custom trace level value, which
      73     *    is provided by the user at run-time.
      74     *
      75     * We use `static` to avoid 'unused variable' warnings.
      76     *
      77     */
      78    static const char*  ft_default_trace_level = NULL;
      79    static FILE*        ft_fileptr             = NULL;
      80    static const char*  ft_component           = NULL;
      81    static FT_Bool      ft_component_flag      = FALSE;
      82    static FT_Bool      ft_timestamp_flag      = FALSE;
      83    static FT_Bool      ft_have_newline_char   = TRUE;
      84    static const char*  ft_custom_trace_level  = NULL;
      85  
      86    /* declared in ftdebug.h */
      87  
      88    dlg_handler            ft_default_log_handler = NULL;
      89    FT_Custom_Log_Handler  custom_output_handler  = NULL;
      90  
      91  #endif /* FT_DEBUG_LOGGING */
      92  
      93  
      94  #ifdef FT_DEBUG_LEVEL_ERROR
      95  
      96  #define WIN32_LEAN_AND_MEAN
      97  #include <windows.h>
      98  
      99  
     100  #ifdef _WIN32_WCE
     101  
     102    FT_LOACAL_DEF( void )
     103    OutputDebugStringA( LPCSTR lpOutputString )
     104    {
     105      int            len;
     106      LPWSTR         lpOutputStringW;
     107  
     108  
     109      /* allocate memory space for converted string */
     110      len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS,
     111                                 lpOutputString, -1, NULL, 0 );
     112  
     113      lpOutputStringW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) );
     114  
     115      if ( !len || !lpOutputStringW )
     116        return;
     117  
     118      /* now it is safe to do the translation */
     119      MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS,
     120                           lpOutputString, -1, lpOutputStringW, len );
     121  
     122      OutputDebugStringW( lpOutputStringW );
     123    }
     124  
     125  #endif /* _WIN32_WCE */
     126  
     127  
     128    /* documentation is in ftdebug.h */
     129  
     130    FT_BASE_DEF( void )
     131    FT_Message( const char*  fmt,
     132                ... )
     133    {
     134      va_list  ap;
     135  
     136  
     137      va_start( ap, fmt );
     138      vfprintf( stderr, fmt, ap );
     139  #if ( defined( _WIN32_WINNT ) && _WIN32_WINNT >= 0x0400 ) || \
     140      ( defined( _WIN32_WCE )   && _WIN32_WCE   >= 0x0600 )
     141      if ( IsDebuggerPresent() )
     142      {
     143        static char  buf[1024];
     144  
     145  
     146        vsnprintf( buf, sizeof buf, fmt, ap );
     147        OutputDebugStringA( buf );
     148      }
     149  #endif
     150      va_end( ap );
     151    }
     152  
     153  
     154    /* documentation is in ftdebug.h */
     155  
     156    FT_BASE_DEF( void )
     157    FT_Panic( const char*  fmt,
     158              ... )
     159    {
     160      va_list  ap;
     161  
     162  
     163      va_start( ap, fmt );
     164      vfprintf( stderr, fmt, ap );
     165  #if ( defined( _WIN32_WINNT ) && _WIN32_WINNT >= 0x0400 ) || \
     166      ( defined( _WIN32_WCE )   && _WIN32_WCE   >= 0x0600 )
     167      if ( IsDebuggerPresent() )
     168      {
     169        static char  buf[1024];
     170  
     171  
     172        vsnprintf( buf, sizeof buf, fmt, ap );
     173        OutputDebugStringA( buf );
     174      }
     175  #endif
     176      va_end( ap );
     177  
     178      exit( EXIT_FAILURE );
     179    }
     180  
     181  
     182    /* documentation is in ftdebug.h */
     183  
     184    FT_BASE_DEF( int )
     185    FT_Throw( FT_Error     error,
     186              int          line,
     187              const char*  file )
     188    {
     189  #if 0
     190      /* activating the code in this block makes FreeType very chatty */
     191      fprintf( stderr,
     192               "%s:%d: error 0x%02x: %s\n",
     193               file,
     194               line,
     195               error,
     196               FT_Error_String( error ) );
     197  #else
     198      FT_UNUSED( error );
     199      FT_UNUSED( line );
     200      FT_UNUSED( file );
     201  #endif
     202  
     203      return 0;
     204    }
     205  
     206  #endif /* FT_DEBUG_LEVEL_ERROR */
     207  
     208  
     209  #ifdef FT_DEBUG_LEVEL_TRACE
     210  
     211    /* array of trace levels, initialized to 0; */
     212    /* this gets adjusted at run-time           */
     213    static int  ft_trace_levels_enabled[trace_count];
     214  
     215    /* array of trace levels, always initialized to 0 */
     216    static int  ft_trace_levels_disabled[trace_count];
     217  
     218    /* a pointer to either `ft_trace_levels_enabled' */
     219    /* or `ft_trace_levels_disabled'                 */
     220    int*  ft_trace_levels;
     221  
     222    /* define array of trace toggle names */
     223  #define FT_TRACE_DEF( x )  #x ,
     224  
     225    static const char*  ft_trace_toggles[trace_count + 1] =
     226    {
     227  #include <freetype/internal/fttrace.h>
     228      NULL
     229    };
     230  
     231  #undef FT_TRACE_DEF
     232  
     233  
     234    /* documentation is in ftdebug.h */
     235  
     236    FT_BASE_DEF( FT_Int )
     237    FT_Trace_Get_Count( void )
     238    {
     239      return trace_count;
     240    }
     241  
     242  
     243    /* documentation is in ftdebug.h */
     244  
     245    FT_BASE_DEF( const char * )
     246    FT_Trace_Get_Name( FT_Int  idx )
     247    {
     248      int  max = FT_Trace_Get_Count();
     249  
     250  
     251      if ( idx < max )
     252        return ft_trace_toggles[idx];
     253      else
     254        return NULL;
     255    }
     256  
     257  
     258    /* documentation is in ftdebug.h */
     259  
     260    FT_BASE_DEF( void )
     261    FT_Trace_Disable( void )
     262    {
     263      ft_trace_levels = ft_trace_levels_disabled;
     264    }
     265  
     266  
     267    /* documentation is in ftdebug.h */
     268  
     269    FT_BASE_DEF( void )
     270    FT_Trace_Enable( void )
     271    {
     272      ft_trace_levels = ft_trace_levels_enabled;
     273    }
     274  
     275  
     276    /**************************************************************************
     277     *
     278     * Initialize the tracing sub-system.  This is done by retrieving the
     279     * value of the `FT2_DEBUG' environment variable.  It must be a list of
     280     * toggles, separated by spaces, `;', or `,'.  Example:
     281     *
     282     *   export FT2_DEBUG="any:3 memory:7 stream:5"
     283     *
     284     * This requests that all levels be set to 3, except the trace level for
     285     * the memory and stream components which are set to 7 and 5,
     286     * respectively.
     287     *
     288     * See the file `include/freetype/internal/fttrace.h' for details of
     289     * the available toggle names.
     290     *
     291     * The level must be between 0 and 7; 0 means quiet (except for serious
     292     * runtime errors), and 7 means _very_ verbose.
     293     */
     294    FT_BASE_DEF( void )
     295    ft_debug_init( void )
     296    {
     297      const char*  ft2_debug = NULL;
     298  
     299  
     300  #ifdef FT_DEBUG_LOGGING
     301      if ( ft_custom_trace_level != NULL )
     302        ft2_debug = ft_custom_trace_level;
     303      else
     304        ft2_debug = ft_default_trace_level;
     305  #else
     306      ft2_debug = ft_getenv( "FT2_DEBUG" );
     307  #endif
     308  
     309      if ( ft2_debug )
     310      {
     311        const char*  p = ft2_debug;
     312        const char*  q;
     313  
     314  
     315        for ( ; *p; p++ )
     316        {
     317          /* skip leading whitespace and separators */
     318          if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
     319            continue;
     320  
     321  #ifdef FT_DEBUG_LOGGING
     322  
     323          /* check extra arguments for logging */
     324          if ( *p == '-' )
     325          {
     326            const char*  r = ++p;
     327  
     328  
     329            if ( *r == 'v' )
     330            {
     331              const char*  s = ++r;
     332  
     333  
     334              ft_component_flag = TRUE;
     335  
     336              if ( *s == 't' )
     337              {
     338                ft_timestamp_flag = TRUE;
     339                p++;
     340              }
     341  
     342              p++;
     343            }
     344  
     345            else if ( *r == 't' )
     346            {
     347              const char*  s = ++r;
     348  
     349  
     350              ft_timestamp_flag = TRUE;
     351  
     352              if ( *s == 'v' )
     353              {
     354                ft_component_flag = TRUE;
     355                p++;
     356              }
     357  
     358              p++;
     359            }
     360          }
     361  
     362  #endif /* FT_DEBUG_LOGGING */
     363  
     364          /* read toggle name, followed by ':' */
     365          q = p;
     366          while ( *p && *p != ':' )
     367            p++;
     368  
     369          if ( !*p )
     370            break;
     371  
     372          if ( *p == ':' && p > q )
     373          {
     374            FT_Int  n, i, len = (FT_Int)( p - q );
     375            FT_Int  level = -1, found = -1;
     376  
     377  
     378            for ( n = 0; n < trace_count; n++ )
     379            {
     380              const char*  toggle = ft_trace_toggles[n];
     381  
     382  
     383              for ( i = 0; i < len; i++ )
     384              {
     385                if ( toggle[i] != q[i] )
     386                  break;
     387              }
     388  
     389              if ( i == len && toggle[i] == 0 )
     390              {
     391                found = n;
     392                break;
     393              }
     394            }
     395  
     396            /* read level */
     397            p++;
     398            if ( *p )
     399            {
     400              level = *p - '0';
     401              if ( level < 0 || level > 7 )
     402                level = -1;
     403            }
     404  
     405            if ( found >= 0 && level >= 0 )
     406            {
     407              if ( found == trace_any )
     408              {
     409                /* special case for `any' */
     410                for ( n = 0; n < trace_count; n++ )
     411                  ft_trace_levels_enabled[n] = level;
     412              }
     413              else
     414                ft_trace_levels_enabled[found] = level;
     415            }
     416          }
     417        }
     418      }
     419  
     420      ft_trace_levels = ft_trace_levels_enabled;
     421    }
     422  
     423  
     424  #else  /* !FT_DEBUG_LEVEL_TRACE */
     425  
     426  
     427    FT_BASE_DEF( void )
     428    ft_debug_init( void )
     429    {
     430      /* nothing */
     431    }
     432  
     433  
     434    FT_BASE_DEF( FT_Int )
     435    FT_Trace_Get_Count( void )
     436    {
     437      return 0;
     438    }
     439  
     440  
     441    FT_BASE_DEF( const char * )
     442    FT_Trace_Get_Name( FT_Int  idx )
     443    {
     444      FT_UNUSED( idx );
     445  
     446      return NULL;
     447    }
     448  
     449  
     450    FT_BASE_DEF( void )
     451    FT_Trace_Disable( void )
     452    {
     453      /* nothing */
     454    }
     455  
     456  
     457    /* documentation is in ftdebug.h */
     458  
     459    FT_BASE_DEF( void )
     460    FT_Trace_Enable( void )
     461    {
     462      /* nothing */
     463    }
     464  
     465  #endif /* !FT_DEBUG_LEVEL_TRACE */
     466  
     467  
     468  #ifdef FT_DEBUG_LOGGING
     469  
     470    /**************************************************************************
     471     *
     472     * Initialize and de-initialize 'dlg' library.
     473     *
     474     */
     475  
     476    FT_BASE_DEF( void )
     477    ft_logging_init( void )
     478    {
     479      ft_default_log_handler = ft_log_handler;
     480      ft_default_trace_level = ft_getenv( "FT2_DEBUG" );
     481  
     482      if ( ft_getenv( "FT_LOGGING_FILE" ) )
     483        ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" );
     484      else
     485        ft_fileptr = stderr;
     486  
     487      ft_debug_init();
     488  
     489      /* Set the default output handler for 'dlg'. */
     490      dlg_set_handler( ft_default_log_handler, NULL );
     491    }
     492  
     493  
     494    FT_BASE_DEF( void )
     495    ft_logging_deinit( void )
     496    {
     497      if ( ft_fileptr != stderr )
     498        ft_fclose( ft_fileptr );
     499    }
     500  
     501  
     502    /**************************************************************************
     503     *
     504     * An output log handler for FreeType.
     505     *
     506     */
     507    FT_BASE_DEF( void )
     508    ft_log_handler( const struct dlg_origin*  origin,
     509                    const char*               string,
     510                    void*                     data )
     511    {
     512      char         features_buf[128];
     513      char*        bufp = features_buf;
     514  
     515      FT_UNUSED( data );
     516  
     517  
     518      if ( ft_have_newline_char )
     519      {
     520        const char*  features        = NULL;
     521        size_t       features_length = 0;
     522  
     523  
     524  #define FEATURES_TIMESTAMP            "[%h:%m] "
     525  #define FEATURES_COMPONENT            "[%t] "
     526  #define FEATURES_TIMESTAMP_COMPONENT  "[%h:%m %t] "
     527  
     528        if ( ft_timestamp_flag && ft_component_flag )
     529        {
     530          features        = FEATURES_TIMESTAMP_COMPONENT;
     531          features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT );
     532        }
     533        else if ( ft_timestamp_flag )
     534        {
     535          features        = FEATURES_TIMESTAMP;
     536          features_length = sizeof ( FEATURES_TIMESTAMP );
     537        }
     538        else if ( ft_component_flag )
     539        {
     540          features        = FEATURES_COMPONENT;
     541          features_length = sizeof ( FEATURES_COMPONENT );
     542        }
     543  
     544        if ( ft_component_flag || ft_timestamp_flag )
     545        {
     546          ft_strncpy( features_buf, features, features_length );
     547          bufp += features_length - 1;
     548        }
     549  
     550        if ( ft_component_flag )
     551        {
     552          size_t  tag_length = ft_strlen( *origin->tags );
     553          size_t  i;
     554  
     555  
     556          /* To vertically align tracing messages we compensate the */
     557          /* different FT_COMPONENT string lengths by inserting an  */
     558          /* appropriate amount of space characters.                */
     559          for ( i = 0;
     560                i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length;
     561                i++ )
     562            *bufp++ = ' ';
     563        }
     564      }
     565  
     566      /* Finally add the format string for the tracing message. */
     567      *bufp++ = '%';
     568      *bufp++ = 'c';
     569      *bufp   = '\0';
     570  
     571      dlg_generic_outputf_stream( ft_fileptr,
     572                                  (const char*)features_buf,
     573                                  origin,
     574                                  string,
     575                                  dlg_default_output_styles,
     576                                  true );
     577  
     578      if ( ft_strrchr( string, '\n' ) )
     579        ft_have_newline_char = TRUE;
     580      else
     581        ft_have_newline_char = FALSE;
     582    }
     583  
     584  
     585    /* documentation is in ftdebug.h */
     586    FT_BASE_DEF( void )
     587    ft_add_tag( const char*  tag )
     588    {
     589      ft_component = tag;
     590  
     591      dlg_add_tag( tag, NULL );
     592    }
     593  
     594  
     595    /* documentation is in ftdebug.h */
     596    FT_BASE_DEF( void )
     597    ft_remove_tag( const char*  tag )
     598    {
     599      dlg_remove_tag( tag, NULL );
     600    }
     601  
     602  
     603    /* documentation is in ftlogging.h */
     604  
     605    FT_EXPORT_DEF( void )
     606    FT_Trace_Set_Level( const char*  level )
     607    {
     608      ft_component_flag     = FALSE;
     609      ft_timestamp_flag     = FALSE;
     610      ft_custom_trace_level = level;
     611  
     612      ft_debug_init();
     613    }
     614  
     615  
     616    /* documentation is in ftlogging.h */
     617  
     618    FT_EXPORT_DEF( void )
     619    FT_Trace_Set_Default_Level( void )
     620    {
     621      ft_component_flag     = FALSE;
     622      ft_timestamp_flag     = FALSE;
     623      ft_custom_trace_level = NULL;
     624  
     625      ft_debug_init();
     626    }
     627  
     628  
     629    /**************************************************************************
     630     *
     631     * Functions to handle a custom log handler.
     632     *
     633     */
     634  
     635    /* documentation is in ftlogging.h */
     636  
     637    FT_EXPORT_DEF( void )
     638    FT_Set_Log_Handler( FT_Custom_Log_Handler  handler )
     639    {
     640      custom_output_handler = handler;
     641    }
     642  
     643  
     644    /* documentation is in ftlogging.h */
     645  
     646    FT_EXPORT_DEF( void )
     647    FT_Set_Default_Log_Handler( void )
     648    {
     649      custom_output_handler = NULL;
     650    }
     651  
     652  
     653    /* documentation is in ftdebug.h */
     654    FT_BASE_DEF( void )
     655    FT_Logging_Callback( const char*  fmt,
     656                         ... )
     657    {
     658      va_list  ap;
     659  
     660  
     661      va_start( ap, fmt );
     662      custom_output_handler( ft_component, fmt, ap );
     663      va_end( ap );
     664    }
     665  
     666  #else /* !FT_DEBUG_LOGGING */
     667  
     668    FT_EXPORT_DEF( void )
     669    FT_Trace_Set_Level( const char*  level )
     670    {
     671      FT_UNUSED( level );
     672    }
     673  
     674  
     675    FT_EXPORT_DEF( void )
     676    FT_Trace_Set_Default_Level( void )
     677    {
     678      /* nothing */
     679    }
     680  
     681  
     682    FT_EXPORT_DEF( void )
     683    FT_Set_Log_Handler( FT_Custom_Log_Handler  handler )
     684    {
     685      FT_UNUSED( handler );
     686    }
     687  
     688  
     689    FT_EXPORT_DEF( void )
     690    FT_Set_Default_Log_Handler( void )
     691    {
     692      /* nothing */
     693    }
     694  
     695  #endif /* !FT_DEBUG_LOGGING */
     696  
     697  
     698  /* END */