/* -*- Mode: C++ -*- * * fg_debug.c -- Flight Gear debug utility functions * * Written by Paul Bleisch, started January 1998. * * Copyright (C) 1998 Paul Bleisch, pbleisch@acm.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id$ * (Log is kept at end of this file) **************************************************************************/ #include #include #include #include #include // Line to command line arguments #include "fg_debug.h" static int fg_DebugSem = 1; fgDebugClass fg_DebugClass = FG_NONE; // Need visibility for fgDebugPriority fg_DebugPriority = FG_INFO; // command line processing. static fgDebugCallback fg_DebugCallback = NULL; FILE *fg_DebugOutput = NULL; // Visibility needed for command line processor. // This can be set to a FILE from the command // line. If not, it will be set to stderr. /* TODO: Actually make this thing thread safe */ #ifdef USETHREADS #define FG_GRABDEBUGSEM while( --fg_DebugSem < 0 ) { fg_DebugSem++; } #define FG_RELEASEDEBUGSEM fg_DebugSem++; #else #define FG_GRABDEBUGSEM #define FG_RELEASEDEBUGSEM #endif /* Used for convienence initialization from env variables. */ static struct { char *str; fgDebugClass dbg_class; } fg_DebugClasses[] = { { "FG_NONE", 0x00000000 }, { "FG_TERRAIN", 0x00000001 }, { "FG_ASTRO", 0x00000002 }, { "FG_FLIGHT", 0x00000004 }, { "FG_INPUT", 0x00000008 }, { "FG_GL", 0x00000010 }, { "FG_VIEW", 0x00000020 }, { "FG_COCKPIT", 0x00000040 }, { "FG_GENERAL", 0x00000080 }, { "FG_MATH", 0x00000100 }, { "FG_EVENT", 0x00000200 }, { "FG_AIRCRAFT", 0x00000400 }, { "FG_AUTOPILOT", 0x00000800 }, /* Do not edit below here, last entry should be null */ { "FG_ALL", 0xFFFFFFFF }, { NULL, 0 } }; static fgDebugClass fgDebugStrToClass( char *str ); /* fgInitDebug =============================================================*/ void fgInitDebug( void ) { char *pszClass, *pszPrio, *pszFile; // Support for log file/alt debug output via command line, environment or // reasonable default. /* if( strlen( logArgbuf ) > 3) { // First check for command line option // Assumed that we will append. fg_DebugOutput = fopen(logArgbuf, "a+" ); } */ if( !fg_DebugOutput ) { // If not set on command line, environment? pszFile = getenv( "FG_DEBUGFILE" ); if( pszFile ) { // There is such an environmental variable. fg_DebugOutput = fopen( pszFile, "a+" ); } } if( !fg_DebugOutput ) { // If neither command line nor environment fg_DebugOutput = stderr; // then we use the fallback position } FG_GRABDEBUGSEM; fg_DebugSem = fg_DebugSem; /* shut up GCC */ // Test command line option overridge of debug priority. If the value // is in range (properly optioned) the we will override both defaults // and the environmental value. /* if ((priorityArgValue >= FG_BULK) && (priorityArgValue <= FG_ABORT)) { fg_DebugPriority = priorityArgValue; } else { // Either not set or out of range. We will not warn the user. */ pszPrio = getenv( "FG_DEBUGPRIORITY" ); if( pszPrio ) { fg_DebugPriority = atoi( pszPrio ); fprintf( stderr, "fg_debug.c: Environment overrides default debug priority (%d)\n", fg_DebugPriority ); } /* } */ /* if ((debugArgValue >= FG_ALL) && (debugArgValue < FG_UNDEFD)) { fg_DebugPriority = priorityArgValue; } else { // Either not set or out of range. We will not warn the user. */ pszClass = getenv( "FG_DEBUGCLASS" ); if( pszClass ) { fg_DebugClass = fgDebugStrToClass( pszClass ); fprintf( stderr, "fg_debug.c: Environment overrides default debug class (0x%08X)\n", fg_DebugClass ); } /* } */ FG_RELEASEDEBUGSEM; } /* fgDebugStrToClass ======================================================*/ fgDebugClass fgDebugStrToClass( char *str ) { char *hex = "0123456789ABCDEF"; char *hexl = "0123456789abcdef"; char *pt, *p, *ph, ps = 1; unsigned int val = 0, i; if( str == NULL ) { return 0; } /* Check for 0xXXXXXX notation */ p = strstr( str, "0x"); if( p ) { p++; p++; while (*p) { ph = strchr(hex,*p); if ( ph ) { val <<= 4; val += ph-hex; p++; } else { ph = strchr(hexl,*p); if ( ph ) { val <<= 4; val += ph-hex; p++; } else { // fprintf( stderr, "Error in hex string '%s'\n", str ); return FG_NONE; } } } } else { /* Must be in string format */ p = str; ps = 1; while( ps ) { while( *p && (*p==' ' || *p=='\t') ) p++; /* remove whitespace */ pt = p; /* mark token */ while( *p && (*p!='|') ) p++; /* find OR or EOS */ ps = *p; /* save value at p so we can attempt to be bounds safe */ *p++ = 0; /* terminate token */ /* determine value for token */ i=0; while( fg_DebugClasses[i].str && strncmp( fg_DebugClasses[i].str, pt, strlen(fg_DebugClasses[i].str)) ) i++; if( fg_DebugClasses[i].str == NULL ) { fprintf( stderr, "fg_debug.c: Could not find message class '%s'\n", pt ); } else { val |= fg_DebugClasses[i].dbg_class; } } } return (fgDebugClass)val; } /* fgSetDebugOutput =======================================================*/ void fgSetDebugOutput( FILE *out ) { FG_GRABDEBUGSEM; fflush( fg_DebugOutput ); fg_DebugOutput = out; FG_RELEASEDEBUGSEM; } /* fgSetDebugLevels =======================================================*/ void fgSetDebugLevels( fgDebugClass dbg_class, fgDebugPriority prio ) { FG_GRABDEBUGSEM; fg_DebugClass = dbg_class; fg_DebugPriority = prio; FG_RELEASEDEBUGSEM; } /* fgRegisterDebugCallback ================================================*/ fgDebugCallback fgRegisterDebugCallback( fgDebugCallback callback ) { fgDebugCallback old; FG_GRABDEBUGSEM; old = fg_DebugCallback; fg_DebugCallback = callback; FG_RELEASEDEBUGSEM; return old; } /* fgPrintf ===============================================================*/ int fgPrintf( fgDebugClass dbg_class, fgDebugPriority prio, char *fmt, ... ) { char szOut[1024+1]; va_list ap; int ret = 0; // If no action to take, then don't bother with the semaphore // activity Slight speed benefit. // printf("dbg_class = %d fg_DebugClass = %d\n", dbg_class, fg_DebugClass); // printf("prio = %d fg_DebugPriority = %d\n", prio, fg_DebugPriority); if( !(dbg_class & fg_DebugClass) ) { // Failed to match a specific debug class if ( prio < fg_DebugPriority ) { // priority is less than requested // "ret" is zero anyway. But we might think about changing // it upon some error condition? return ret; } } FG_GRABDEBUGSEM; /* ret = vsprintf( szOut, fmt, (&fmt+1)); (but it didn't work, thus ... */ va_start (ap, fmt); ret = vsprintf( szOut, fmt, ap); va_end (ap); if( fg_DebugCallback!=NULL && fg_DebugCallback(dbg_class, prio, szOut) ) { FG_RELEASEDEBUGSEM; return ret; } else { fprintf( fg_DebugOutput, szOut ); FG_RELEASEDEBUGSEM; if( prio == FG_EXIT ) { exit(0); } else if( prio == FG_ABORT ) { abort(); } } return ret; } /* $Log$ /* Revision 1.4 1998/06/01 17:49:44 curt /* Rewrote a slightly ambiguous code fragment (contributed by Charlie Hotchkiss) /* * Revision 1.3 1998/05/07 23:03:54 curt * Added an entry for AUTOPILOT. * * Revision 1.2 1998/04/21 17:03:45 curt * Prepairing for C++ integration. * * Revision 1.1 1998/04/18 03:52:04 curt * Moved to Lib directory and created a libDebug. * * Revision 1.10 1998/03/14 00:31:21 curt * Beginning initial terrain texturing experiments. * * Revision 1.9 1998/03/09 22:44:58 curt * Modified so that you can specify FG_DEBUGCLASS ***or*** FG_DEBUG_PRIORITY * * Revision 1.8 1998/03/09 22:11:00 curt * Processed through the format-o-matic. * * Revision 1.7 1998/02/16 13:39:43 curt * Miscellaneous weekend tweaks. Fixed? a cache problem that caused whole * tiles to occasionally be missing. * */