LCOV - code coverage report
Current view: top level - Core - OOLogging.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 83 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOLogging.m
       4             : 
       5             : 
       6             : Copyright (C) 2007-2013 Jens Ayton and contributors
       7             : 
       8             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9             : of this software and associated documentation files (the "Software"), to deal
      10             : in the Software without restriction, including without limitation the rights
      11             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             : copies of the Software, and to permit persons to whom the Software is
      13             : furnished to do so, subject to the following conditions:
      14             : 
      15             : The above copyright notice and this permission notice shall be included in all
      16             : copies or substantial portions of the Software.
      17             : 
      18             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             : SOFTWARE.
      25             : 
      26             : */
      27             : 
      28             : 
      29           0 : #define OOLOG_POISON_NSLOG 0
      30             : 
      31             : #import "OOLoggingExtended.h"
      32             : #import "OOPListParsing.h"
      33             : #import "OOFunctionAttributes.h"
      34             : #import "ResourceManager.h"
      35             : #import "OOCollectionExtractors.h"
      36             : #import "NSThreadOOExtensions.h"
      37             : #import "OOLogHeader.h"
      38             : #import "OOLogOutputHandler.h"
      39             : 
      40             : #undef NSLog            // We need to be able to call the real NSLog.
      41             : 
      42             : 
      43           0 : #define PER_THREAD_INDENTATION          1
      44             : 
      45             : 
      46             : #if PER_THREAD_INDENTATION
      47             :         #if OOLITE_USE_TLS      // Define to use __thread keyword where supported
      48             :                 #define USE_INDENT_GLOBALS      1
      49             :                 #define THREAD_LOCAL            __thread
      50             :         #else
      51           0 :                 #define USE_INDENT_GLOBALS      0
      52           0 :                 static NSString * const kIndentLevelKey = @"org.aegidian.oolite.oolog.indentLevel";
      53           0 :                 static NSString * const kIndentStackKey = @"org.aegidian.oolite.oolog.indentStack";
      54             :         #endif
      55             : #else
      56             :         #define USE_INDENT_GLOBALS              1
      57             :         #define THREAD_LOCAL
      58             : #endif
      59             : 
      60             : 
      61             : // Control flags for OOLogInternal() - like message classes, but less cool.
      62           0 : #define OOLOG_NOT_INITED                        1
      63           0 : #define OOLOG_SETTING_SET                       0
      64           0 : #define OOLOG_SETTING_RETRIEVE          0
      65           0 : #define OOLOG_UNDEFINED_METACLASS       1
      66           0 : #define OOLOG_BAD_SETTING                       1
      67           0 : #define OOLOG_BAD_DEFAULT_SETTING       1
      68           0 : #define OOLOG_BAD_POP_INDENT            1
      69           0 : #define OOLOG_EXCEPTION_IN_LOG          1
      70             : 
      71             : 
      72             : // Used to track OOLogPushIndent()/OOLogPopIndent() state.
      73           0 : typedef struct OOLogIndentStackElement OOLogIndentStackElement;
      74           0 : struct OOLogIndentStackElement
      75             : {
      76           0 :         OOLogIndentStackElement         *link;
      77           0 :         unsigned                                        indent;
      78             : };
      79             : 
      80             : 
      81             : // We could probably use less state variables.
      82           0 : static BOOL                                             sInited = NO;
      83           0 : static NSLock                                   *sLock = nil;
      84           0 : static NSMutableDictionary              *sExplicitSettings = nil;
      85           0 : static NSMutableDictionary              *sDerivedSettingsCache = nil;
      86             : #if USE_INDENT_GLOBALS
      87             : static THREAD_LOCAL unsigned    sIndentLevel = 0;
      88             : static THREAD_LOCAL OOLogIndentStackElement
      89             :                                                                 *sIndentStack = NULL;
      90             : #endif
      91           0 : static BOOL                                             sShowFunction = NO;
      92           0 : static BOOL                                             sShowFileAndLine = NO;
      93           0 : static BOOL                                             sShowTime = NO;         // This is defaulted to YES when loading settings, but after printing log header.
      94           0 : static BOOL                                             sShowClass = NO;        // Ditto.
      95           0 : static BOOL                                             sDefaultDisplay = YES;
      96           0 : static BOOL                                             sOverrideInEffect = NO;
      97           0 : static BOOL                                             sOverrideValue = NO;
      98             : 
      99             : // These specific values are used for true, false and inherit in the cache and explicitSettings dictionaries so we can use pointer comparison.
     100           0 : static NSString * const                 kTrueToken = @"on";
     101           0 : static NSString * const                 kFalseToken = @"off";
     102           0 : static NSString * const                 kInheritToken = @"inherit";
     103             : 
     104             : 
     105             : // To avoid recursion/self-dependencies, OOLog gets its own logging function.
     106           0 : #define OOLogInternal(cond, format, ...) do { if ((cond)) { OOLogInternal_(OOLOG_FUNCTION_NAME, format, ## __VA_ARGS__); }} while (0)
     107             : static void OOLogInternal_(const char *inFunction, NSString *inFormat, ...);
     108             : 
     109             : 
     110             : // Functions used internally
     111             : static void LoadExplicitSettings(void);
     112             : static void LoadExplicitSettingsFromDictionary(NSDictionary *inDict);
     113             : static id ResolveDisplaySetting(NSString *inMessageClass);
     114             : static id ResolveMetaClassReference(NSString *inMetaClass, NSMutableSet *ioSeenMetaClasses);
     115             : 
     116             : OOINLINE unsigned GetIndentLevel(void) PURE_FUNC;
     117             : OOINLINE void SetIndentLevel(unsigned level);
     118             : 
     119             : 
     120             : #ifndef OOLOG_NO_FILE_NAME
     121           0 : static NSMapTable                               *sFileNamesCache = NULL;
     122             : #endif
     123             : 
     124             : 
     125             : // Given a boolean, return the appropriate value for the cache dictionary.
     126             : OOINLINE id CacheValue(BOOL inValue) PURE_FUNC;
     127           0 : OOINLINE id CacheValue(BOOL inValue)
     128             : {
     129             :         return inValue ? kTrueToken : kFalseToken;
     130             : }
     131             : 
     132             : 
     133             : /*      Inited()
     134             :         Test wether OOLoggingInit() has been called.
     135             : */
     136           0 : OOINLINE BOOL Inited(void)
     137             : {
     138             :         if (EXPECT(sInited)) return YES;
     139             :         OOLogInternal(OOLOG_NOT_INITED, @"***** ERROR: OOLoggingInit() has not been called.");
     140             :         return NO;
     141             : }
     142             : 
     143             : 
     144           0 : BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
     145             : {
     146             :         id                              value = nil;
     147             :         
     148             :         if (!Inited()) return NO;
     149             :         
     150             :         if (sOverrideInEffect)  return sOverrideValue;
     151             :         
     152             :         [sLock lock];
     153             :         
     154             :         // Look for cached value
     155             :         value = [sDerivedSettingsCache objectForKey:inMessageClass];
     156             :         if (EXPECT_NOT(value == nil))
     157             :         {
     158             :                 @try
     159             :                 {
     160             :                         // No cached value.
     161             :                         value = ResolveDisplaySetting(inMessageClass);
     162             :                         
     163             :                         if (value != nil)
     164             :                         {
     165             :                                 if (EXPECT_NOT(sDerivedSettingsCache == nil)) sDerivedSettingsCache = [[NSMutableDictionary alloc] init];
     166             :                                 [sDerivedSettingsCache setObject:value forKey:inMessageClass];
     167             :                         }
     168             :                 }
     169             :                 @catch (id exception)
     170             :                 {
     171             :                         [sLock unlock];
     172             :                         @throw exception;
     173             :                 }
     174             :         }
     175             :         [sLock unlock];
     176             :         
     177             :         OOLogInternal(OOLOG_SETTING_RETRIEVE, @"%@ is %s", inMessageClass, (value == kTrueToken) ? "on" : "off");
     178             :         return value == kTrueToken;
     179             : }
     180             : 
     181             : 
     182           0 : void OOLogSetDisplayMessagesInClass(NSString *inClass, BOOL inFlag)
     183             : {
     184             :         id                              value = nil;
     185             :         
     186             :         if (!Inited()) return;
     187             :         
     188             :         [sLock lock];
     189             :         value = [sExplicitSettings objectForKey:inClass];
     190             :         if (value == nil || value != CacheValue(inFlag))
     191             :         {
     192             :                 OOLogInternal(OOLOG_SETTING_SET, @"Setting %@ to %s", inClass, inFlag ? "ON" : "OFF");
     193             :                 
     194             :                 [sExplicitSettings setObject:CacheValue(inFlag) forKey:inClass];
     195             :                 
     196             :                 // Clear cache and let it be rebuilt as needed.
     197             :                 DESTROY(sDerivedSettingsCache);
     198             :         }
     199             :         else
     200             :         {
     201             :                 OOLogInternal(OOLOG_SETTING_SET, @"Keeping %@ %s", inClass, inFlag ? "ON" : "OFF");
     202             :         }
     203             :         [sLock unlock];
     204             : }
     205             : 
     206             : 
     207           0 : NSString *OOLogGetParentMessageClass(NSString *inClass)
     208             : {
     209             :         NSRange                                 range;
     210             :         
     211             :         if (inClass == nil) return nil;
     212             :         
     213             :         range = [inClass rangeOfString:@"." options:NSCaseInsensitiveSearch | NSLiteralSearch | NSBackwardsSearch];   // Only NSBackwardsSearch is important, others are optimizations
     214             :         if (range.location == NSNotFound) return nil;
     215             :         
     216             :         return [inClass substringToIndex:range.location];
     217             : }
     218             : 
     219             : 
     220             : #if !OOLOG_SHORT_CIRCUIT
     221             : 
     222             : void OOLogIndentIf(NSString *inMessageClass)
     223             : {
     224             :         if (OOLogWillDisplayMessagesInClass(inMessageClass)) OOLogIndent();
     225             : }
     226             : 
     227             : 
     228             : void OOLogOutdentIf(NSString *inMessageClass)
     229             : {
     230             :         if (OOLogWillDisplayMessagesInClass(inMessageClass)) OOLogOutdent();
     231             : }
     232             : 
     233             : #endif
     234             : 
     235             : 
     236             : #if USE_INDENT_GLOBALS
     237             : 
     238             : #if OOLITE_USE_TLS
     239             :         #define INDENT_LOCK()           do {} while (0)
     240             :         #define INDENT_UNLOCK()         do {} while (0)
     241             : #else
     242             :         #define INDENT_LOCK()           [sLock lock]
     243             :         #define INDENT_UNLOCK()         [sLock unlock]
     244             : #endif
     245             : 
     246             : 
     247             : OOINLINE unsigned GetIndentLevel(void)
     248             : {
     249             :         return sIndentLevel;
     250             : }
     251             : 
     252             : 
     253             : OOINLINE void SetIndentLevel(unsigned value)
     254             : {
     255             :         sIndentLevel = value;
     256             : }
     257             : 
     258             : 
     259             : void OOLogPushIndent(void)
     260             : {
     261             :         OOLogIndentStackElement *elem = NULL;
     262             :         
     263             :         elem = malloc(sizeof *elem);
     264             :         if (elem != NULL)
     265             :         {
     266             :                 INDENT_LOCK();
     267             :                 
     268             :                 elem->indent = sIndentLevel;
     269             :                 elem->link = sIndentStack;
     270             :                 sIndentStack = elem;
     271             :                 
     272             :                 INDENT_UNLOCK();
     273             :         }
     274             : }
     275             : 
     276             : 
     277             : void OOLogPopIndent(void)
     278             : {
     279             :         INDENT_LOCK();
     280             :         
     281             :         OOLogIndentStackElement *elem = sIndentStack;
     282             :         
     283             :         if (elem != NULL)
     284             :         {
     285             :                 sIndentStack = elem->link;
     286             :                 sIndentLevel = elem->indent;
     287             :                 free(elem);
     288             :         }
     289             :         else
     290             :         {
     291             :                 OOLogInternal(OOLOG_BAD_POP_INDENT, @"OOLogPopIndent(): state stack underflow.");
     292             :         }
     293             :         INDENT_UNLOCK();
     294             : }
     295             : 
     296             : #else   // !USE_INDENT_GLOBALS
     297             : 
     298           0 : #define INDENT_LOCK()                   do {} while (0)
     299           0 : #define INDENT_UNLOCK()                 do {} while (0)
     300             : 
     301             : 
     302           0 : OOINLINE unsigned GetIndentLevel(void)
     303             : {
     304             :         NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
     305             :         return [[threadDict objectForKey:kIndentLevelKey] unsignedIntValue];
     306             : }
     307             : 
     308             : 
     309           0 : OOINLINE void SetIndentLevel(unsigned value)
     310             : {
     311             :         NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
     312             :         [threadDict setObject:[NSNumber numberWithUnsignedInt:value] forKey:kIndentLevelKey];
     313             : }
     314             : 
     315             : 
     316           0 : void OOLogPushIndent(void)
     317             : {
     318             :         OOLogIndentStackElement *elem = NULL;
     319             :         NSMutableDictionary             *threadDict = nil;
     320             :         NSValue                                 *val = nil;
     321             :         
     322             :         elem = malloc(sizeof *elem);
     323             :         if (elem != NULL)
     324             :         {
     325             :                 threadDict = [[NSThread currentThread] threadDictionary];
     326             :                 val = [threadDict objectForKey:kIndentStackKey];
     327             :                 
     328             :                 elem->indent = [[threadDict objectForKey:kIndentLevelKey] intValue];
     329             :                 elem->link = [val pointerValue];
     330             :                 
     331             :                 /*
     332             :                         Clang static analyzer reports elem not released here. It is in fact
     333             :                         released in OOLogPopIndent().
     334             :                 */
     335             :                 [threadDict setObject:[NSValue valueWithPointer:elem] forKey:kIndentStackKey];
     336             :         }
     337             : }
     338             : 
     339             : 
     340           0 : void OOLogPopIndent(void)
     341             : {
     342             :         OOLogIndentStackElement *elem = NULL;
     343             :         NSMutableDictionary             *threadDict = nil;
     344             :         NSValue                                 *val = nil;
     345             :         
     346             :         threadDict = [[NSThread currentThread] threadDictionary];
     347             :         val = [threadDict objectForKey:kIndentStackKey];
     348             :         
     349             :         elem = [val pointerValue];
     350             :         
     351             :         if (elem != NULL)
     352             :         {
     353             :                 [threadDict setObject:[NSNumber numberWithUnsignedInt:elem->indent] forKey:kIndentLevelKey];
     354             :                 [threadDict setObject:[NSValue valueWithPointer:elem->link] forKey:kIndentStackKey];
     355             :                 free(elem);
     356             :         }
     357             :         else
     358             :         {
     359             :                 OOLogInternal(OOLOG_BAD_POP_INDENT, @"OOLogPopIndent(): state stack underflow.");
     360             :         }
     361             : }
     362             : 
     363             : #endif  // USE_INDENT_GLOBALS
     364             : 
     365             : 
     366           0 : void OOLogIndent(void)
     367             : {
     368             :         INDENT_LOCK();
     369             : 
     370             :         SetIndentLevel(GetIndentLevel() + 1);
     371             :         
     372             :         INDENT_UNLOCK();
     373             : }
     374             : 
     375             : 
     376           0 : void OOLogOutdent(void)
     377             : {
     378             :         INDENT_LOCK();
     379             :         
     380             :         unsigned indentLevel = GetIndentLevel();
     381             :         if (indentLevel != 0)  SetIndentLevel(indentLevel - 1);
     382             :         
     383             :         INDENT_UNLOCK();
     384             : }
     385             : 
     386             : 
     387           0 : void OOLogWithPrefix(NSString *inMessageClass, const char *inFunction, const char *inFile, unsigned long inLine, NSString *inPrefix, NSString *inFormat, ...)
     388             : {
     389             :         if (!OOLogWillDisplayMessagesInClass(inMessageClass)) return;
     390             :         va_list                         args;
     391             :         va_start(args, inFormat);
     392             :         OOLogWithFunctionFileAndLineAndArguments(inMessageClass, inFunction, inFile, inLine, [inPrefix stringByAppendingString:inFormat], args);
     393             :         va_end(args);
     394             : }
     395             : 
     396             : 
     397           0 : void OOLogWithFunctionFileAndLine(NSString *inMessageClass, const char *inFunction, const char *inFile, unsigned long inLine, NSString *inFormat, ...)
     398             : {
     399             :         va_list                         args;
     400             :         
     401             :         va_start(args, inFormat);
     402             :         OOLogWithFunctionFileAndLineAndArguments(inMessageClass, inFunction, inFile, inLine, inFormat, args);
     403             :         va_end(args);
     404             : }
     405             : 
     406             : 
     407           0 : void OOLogWithFunctionFileAndLineAndArguments(NSString *inMessageClass, const char *inFunction, const char *inFile, unsigned long inLine, NSString *inFormat, va_list inArguments)
     408             : {
     409             :         NSAutoreleasePool       *pool = nil;
     410             :         NSString                        *formattedMessage = nil;
     411             :         unsigned                        indentLevel;
     412             :         
     413             :         if (inFormat == nil)  return;
     414             :         
     415             : #if !OOLOG_SHORT_CIRCUIT
     416             :         if (!OOLogWillDisplayMessagesInClass(inMessageClass))  return;
     417             : #endif
     418             :         
     419             :         pool = [[NSAutoreleasePool alloc] init];
     420             :         @try
     421             :         {
     422             :                 // Do argument substitution
     423             :                 formattedMessage = [[[NSString alloc] initWithFormat:inFormat arguments:inArguments] autorelease];
     424             :                 
     425             :                 // Apply various prefix options
     426             :         #ifndef OOLOG_NO_FILE_NAME
     427             :                 if (sShowFileAndLine && inFile != NULL)
     428             :                 {
     429             :                         if (sShowFunction)
     430             :                         {
     431             :                                 formattedMessage = [NSString stringWithFormat:@"%s (%@:%lu): %@", inFunction, OOLogAbbreviatedFileName(inFile), inLine, formattedMessage];
     432             :                         }
     433             :                         else
     434             :                         {
     435             :                                 formattedMessage = [NSString stringWithFormat:@"%@:%lu: %@", OOLogAbbreviatedFileName(inFile), inLine, formattedMessage];
     436             :                         }
     437             :                 }
     438             :                 else
     439             :         #endif
     440             :                 {
     441             :                         if (sShowFunction)
     442             :                         {
     443             :                                 formattedMessage = [NSString stringWithFormat:@"%s: %@", inFunction, formattedMessage];
     444             :                         }
     445             :                 }
     446             :                 
     447             :                 if (sShowClass)
     448             :                 {
     449             :                         if (sShowFunction || sShowFileAndLine)
     450             :                         {
     451             :                                 formattedMessage = [NSString stringWithFormat:@"[%@] %@", inMessageClass, formattedMessage];
     452             :                         }
     453             :                         else
     454             :                         {
     455             :                                 formattedMessage = [NSString stringWithFormat:@"[%@]: %@", inMessageClass, formattedMessage];
     456             :                         }
     457             :                 }
     458             :                 
     459             :                 if (sShowTime)
     460             :                 {
     461             :                         formattedMessage = [NSString stringWithFormat:@"%@ %@", [[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S.%F" timeZone:nil locale:nil], formattedMessage];
     462             :                 }
     463             :                 
     464             :                 // Apply indentation
     465             :                 indentLevel = GetIndentLevel();
     466             :                 if (indentLevel != 0)
     467             :                 {
     468           0 :                         #define INDENT_FACTOR   2               /* Spaces per indent level */
     469           0 :                         #define MAX_INDENT              64              /* Maximum number of indentation _spaces_ */
     470             :                         
     471             :                         unsigned                        indent;
     472             :                                                                 // String of 64 spaces (null-terminated)
     473             :                         const char                      spaces[MAX_INDENT + 1] =
     474             :                                                                 "                                                                ";
     475             :                         const char                      *indentString;
     476             :                         
     477             :                         indent = INDENT_FACTOR * indentLevel;
     478             :                         if (MAX_INDENT < indent) indent = MAX_INDENT;
     479             :                         indentString = &spaces[MAX_INDENT - indent];
     480             :                         
     481             :                         formattedMessage = [NSString stringWithFormat:@"%s%@", indentString, formattedMessage];
     482             :                 }
     483             :                 
     484             :                 OOLogOutputHandlerPrint(formattedMessage);
     485             :         }
     486             :         @catch (NSException *exception)
     487             :         {
     488             :                 OOLogInternal(OOLOG_EXCEPTION_IN_LOG, @"***** Exception thrown during logging: %@ : %@", [exception name], [exception reason]);
     489             :         }
     490             :         
     491             :         [pool release];
     492             : }
     493             : 
     494             : 
     495           0 : void OOLogGenericParameterErrorForFunction(const char *inFunction)
     496             : {
     497             :         OOLog(kOOLogParameterError, @"***** %s: bad parameters. (This is an internal programming error, please report it.)", inFunction);
     498             : }
     499             : 
     500             : 
     501           0 : void OOLogGenericSubclassResponsibilityForFunction(const char *inFunction)
     502             : {
     503             :         OOLog(kOOLogSubclassResponsibility, @"***** %s is a subclass responsibility. (This is an internal programming error, please report it.)", inFunction);
     504             : }
     505             : 
     506             : 
     507           0 : BOOL OOLogShowFunction(void)
     508             : {
     509             :         return sShowFunction;
     510             : }
     511             : 
     512             : 
     513           0 : void OOLogSetShowFunction(BOOL flag)
     514             : {
     515             :         flag = !!flag;  // YES or NO, not 42.
     516             :         
     517             :         if (flag != sShowFunction)
     518             :         {
     519             :                 sShowFunction = flag;
     520             :                 [[NSUserDefaults standardUserDefaults] setBool:flag forKey:@"logging-show-function"];
     521             :         }
     522             : }
     523             : 
     524             : 
     525           0 : BOOL OOLogShowFileAndLine(void)
     526             : {
     527             :         return sShowFileAndLine;
     528             : }
     529             : 
     530             : 
     531           0 : void OOLogSetShowFileAndLine(BOOL flag)
     532             : {
     533             :         flag = !!flag;  // YES or NO, not 42.
     534             :         
     535             :         if (flag != sShowFileAndLine)
     536             :         {
     537             :                 sShowFileAndLine = flag;
     538             :                 [[NSUserDefaults standardUserDefaults] setBool:flag forKey:@"logging-show-file-and-line"];
     539             :         }
     540             : }
     541             : 
     542             : 
     543           0 : BOOL OOLogShowTime(void)
     544             : {
     545             :         return sShowTime;
     546             : }
     547             : 
     548             : 
     549           0 : void OOLogSetShowTime(BOOL flag)
     550             : {
     551             :         flag = !!flag;  // YES or NO, not 42.
     552             :         
     553             :         if (flag != sShowTime)
     554             :         {
     555             :                 sShowTime = flag;
     556             :                 [[NSUserDefaults standardUserDefaults] setBool:flag forKey:@"logging-show-time"];
     557             :         }
     558             : }
     559             : 
     560             : 
     561           0 : BOOL OOLogShowMessageClass(void)
     562             : {
     563             :         return sShowClass;
     564             : }
     565             : 
     566             : 
     567           0 : void OOLogSetShowMessageClass(BOOL flag)
     568             : {
     569             :         flag = !!flag;  // YES or NO, not 42.
     570             :         
     571             :         if (flag != sShowClass)
     572             :         {
     573             :                 sShowClass = flag;
     574             :                 [[NSUserDefaults standardUserDefaults] setBool:flag forKey:@"logging-show-class"];
     575             :         }
     576             : }
     577             : 
     578             : 
     579           0 : void OOLogSetShowMessageClassTemporary(BOOL flag)
     580             : {
     581             :         sShowClass = !!flag;    // YES or NO, not 42.
     582             : }
     583             : 
     584             : 
     585           0 : void OOLoggingInit(void)
     586             : {
     587             :         NSAutoreleasePool               *pool = nil;
     588             :         
     589             :         if (sInited) return;
     590             :         
     591             :         pool = [[NSAutoreleasePool alloc] init];
     592             :         
     593             :         sLock = [[NSLock alloc] init];
     594             :         [sLock setName:@"OOLogging lock"];
     595             :         if (sLock == nil) exit(EXIT_FAILURE);
     596             :         
     597             : #ifndef OOLOG_NO_FILE_NAME
     598             :         sFileNamesCache = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSObjectMapValueCallBacks, 100);
     599             : #endif
     600             :         
     601             :         sInited = YES;  // Must be before OOLogOutputHandlerInit().
     602             :         OOLogOutputHandlerInit();
     603             :         
     604             :         OOPrintLogHeader();
     605             :         
     606             :         LoadExplicitSettings();
     607             :         
     608             :         [pool release];
     609             : }
     610             : 
     611             : 
     612           0 : void OOLoggingTerminate(void)
     613             : {
     614             :         if (!sInited) return;
     615             :         
     616             :         OOLogOutputHandlerClose();
     617             :         
     618             :         /*      We do not set sInited to NO. Instead, the output handler is required
     619             :                 to be able to handle working even after being closed. Under OS X, this
     620             :                 is done by writing to stderr in this case; on other platforms, NSLog()
     621             :                 is used and OOLogOutputHandlerClose() is a no-op.
     622             :         */
     623             : }
     624             : 
     625             : 
     626           0 : void OOLoggingReloadSettings(void)
     627             : {
     628             :         LoadExplicitSettings();
     629             : }
     630             : 
     631             : 
     632           0 : void OOLogInsertMarker(void)
     633             : {
     634             :         static unsigned         lastMarkerID = 0;
     635             :         unsigned                        thisMarkerID;
     636             :         NSString                        *marker = nil;
     637             :         
     638             :         [sLock lock];
     639             :         thisMarkerID = ++lastMarkerID;
     640             :         [sLock unlock];
     641             :         
     642             :         marker = [NSString stringWithFormat:@"\n\n========== [Marker %u] ==========", thisMarkerID];
     643             :         OOLogOutputHandlerPrint(marker);
     644             : }
     645             : 
     646           0 : NSString * const kOOLogSubclassResponsibility           = @"general.error.subclassResponsibility";
     647           0 : NSString * const kOOLogParameterError                           = @"general.error.parameterError";
     648           0 : NSString * const kOOLogDeprecatedMethod                         = @"general.error.deprecatedMethod";
     649           0 : NSString * const kOOLogAllocationFailure                        = @"general.error.allocationFailure";
     650           0 : NSString * const kOOLogInconsistentState                        = @"general.error.inconsistentState";
     651           0 : NSString * const kOOLogException                                        = @"exception";
     652           0 : NSString * const kOOLogFileNotFound                                     = @"files.notFound";
     653           0 : NSString * const kOOLogFileNotLoaded                            = @"files.notLoaded";
     654           0 : NSString * const kOOLogOpenGLError                                      = @"rendering.opengl.error";
     655           0 : NSString * const kOOLogUnconvertedNSLog                         = @"unclassified";
     656             : 
     657             : 
     658             : /*      OOLogInternal_()
     659             :         Implementation of OOLogInternal(), private logging function used by
     660             :         OOLogging so it doesn’t depend on itself (and risk recursiveness).
     661             : */
     662           0 : static void OOLogInternal_(const char *inFunction, NSString *inFormat, ...)
     663             : {
     664             :         va_list                         args;
     665             :         NSString                        *formattedMessage = nil;
     666             :         NSAutoreleasePool       *pool = nil;
     667             :         
     668             :         pool = [[NSAutoreleasePool alloc] init];
     669             :         
     670             :         @try
     671             :         {
     672             :                 va_start(args, inFormat);
     673             :                 formattedMessage = [[[NSString alloc] initWithFormat:inFormat arguments:args] autorelease];
     674             :                 va_end(args);
     675             :                 
     676             :                 formattedMessage = [NSString stringWithFormat:@"OOLogging internal - %s: %@", inFunction, formattedMessage];
     677             :                 
     678             :                 OOLogOutputHandlerPrint(formattedMessage);
     679             :         }
     680             :         @catch (NSException *exception)
     681             :         {
     682             :                 fprintf(stderr, "***** Exception in OOLogInternal_(): %s : %s", [[exception name] UTF8String], [[exception reason] UTF8String]);
     683             :         }
     684             :         
     685             :         [pool release];
     686             : }
     687             : 
     688             : 
     689             : /*      LoadExplicitSettings()
     690             :         Read settings from logcontrol.plists, merge in settings from preferences.
     691             :         
     692             :         Log settings are loaded from the following locations, from lowest to
     693             :         highest priority:
     694             :                 * logcontrol.plist inside OXPs, but only in hierarchies not defined
     695             :                   by the built-in plist.
     696             :                 * Built-in logcontrol.plist.
     697             :                 * Loose logcontrol.plist files in AddOns folders.
     698             :                 * Preferences (settable through the debug console).
     699             :         
     700             :         Because the settings are loaded very early (OOLoggingInit() time), before
     701             :         the state of strict mode has been set, OXP settings are always loaded.
     702             :         Since these generally shouldn't have any effect in strict mode, that's
     703             :         fine.
     704             : */
     705           0 : static void LoadExplicitSettings(void)
     706             : {
     707             :         // Load display settings.
     708             :         NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
     709             :         sShowFunction = [prefs oo_boolForKey:@"logging-show-function" defaultValue:NO];
     710             :         sShowFileAndLine = [prefs oo_boolForKey:@"logging-show-file-and-line" defaultValue:NO];
     711             :         sShowTime = [prefs oo_boolForKey:@"logging-show-time" defaultValue:YES];
     712             :         sShowClass = [prefs oo_boolForKey:@"logging-show-class" defaultValue:YES];
     713             :         
     714             :         NSDictionary *oldSettings = sExplicitSettings;
     715             :         
     716             :         /*
     717             :                 HACK: we look up search paths while loading settings, which touches
     718             :                 the cache, which logs stuff. To avoid spam like dataCache.retrieve.success,
     719             :                 we first load the built-in logcontrol.plist only and use it while
     720             :                 loading the full settings.
     721             :         */
     722             :         NSString *path = [[[ResourceManager builtInPath] stringByAppendingPathComponent:@"Config"]
     723             :                                           stringByAppendingPathComponent:@"logcontrol.plist"];
     724             :         sExplicitSettings = [NSMutableDictionary dictionary];
     725             :         LoadExplicitSettingsFromDictionary(OODictionaryFromFile(path));
     726             :         
     727             :         // Release previous sExplicitSettings.
     728             :         [oldSettings release];
     729             :         
     730             :         // Load new settings.
     731             :         NSDictionary *settings = [ResourceManager logControlDictionary];
     732             :         
     733             :         // Replace the old dictionary.
     734             :         sExplicitSettings = [[NSMutableDictionary alloc] init];
     735             :         
     736             :         // Populate.
     737             :         LoadExplicitSettingsFromDictionary(settings);
     738             :         
     739             :         // Get _default and _override values.
     740             :         id value = [sExplicitSettings objectForKey:@"_default"];
     741             :         if (value != nil && [value respondsToSelector:@selector(boolValue)])
     742             :         {
     743             :                 if (value == kTrueToken) sDefaultDisplay = YES;
     744             :                 else if (value == kFalseToken) sDefaultDisplay = NO;
     745             :                 else OOLogInternal(OOLOG_BAD_DEFAULT_SETTING, @"_default may not be set to a metaclass, ignoring.");
     746             :                 
     747             :                 [sExplicitSettings removeObjectForKey:@"_default"];
     748             :         }
     749             :         value = [sExplicitSettings objectForKey:@"_override"];
     750             :         if (value != nil && [value respondsToSelector:@selector(boolValue)])
     751             :         {
     752             :                 if (value == kTrueToken)
     753             :                 {
     754             :                         sOverrideInEffect = YES;
     755             :                         sOverrideValue = YES;
     756             :                 }
     757             :                 else if (value == kFalseToken)
     758             :                 {
     759             :                         sOverrideInEffect = YES;
     760             :                         sOverrideValue = NO;
     761             :                 }
     762             :                 else OOLogInternal(OOLOG_BAD_DEFAULT_SETTING, @"_override may not be set to a metaclass, ignoring.");
     763             :                 
     764             :                 [sExplicitSettings removeObjectForKey:@"_override"];
     765             :         }
     766             :         
     767             :         // Invalidate cache.
     768             :         DESTROY(sDerivedSettingsCache);
     769             :         
     770             :         OOLogInternal(OOLOG_SETTING_SET, @"Settings: %@", sExplicitSettings);
     771             : }
     772             : 
     773             : 
     774             : /*      LoadExplicitSettingsFromDictionary()
     775             :         Helper for LoadExplicitSettings().
     776             : */
     777           0 : static void LoadExplicitSettingsFromDictionary(NSDictionary *inDict)
     778             : {
     779             :         id key = nil;
     780             :         foreachkey (key, inDict)
     781             :         {
     782             :                 id value = [inDict objectForKey:key];
     783             :                 
     784             :                 /*      Supported values:
     785             :                         "yes", "true" or "on" -> kTrueToken
     786             :                         "no", "false" or "off" -> kFalseToken
     787             :                         "inherit" or "inherited" -> nil
     788             :                         NSNumber -> kTrueToken or kFalseToken
     789             :                         "$metaclass" -> "$metaclass"
     790             :                 */
     791             :                 if ([value isKindOfClass:[NSString class]])
     792             :                 {
     793             :                         if (NSOrderedSame == [value caseInsensitiveCompare:@"yes"] ||
     794             :                                 NSOrderedSame == [value caseInsensitiveCompare:@"true"] ||
     795             :                                 NSOrderedSame == [value caseInsensitiveCompare:@"on"])
     796             :                         {
     797             :                                 value = kTrueToken;
     798             :                         }
     799             :                         else if (NSOrderedSame == [value caseInsensitiveCompare:@"no"] ||
     800             :                                 NSOrderedSame == [value caseInsensitiveCompare:@"false"] ||
     801             :                                 NSOrderedSame == [value caseInsensitiveCompare:@"off"])
     802             :                         {
     803             :                                 value = kFalseToken;
     804             :                         }
     805             :                         else if (NSOrderedSame == [value caseInsensitiveCompare:@"inherit"] ||
     806             :                                 NSOrderedSame == [value caseInsensitiveCompare:@"inherited"])
     807             :                         {
     808             :                                 value = nil;
     809             :                                 [sExplicitSettings removeObjectForKey:key];
     810             :                         }
     811             :                         else if (![value hasPrefix:@"$"])
     812             :                         {
     813             :                                 OOLogInternal(OOLOG_BAD_SETTING, @"Bad setting value \"%@\" (expected yes, no, inherit or $metaclass).", value);
     814             :                                 value = nil;
     815             :                         }
     816             :                 }
     817             :                 else if ([value respondsToSelector:@selector(boolValue)])
     818             :                 {
     819             :                         value = CacheValue([value boolValue]);
     820             :                 }
     821             :                 else
     822             :                 {
     823             :                         OOLogInternal(OOLOG_BAD_SETTING, @"Bad setting value \"%@\" (expected yes, no, inherit or $metaclass).", value);
     824             :                         value = nil;
     825             :                 }
     826             :                 
     827             :                 if (value != nil)
     828             :                 {
     829             :                         [sExplicitSettings setObject:value forKey:key];
     830             :                 }
     831             :         }
     832             : }
     833             : 
     834             : 
     835             : /*      OOLogAbbreviatedFileName()
     836             :         Map full file paths provided by __FILE__ to more mananagable file names,
     837             :         with caching.
     838             : */
     839           0 : NSString *OOLogAbbreviatedFileName(const char *inName)
     840             : {
     841             :         NSString                        *name = nil;
     842             :         
     843             :         if (EXPECT_NOT(inName == NULL))  return @"unspecified file";
     844             :         
     845             :         [sLock lock];
     846             :         name = NSMapGet(sFileNamesCache, inName);
     847             :         if (EXPECT_NOT(name == nil))
     848             :         {
     849             :                 name = [[NSString stringWithUTF8String:inName] lastPathComponent];
     850             :                 NSMapInsertKnownAbsent(sFileNamesCache, inName, name);
     851             :         }
     852             :         [sLock unlock];
     853             :         
     854             :         return name;
     855             : }
     856             : 
     857             : 
     858             : /*      Look up setting for a message class in explicit settings, resolving
     859             :         inheritance and metaclasses.
     860             : */
     861           0 : static id ResolveDisplaySetting(NSString *inMessageClass)
     862             : {
     863             :         id                                      value = nil;
     864             :         NSMutableSet            *seenMetaClasses = nil;
     865             :         
     866             :         if (inMessageClass == nil) return CacheValue(sDefaultDisplay);
     867             :         
     868             :         value = [sExplicitSettings objectForKey:inMessageClass];
     869             :         
     870             :         // Simple case: explicit setting for this value
     871             :         if (value == kTrueToken || value == kFalseToken) return value;
     872             :         
     873             :         // Simplish case: use inherited value
     874             :         if (value == nil || value == kInheritToken) return ResolveDisplaySetting(OOLogGetParentMessageClass(inMessageClass));
     875             :         
     876             :         // Less simple case: should be a metaclass.
     877             :         seenMetaClasses = [NSMutableSet set];
     878             :         return ResolveMetaClassReference(value, seenMetaClasses);
     879             : }
     880             : 
     881             : 
     882             : /*      Resolve a metaclass reference, recursively if necessary. The
     883             :         ioSeenMetaClasses dictionary is used to avoid loops.
     884             : */
     885           0 : static id ResolveMetaClassReference(NSString *inMetaClass, NSMutableSet *ioSeenMetaClasses)
     886             : {
     887             :         id                                      value = nil;
     888             :         
     889             :         // All values should have been checked at load time, but what the hey.
     890             :         if (![inMetaClass isKindOfClass:[NSString class]] || ![inMetaClass hasPrefix:@"$"])
     891             :         {
     892             :                 OOLogInternal(OOLOG_BAD_SETTING, @"Bad setting value \"%@\" (expected yes, no, inherit or $metaclass). Falling back to _default.", inMetaClass);
     893             :                 return CacheValue(sDefaultDisplay);
     894             :         }
     895             :         
     896             :         [ioSeenMetaClasses addObject:inMetaClass];
     897             :         
     898             :         value = [sExplicitSettings objectForKey:inMetaClass];
     899             :         
     900             :         if (value == kTrueToken || value == kFalseToken) return value;
     901             :         if (value == nil)
     902             :         {
     903             :                 OOLogInternal(OOLOG_UNDEFINED_METACLASS, @"Reference to undefined metaclass %@, falling back to _default.", inMetaClass);
     904             :                 return CacheValue(sDefaultDisplay);
     905             :         }
     906             :         
     907             :         // If we get here, it should be a metaclass reference.
     908             :         return ResolveMetaClassReference(value, ioSeenMetaClasses);
     909             : }

Generated by: LCOV version 1.14