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