(root)/
freetype-2.13.2/
src/
base/
ftdebug.c
       1  /****************************************************************************
       2   *
       3   * ftdebug.c
       4   *
       5   *   Debugging and logging component (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    /* documentation is in ftdebug.h */
      97  
      98    FT_BASE_DEF( void )
      99    FT_Message( const char*  fmt,
     100                ... )
     101    {
     102      va_list  ap;
     103  
     104  
     105      va_start( ap, fmt );
     106      vfprintf( stderr, fmt, ap );
     107      va_end( ap );
     108    }
     109  
     110  
     111    /* documentation is in ftdebug.h */
     112  
     113    FT_BASE_DEF( void )
     114    FT_Panic( const char*  fmt,
     115              ... )
     116    {
     117      va_list  ap;
     118  
     119  
     120      va_start( ap, fmt );
     121      vfprintf( stderr, fmt, ap );
     122      va_end( ap );
     123  
     124      exit( EXIT_FAILURE );
     125    }
     126  
     127  
     128    /* documentation is in ftdebug.h */
     129  
     130    FT_BASE_DEF( int )
     131    FT_Throw( FT_Error     error,
     132              int          line,
     133              const char*  file )
     134    {
     135  #if 0
     136      /* activating the code in this block makes FreeType very chatty */
     137      fprintf( stderr,
     138               "%s:%d: error 0x%02x: %s\n",
     139               file,
     140               line,
     141               error,
     142               FT_Error_String( error ) );
     143  #else
     144      FT_UNUSED( error );
     145      FT_UNUSED( line );
     146      FT_UNUSED( file );
     147  #endif
     148  
     149      return 0;
     150    }
     151  
     152  #endif /* FT_DEBUG_LEVEL_ERROR */
     153  
     154  
     155  #ifdef FT_DEBUG_LEVEL_TRACE
     156  
     157    /* array of trace levels, initialized to 0; */
     158    /* this gets adjusted at run-time           */
     159    static int  ft_trace_levels_enabled[trace_count];
     160  
     161    /* array of trace levels, always initialized to 0 */
     162    static int  ft_trace_levels_disabled[trace_count];
     163  
     164    /* a pointer to either `ft_trace_levels_enabled' */
     165    /* or `ft_trace_levels_disabled'                 */
     166    int*  ft_trace_levels;
     167  
     168    /* define array of trace toggle names */
     169  #define FT_TRACE_DEF( x )  #x ,
     170  
     171    static const char*  ft_trace_toggles[trace_count + 1] =
     172    {
     173  #include <freetype/internal/fttrace.h>
     174      NULL
     175    };
     176  
     177  #undef FT_TRACE_DEF
     178  
     179  
     180    /* documentation is in ftdebug.h */
     181  
     182    FT_BASE_DEF( FT_Int )
     183    FT_Trace_Get_Count( void )
     184    {
     185      return trace_count;
     186    }
     187  
     188  
     189    /* documentation is in ftdebug.h */
     190  
     191    FT_BASE_DEF( const char * )
     192    FT_Trace_Get_Name( FT_Int  idx )
     193    {
     194      int  max = FT_Trace_Get_Count();
     195  
     196  
     197      if ( idx < max )
     198        return ft_trace_toggles[idx];
     199      else
     200        return NULL;
     201    }
     202  
     203  
     204    /* documentation is in ftdebug.h */
     205  
     206    FT_BASE_DEF( void )
     207    FT_Trace_Disable( void )
     208    {
     209      ft_trace_levels = ft_trace_levels_disabled;
     210    }
     211  
     212  
     213    /* documentation is in ftdebug.h */
     214  
     215    FT_BASE_DEF( void )
     216    FT_Trace_Enable( void )
     217    {
     218      ft_trace_levels = ft_trace_levels_enabled;
     219    }
     220  
     221  
     222    /**************************************************************************
     223     *
     224     * Initialize the tracing sub-system.  This is done by retrieving the
     225     * value of the `FT2_DEBUG' environment variable.  It must be a list of
     226     * toggles, separated by spaces, `;', or `,'.  Example:
     227     *
     228     *   export FT2_DEBUG="any:3 memory:7 stream:5"
     229     *
     230     * This requests that all levels be set to 3, except the trace level for
     231     * the memory and stream components which are set to 7 and 5,
     232     * respectively.
     233     *
     234     * See the file `include/freetype/internal/fttrace.h' for details of
     235     * the available toggle names.
     236     *
     237     * The level must be between 0 and 7; 0 means quiet (except for serious
     238     * runtime errors), and 7 means _very_ verbose.
     239     */
     240    FT_BASE_DEF( void )
     241    ft_debug_init( void )
     242    {
     243      const char*  ft2_debug = NULL;
     244  
     245  
     246  #ifdef FT_DEBUG_LOGGING
     247      if ( ft_custom_trace_level != NULL )
     248        ft2_debug = ft_custom_trace_level;
     249      else
     250        ft2_debug = ft_default_trace_level;
     251  #else
     252      ft2_debug = ft_getenv( "FT2_DEBUG" );
     253  #endif
     254  
     255      if ( ft2_debug )
     256      {
     257        const char*  p = ft2_debug;
     258        const char*  q;
     259  
     260  
     261        for ( ; *p; p++ )
     262        {
     263          /* skip leading whitespace and separators */
     264          if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
     265            continue;
     266  
     267  #ifdef FT_DEBUG_LOGGING
     268  
     269          /* check extra arguments for logging */
     270          if ( *p == '-' )
     271          {
     272            const char*  r = ++p;
     273  
     274  
     275            if ( *r == 'v' )
     276            {
     277              const char*  s = ++r;
     278  
     279  
     280              ft_component_flag = TRUE;
     281  
     282              if ( *s == 't' )
     283              {
     284                ft_timestamp_flag = TRUE;
     285                p++;
     286              }
     287  
     288              p++;
     289            }
     290  
     291            else if ( *r == 't' )
     292            {
     293              const char*  s = ++r;
     294  
     295  
     296              ft_timestamp_flag = TRUE;
     297  
     298              if ( *s == 'v' )
     299              {
     300                ft_component_flag = TRUE;
     301                p++;
     302              }
     303  
     304              p++;
     305            }
     306          }
     307  
     308  #endif /* FT_DEBUG_LOGGING */
     309  
     310          /* read toggle name, followed by ':' */
     311          q = p;
     312          while ( *p && *p != ':' )
     313            p++;
     314  
     315          if ( !*p )
     316            break;
     317  
     318          if ( *p == ':' && p > q )
     319          {
     320            FT_Int  n, i, len = (FT_Int)( p - q );
     321            FT_Int  level = -1, found = -1;
     322  
     323  
     324            for ( n = 0; n < trace_count; n++ )
     325            {
     326              const char*  toggle = ft_trace_toggles[n];
     327  
     328  
     329              for ( i = 0; i < len; i++ )
     330              {
     331                if ( toggle[i] != q[i] )
     332                  break;
     333              }
     334  
     335              if ( i == len && toggle[i] == 0 )
     336              {
     337                found = n;
     338                break;
     339              }
     340            }
     341  
     342            /* read level */
     343            p++;
     344            if ( *p )
     345            {
     346              level = *p - '0';
     347              if ( level < 0 || level > 7 )
     348                level = -1;
     349            }
     350  
     351            if ( found >= 0 && level >= 0 )
     352            {
     353              if ( found == trace_any )
     354              {
     355                /* special case for `any' */
     356                for ( n = 0; n < trace_count; n++ )
     357                  ft_trace_levels_enabled[n] = level;
     358              }
     359              else
     360                ft_trace_levels_enabled[found] = level;
     361            }
     362          }
     363        }
     364      }
     365  
     366      ft_trace_levels = ft_trace_levels_enabled;
     367    }
     368  
     369  
     370  #else  /* !FT_DEBUG_LEVEL_TRACE */
     371  
     372  
     373    FT_BASE_DEF( void )
     374    ft_debug_init( void )
     375    {
     376      /* nothing */
     377    }
     378  
     379  
     380    FT_BASE_DEF( FT_Int )
     381    FT_Trace_Get_Count( void )
     382    {
     383      return 0;
     384    }
     385  
     386  
     387    FT_BASE_DEF( const char * )
     388    FT_Trace_Get_Name( FT_Int  idx )
     389    {
     390      FT_UNUSED( idx );
     391  
     392      return NULL;
     393    }
     394  
     395  
     396    FT_BASE_DEF( void )
     397    FT_Trace_Disable( void )
     398    {
     399      /* nothing */
     400    }
     401  
     402  
     403    /* documentation is in ftdebug.h */
     404  
     405    FT_BASE_DEF( void )
     406    FT_Trace_Enable( void )
     407    {
     408      /* nothing */
     409    }
     410  
     411  #endif /* !FT_DEBUG_LEVEL_TRACE */
     412  
     413  
     414  #ifdef FT_DEBUG_LOGGING
     415  
     416    /**************************************************************************
     417     *
     418     * Initialize and de-initialize 'dlg' library.
     419     *
     420     */
     421  
     422    FT_BASE_DEF( void )
     423    ft_logging_init( void )
     424    {
     425      ft_default_log_handler = ft_log_handler;
     426      ft_default_trace_level = ft_getenv( "FT2_DEBUG" );
     427  
     428      if ( ft_getenv( "FT_LOGGING_FILE" ) )
     429        ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" );
     430      else
     431        ft_fileptr = stderr;
     432  
     433      ft_debug_init();
     434  
     435      /* Set the default output handler for 'dlg'. */
     436      dlg_set_handler( ft_default_log_handler, NULL );
     437    }
     438  
     439  
     440    FT_BASE_DEF( void )
     441    ft_logging_deinit( void )
     442    {
     443      if ( ft_fileptr != stderr )
     444        ft_fclose( ft_fileptr );
     445    }
     446  
     447  
     448    /**************************************************************************
     449     *
     450     * An output log handler for FreeType.
     451     *
     452     */
     453    FT_BASE_DEF( void )
     454    ft_log_handler( const struct dlg_origin*  origin,
     455                    const char*               string,
     456                    void*                     data )
     457    {
     458      char         features_buf[128];
     459      char*        bufp = features_buf;
     460  
     461      FT_UNUSED( data );
     462  
     463  
     464      if ( ft_have_newline_char )
     465      {
     466        const char*  features        = NULL;
     467        size_t       features_length = 0;
     468  
     469  
     470  #define FEATURES_TIMESTAMP            "[%h:%m] "
     471  #define FEATURES_COMPONENT            "[%t] "
     472  #define FEATURES_TIMESTAMP_COMPONENT  "[%h:%m %t] "
     473  
     474        if ( ft_timestamp_flag && ft_component_flag )
     475        {
     476          features        = FEATURES_TIMESTAMP_COMPONENT;
     477          features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT );
     478        }
     479        else if ( ft_timestamp_flag )
     480        {
     481          features        = FEATURES_TIMESTAMP;
     482          features_length = sizeof ( FEATURES_TIMESTAMP );
     483        }
     484        else if ( ft_component_flag )
     485        {
     486          features        = FEATURES_COMPONENT;
     487          features_length = sizeof ( FEATURES_COMPONENT );
     488        }
     489  
     490        if ( ft_component_flag || ft_timestamp_flag )
     491        {
     492          ft_strncpy( features_buf, features, features_length );
     493          bufp += features_length - 1;
     494        }
     495  
     496        if ( ft_component_flag )
     497        {
     498          size_t  tag_length = ft_strlen( *origin->tags );
     499          size_t  i;
     500  
     501  
     502          /* To vertically align tracing messages we compensate the */
     503          /* different FT_COMPONENT string lengths by inserting an  */
     504          /* appropriate amount of space characters.                */
     505          for ( i = 0;
     506                i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length;
     507                i++ )
     508            *bufp++ = ' ';
     509        }
     510      }
     511  
     512      /* Finally add the format string for the tracing message. */
     513      *bufp++ = '%';
     514      *bufp++ = 'c';
     515      *bufp   = '\0';
     516  
     517      dlg_generic_outputf_stream( ft_fileptr,
     518                                  (const char*)features_buf,
     519                                  origin,
     520                                  string,
     521                                  dlg_default_output_styles,
     522                                  true );
     523  
     524      if ( ft_strrchr( string, '\n' ) )
     525        ft_have_newline_char = TRUE;
     526      else
     527        ft_have_newline_char = FALSE;
     528    }
     529  
     530  
     531    /* documentation is in ftdebug.h */
     532    FT_BASE_DEF( void )
     533    ft_add_tag( const char*  tag )
     534    {
     535      ft_component = tag;
     536  
     537      dlg_add_tag( tag, NULL );
     538    }
     539  
     540  
     541    /* documentation is in ftdebug.h */
     542    FT_BASE_DEF( void )
     543    ft_remove_tag( const char*  tag )
     544    {
     545      dlg_remove_tag( tag, NULL );
     546    }
     547  
     548  
     549    /* documentation is in ftlogging.h */
     550  
     551    FT_EXPORT_DEF( void )
     552    FT_Trace_Set_Level( const char*  level )
     553    {
     554      ft_component_flag     = FALSE;
     555      ft_timestamp_flag     = FALSE;
     556      ft_custom_trace_level = level;
     557  
     558      ft_debug_init();
     559    }
     560  
     561  
     562    /* documentation is in ftlogging.h */
     563  
     564    FT_EXPORT_DEF( void )
     565    FT_Trace_Set_Default_Level( void )
     566    {
     567      ft_component_flag     = FALSE;
     568      ft_timestamp_flag     = FALSE;
     569      ft_custom_trace_level = NULL;
     570  
     571      ft_debug_init();
     572    }
     573  
     574  
     575    /**************************************************************************
     576     *
     577     * Functions to handle a custom log handler.
     578     *
     579     */
     580  
     581    /* documentation is in ftlogging.h */
     582  
     583    FT_EXPORT_DEF( void )
     584    FT_Set_Log_Handler( FT_Custom_Log_Handler  handler )
     585    {
     586      custom_output_handler = handler;
     587    }
     588  
     589  
     590    /* documentation is in ftlogging.h */
     591  
     592    FT_EXPORT_DEF( void )
     593    FT_Set_Default_Log_Handler( void )
     594    {
     595      custom_output_handler = NULL;
     596    }
     597  
     598  
     599    /* documentation is in ftdebug.h */
     600    FT_BASE_DEF( void )
     601    FT_Logging_Callback( const char*  fmt,
     602                         ... )
     603    {
     604      va_list  ap;
     605  
     606  
     607      va_start( ap, fmt );
     608      custom_output_handler( ft_component, fmt, ap );
     609      va_end( ap );
     610    }
     611  
     612  #else /* !FT_DEBUG_LOGGING */
     613  
     614    FT_EXPORT_DEF( void )
     615    FT_Trace_Set_Level( const char*  level )
     616    {
     617      FT_UNUSED( level );
     618    }
     619  
     620  
     621    FT_EXPORT_DEF( void )
     622    FT_Trace_Set_Default_Level( void )
     623    {
     624      /* nothing */
     625    }
     626  
     627  
     628    FT_EXPORT_DEF( void )
     629    FT_Set_Log_Handler( FT_Custom_Log_Handler  handler )
     630    {
     631      FT_UNUSED( handler );
     632    }
     633  
     634  
     635    FT_EXPORT_DEF( void )
     636    FT_Set_Default_Log_Handler( void )
     637    {
     638      /* nothing */
     639    }
     640  
     641  #endif /* !FT_DEBUG_LOGGING */
     642  
     643  
     644  /* END */