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