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

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOLogOutputHandler.m
       4             : By Jens Ayton
       5             : 
       6             : 
       7             : Copyright (C) 2007-2013 Jens Ayton and contributors
       8             : 
       9             : Permission is hereby granted, free of charge, to any person obtaining a copy
      10             : of this software and associated documentation files (the "Software"), to deal
      11             : in the Software without restriction, including without limitation the rights
      12             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13             : copies of the Software, and to permit persons to whom the Software is
      14             : furnished to do so, subject to the following conditions:
      15             : 
      16             : The above copyright notice and this permission notice shall be included in all
      17             : copies or substantial portions of the Software.
      18             : 
      19             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      25             : SOFTWARE.
      26             : 
      27             : */
      28             : 
      29             : 
      30           0 : #define OOLOG_POISON_NSLOG 0
      31             : 
      32             : #import "OOLogOutputHandler.h"
      33             : #import "OOLogging.h"
      34             : #import "OOAsyncQueue.h"
      35             : #include <stdlib.h>
      36             : #include <stdio.h>
      37             : #import "NSThreadOOExtensions.h"
      38             : #import "NSFileManagerOOExtensions.h"
      39             : 
      40             : 
      41             : #undef NSLog            // We need to be able to call the real NSLog.
      42             : 
      43             : 
      44             : #if OOLITE_MAC_OS_X
      45             : 
      46             : #include <dlfcn.h>
      47             : 
      48             : #ifndef NDEBUG
      49             : 
      50           0 : #define SET_CRASH_REPORTER_INFO 1
      51             : 
      52             : // Function to set "Application Specific Information" field in crash reporter log in Leopard.
      53             : // Extremely unsupported, so not used in release builds.
      54             : static void InitCrashReporterInfo(void);
      55             : static void SetCrashReporterInfo(const char *info);
      56           0 : static BOOL sCrashReporterInfoAvailable = NO;
      57             : 
      58             : #endif
      59             : 
      60             : 
      61           0 : typedef void (*LogCStringFunctionProc)(const char *string, unsigned length, BOOL withSyslogBanner);
      62           0 : typedef LogCStringFunctionProc (*LogCStringFunctionGetterProc)(void);
      63           0 : typedef void (*LogCStringFunctionSetterProc)(LogCStringFunctionProc);
      64             : 
      65           0 : static LogCStringFunctionGetterProc _NSLogCStringFunction = NULL;
      66           0 : static LogCStringFunctionSetterProc _NSSetLogCStringFunction = NULL;
      67             : 
      68             : static void LoadLogCStringFunctions(void);
      69             : static void OONSLogCStringFunction(const char *string, unsigned length, BOOL withSyslogBanner);
      70             : 
      71             : static NSString *GetAppName(void);
      72             : 
      73           0 : static LogCStringFunctionProc   sDefaultLogCStringFunction = NULL;
      74             : 
      75             : #elif OOLITE_GNUSTEP
      76             : 
      77             : static void OONSLogPrintfHandler(NSString *message);
      78             : 
      79             : #else
      80             : #error Unknown platform!
      81             : #endif
      82             : 
      83             : static BOOL DirectoryExistCreatingIfNecessary(NSString *path);
      84             : 
      85             : 
      86           0 : #define kFlushInterval  2.0             // Lower bound on interval between explicit log file flushes.
      87             : 
      88             : 
      89           0 : @interface OOAsyncLogger: NSObject
      90             : {
      91             : @private
      92           0 :         OOAsyncQueue            *messageQueue;
      93           0 :         NSConditionLock         *threadStateMonitor;
      94           0 :         NSFileHandle            *logFile;
      95           0 :         NSTimer                         *flushTimer;
      96             : }
      97             : 
      98           0 : - (void)asyncLogMessage:(NSString *)message;
      99           0 : - (void)endLogging;
     100             : 
     101           0 : - (void)changeFile;
     102             : 
     103             : // Internal
     104           0 : - (BOOL)startLogging;
     105           0 : - (void)loggerThread;
     106           0 : - (void)flushLog;
     107             : 
     108             : @end
     109             : 
     110             : 
     111           0 : static BOOL                                             sInited = NO;
     112           0 : static BOOL                                             sWriteToStderr = YES;
     113           0 : static BOOL                                             sWriteToStdout = NO;
     114           0 : static BOOL                                             sSaturated = NO;
     115           0 : static OOAsyncLogger                    *sLogger = nil;
     116           0 : static NSString                                 *sLogFileName = @"Latest.log";
     117             : 
     118             : 
     119           0 : void OOLogOutputHandlerInit(void)
     120             : {
     121             :         if (sInited)  return;
     122             :         
     123             : #if SET_CRASH_REPORTER_INFO
     124             :         InitCrashReporterInfo();
     125             : #endif
     126             :         
     127             :         sLogger = [[OOAsyncLogger alloc] init];
     128             :         sInited = YES;
     129             :         
     130             :         if (sLogger != nil)
     131             :         {
     132             :                 sWriteToStderr = [[NSUserDefaults standardUserDefaults] boolForKey:@"logging-echo-to-stderr"];
     133             :         }
     134             :         else
     135             :         {
     136             :                 sWriteToStderr = YES;
     137             :         }
     138             :         
     139             : #if OOLITE_MAC_OS_X
     140             :         LoadLogCStringFunctions();
     141             :         if (_NSSetLogCStringFunction != NULL)
     142             :         {
     143             :                 sDefaultLogCStringFunction = _NSLogCStringFunction();
     144             :                 _NSSetLogCStringFunction(OONSLogCStringFunction);
     145             :         }
     146             :         else
     147             :         {
     148             :                 OOLog(@"logging.nsLogFilter.install.failed", @"Failed to install NSLog() filter; system messages will not be logged in log file.");
     149             :         }
     150             : #elif GNUSTEP
     151             :         NSRecursiveLock *lock = GSLogLock();
     152             :         [lock lock];
     153             :         _NSLog_printf_handler = OONSLogPrintfHandler;
     154             :         [lock unlock];
     155             : #endif
     156             :         
     157             :         atexit(OOLogOutputHandlerClose);
     158             : }
     159             : 
     160             : 
     161           0 : void OOLogOutputHandlerClose(void)
     162             : {
     163             :         if (sInited)
     164             :         {
     165             :                 sWriteToStderr = YES;
     166             :                 sInited = NO;
     167             :                 
     168             :                 [sLogger endLogging];
     169             :                 DESTROY(sLogger);
     170             :                 
     171             : #if OOLITE_MAC_OS_X
     172             :                 if (sDefaultLogCStringFunction != NULL && _NSSetLogCStringFunction != NULL)
     173             :                 {
     174             :                         _NSSetLogCStringFunction(sDefaultLogCStringFunction);
     175             :                         sDefaultLogCStringFunction = NULL;
     176             :                 }
     177             : #elif GNUSTEP
     178             :                 NSRecursiveLock *lock = GSLogLock();
     179             :                 [lock lock];
     180             :                 _NSLog_printf_handler = NULL;
     181             :                 [lock unlock];
     182             : #endif
     183             :         }
     184             : }
     185             : 
     186           0 : void OOLogOutputHandlerStartLoggingToStdout()
     187             : {
     188             :         sWriteToStdout = true;
     189             : }
     190           0 : void OOLogOutputHandlerStopLoggingToStdout()
     191             : {
     192             :         sWriteToStdout = false;
     193             : }
     194             : 
     195           0 : void OOLogOutputHandlerPrint(NSString *string)
     196             : {
     197             :         if (sInited && sLogger != nil && !sWriteToStdout)  [sLogger asyncLogMessage:string];
     198             :         
     199             :         BOOL doCStringStuff = sWriteToStderr || sWriteToStdout;
     200             : #if SET_CRASH_REPORTER_INFO
     201             :         doCStringStuff = doCStringStuff || sCrashReporterInfoAvailable;
     202             : #endif
     203             :         
     204             :         if (doCStringStuff)
     205             :         {
     206             :                 const char *cStr = [[string stringByAppendingString:@"\n"] UTF8String];
     207             :                 if (sWriteToStdout)
     208             :                         fputs(cStr, stdout);
     209             :                 else if (sWriteToStderr)
     210             :                         fputs(cStr, stderr);
     211             :                 
     212             : #if SET_CRASH_REPORTER_INFO
     213             :                 if (sCrashReporterInfoAvailable)  SetCrashReporterInfo(cStr);
     214             : #endif
     215             :         }
     216             :         
     217             : }
     218             : 
     219             : 
     220           0 : NSString *OOLogHandlerGetLogPath(void)
     221             : {
     222             :         return [OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:sLogFileName];      
     223             : }
     224             : 
     225             : 
     226           0 : void OOLogOutputHandlerChangeLogFile(NSString *newLogName)
     227             : {
     228             :         if (![sLogFileName isEqual:newLogName])
     229             :         {
     230             :                 sLogFileName = [newLogName copy];
     231             :                 [sLogger changeFile];
     232             :         }
     233             : }
     234             : 
     235             : 
     236           0 : enum
     237             : {
     238             :         kConditionReadyToDealloc = 1,
     239             :         kConditionWorking
     240             : };
     241             : 
     242             : 
     243             : @implementation OOAsyncLogger
     244             : 
     245           0 : - (id)init
     246             : {
     247             :         BOOL                            OK = YES;
     248             :         NSString                        *logPath = nil;
     249             :         NSString                        *oldPath = nil;
     250             :         NSFileManager           *fmgr = nil;
     251             :         
     252             :         self = [super init];
     253             :         if (self == nil)  OK = NO;
     254             :         
     255             :         if (OK)
     256             :         {
     257             :                 fmgr = [NSFileManager defaultManager];
     258             :                 logPath = OOLogHandlerGetLogPath();
     259             :                 
     260             :                 // If there is an existing file, move it to Previous.log.
     261             :                 if ([fmgr fileExistsAtPath:logPath])
     262             :                 {
     263             :                         oldPath = [OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:@"Previous.log"];
     264             :                         [fmgr oo_removeItemAtPath:oldPath];
     265             :                         if (![fmgr oo_moveItemAtPath:logPath toPath:oldPath])
     266             :                         {
     267             :                                 if (![fmgr oo_removeItemAtPath:logPath])
     268             :                                 {
     269             :                                         NSLog(@"Log setup: could not move or delete existing log at %@, will log to stdout instead.", logPath);
     270             :                                         OK = NO;
     271             :                                 }
     272             :                         }
     273             :                 }
     274             :         }
     275             :         
     276             :         if (OK)  OK = [self startLogging];
     277             :         
     278             :         if (!OK)  DESTROY(self);
     279             :         
     280             :         return self;
     281             : }
     282             : 
     283             : 
     284           0 : - (void)dealloc
     285             : {
     286             :         DESTROY(messageQueue);
     287             :         DESTROY(threadStateMonitor);
     288             :         DESTROY(logFile);
     289             :         // We don't own a reference to flushTimer.
     290             :         
     291             :         [super dealloc];
     292             : }
     293             : 
     294             : 
     295             : - (BOOL)startLogging
     296             : {
     297             :         BOOL                            OK = YES;
     298             :         NSString                        *logPath = nil;
     299             :         NSFileManager           *fmgr = nil;
     300             :         
     301             :         fmgr = [NSFileManager defaultManager];
     302             :         
     303             :         if (OK)
     304             :         {
     305             :                 messageQueue = [[OOAsyncQueue alloc] init];
     306             :                 if (messageQueue == nil)  OK = NO;
     307             :         }
     308             :         
     309             :         if (OK)
     310             :         {
     311             :                 // set up threadStateMonitor -- used as a binary semaphore of sorts to check when the worker thread starts and stops.
     312             :                 threadStateMonitor = [[NSConditionLock alloc] initWithCondition:kConditionReadyToDealloc];
     313             :                 if (threadStateMonitor == nil)  OK = NO;
     314             :                 [threadStateMonitor setName:@"OOLogOutputHandler thread state monitor"];
     315             :         }
     316             :         
     317             :         if (OK)
     318             :         {
     319             :                 // Create work thread to actually handle messages.
     320             :                 // This needs to be done early to avoid messy state if something goes wrong.
     321             :                 [NSThread detachNewThreadSelector:@selector(loggerThread) toTarget:self withObject:nil];
     322             :                 // Wait for it to start.
     323             :                 if (![threadStateMonitor lockWhenCondition:kConditionWorking beforeDate:[NSDate dateWithTimeIntervalSinceNow:5.0]])
     324             :                 {
     325             :                         // If it doesn't signal a start within five seconds, assume something's wrong.
     326             :                         // Send kill signal, just in case it comes to life...
     327             :                         [messageQueue enqueue:@"die"];
     328             :                         // ...and stop -dealloc from waiting for thread death
     329             :                         [threadStateMonitor release];
     330             :                         threadStateMonitor = nil;
     331             :                         OK = NO;
     332             :                 }
     333             :                 [threadStateMonitor unlockWithCondition:kConditionWorking];
     334             :         }
     335             :         
     336             :         if (OK)
     337             :         {
     338             :                 logPath = OOLogHandlerGetLogPath();
     339             :                 OK = (logPath != nil);
     340             :         }
     341             :         
     342             :         if (OK)
     343             :         {
     344             :                 // Create shiny new log file
     345             :                 OK = [fmgr createFileAtPath:logPath contents:nil attributes:nil];
     346             :                 if (OK)
     347             :                 {
     348             :                         logFile = [[NSFileHandle fileHandleForWritingAtPath:logPath] retain];
     349             :                         OK = (logFile != nil);
     350             :                 }
     351             :                 if (!OK)
     352             :                 {
     353             :                         NSLog(@"Log setup: could not open log at %@, will log to stdout instead.", logPath);
     354             :                         OK = NO;
     355             :                 }
     356             :         }
     357             :         
     358             :         return OK;
     359             : }
     360             : 
     361             : 
     362             : - (void)endLogging
     363             : {
     364             :         NSString                                *postamble = nil;
     365             :         
     366             :         if (messageQueue != nil && threadStateMonitor != nil)
     367             :         {
     368             :                 // We're fully inited; write postamble, wait for worker thread to terminate cleanly, and close file.
     369             :                 postamble = [NSString stringWithFormat:@"\nClosing log at %@.", [NSDate date]];
     370             :                 [self asyncLogMessage:postamble];
     371             :                 [messageQueue enqueue:@"die"];        // Kill message
     372             :                 [threadStateMonitor lockWhenCondition:kConditionReadyToDealloc];
     373             :                 [threadStateMonitor unlock];
     374             :                 
     375             :                 [logFile closeFile];
     376             :         }
     377             : }
     378             : 
     379             : 
     380             : - (void)changeFile
     381             : {
     382             :         [self endLogging];
     383             :         if (![self startLogging])  sWriteToStderr = YES;
     384             : }
     385             : 
     386             : 
     387             : - (void)asyncLogMessage:(NSString *)message
     388             : {
     389             :         // Don't log of saturated flag is set.
     390             :         if (sSaturated)  return;
     391             :         
     392             :         if (message != nil)
     393             :         {
     394             :                 message = [message stringByAppendingString:@"\n"];
     395             :                 
     396             : #if OOLITE_WINDOWS
     397             :                 // Convert Unix line endings to Windows ones.
     398             :                 NSArray *messageComponents = [message componentsSeparatedByString:@"\n"];
     399             :                 message = [messageComponents componentsJoinedByString:@"\r\n"];
     400             : #endif
     401             :                 
     402             :                 [messageQueue enqueue:[message dataUsingEncoding:NSUTF8StringEncoding]];
     403             :                 
     404             :                 if (flushTimer == nil)
     405             :                 {
     406             :                         // No pending flush
     407             :                         flushTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushInterval target:self selector:@selector(flushLog) userInfo:nil repeats:NO];
     408             :                 }
     409             :         }
     410             : }
     411             : 
     412             : 
     413             : - (void)flushLog
     414             : {
     415             :         flushTimer = nil;
     416             :         [messageQueue enqueue:@"flush"];
     417             : }
     418             : 
     419             : 
     420             : - (void)loggerThread
     421             : {
     422             :         id                                      message = nil;
     423             :         NSAutoreleasePool       *rootPool = nil, *pool = nil;
     424             :         NSUInteger                      size = 0;
     425             :         
     426             :         rootPool = [[NSAutoreleasePool alloc] init];
     427             :         [NSThread ooSetCurrentThreadName:@"OOLogOutputHandler logging thread"];
     428             :         
     429             :         // Signal readiness
     430             :         [messageQueue retain];
     431             :         [threadStateMonitor lock];
     432             :         [threadStateMonitor unlockWithCondition:kConditionWorking];
     433             :         
     434             :         @try
     435             :         {
     436             :                 for (;;)
     437             :                 {
     438             :                         pool = [[NSAutoreleasePool alloc] init];
     439             :                         
     440             :                         message = [messageQueue dequeue];
     441             :                         
     442             :                         if (!sSaturated && [message isKindOfClass:[NSData class]])
     443             :                         {
     444             :                                 size += [message length];
     445             :                                 if (size > 1 << 30)    // 1 GiB
     446             :                                 {
     447             :                                         sSaturated = YES;
     448             : #if OOLITE_WINDOWS
     449             :                                         message = @"\r\n\r\n\r\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\r\n";
     450             : #else
     451             :                                         message = @"\n\n\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\n";
     452             : #endif
     453             :                                         message = [message dataUsingEncoding:NSUTF8StringEncoding];
     454             :                                 }
     455             :                                 
     456             :                                 [logFile writeData:message];
     457             :                         }
     458             :                         else if ([message isEqual:@"flush"])
     459             :                         {
     460             :                                 [logFile synchronizeFile];
     461             :                         }
     462             :                         else if ([message isEqual:@"die"])
     463             :                         {
     464             :                                 break;
     465             :                         }
     466             :                         
     467             :                         [pool release];
     468             :                 }
     469             :         }
     470             :         @catch (NSException *exception) {}
     471             :         [pool release];
     472             :         
     473             :         // Clean up; after this, ivars are out of bounds.
     474             :         [messageQueue release];
     475             :         [threadStateMonitor lock];
     476             :         [threadStateMonitor unlockWithCondition:kConditionReadyToDealloc];
     477             :         
     478             :         [rootPool release];
     479             : }
     480             : 
     481             : @end
     482             : 
     483             : 
     484             : #if OOLITE_MAC_OS_X
     485             : 
     486             : /*      LoadLogCStringFunctions()
     487             :         
     488             :         We wish to make NSLogv() call our custom function OONSLogCStringFunction()
     489             :         rather than printing to stdout, by calling _NSSetLogCStringFunction().
     490             :         Additionally, in order to close the logger cleanly, we wish to be able to
     491             :         restore the standard logger, which requires us to call
     492             :         _NSLogCStringFunction(). These functions are private.
     493             :         _NSLogCStringFunction() is undocumented. _NSSetLogCStringFunction() is
     494             :         documented at http://docs.info.apple.com/article.html?artnum=70081 ,
     495             :         with the warning:
     496             :         
     497             :                 Be aware that this code references private APIs; this is an
     498             :                 unsupported workaround and users should use these instructions at
     499             :                 their own risk. Apple will not guarantee or provide support for
     500             :                 this procedure.
     501             :         
     502             :         The approach taken here is to load the functions dynamically. This makes
     503             :         us safe in the case of Apple removing the functions. In the unlikely event
     504             :         that they change the functions' paramters without renaming them, we would
     505             :         have a problem.
     506             : */
     507           0 : static void LoadLogCStringFunctions(void)
     508             : {
     509             :         CFBundleRef                                             foundationBundle = NULL;
     510             :         LogCStringFunctionGetterProc    getter = NULL;
     511             :         LogCStringFunctionSetterProc    setter = NULL;
     512             :         
     513             :         foundationBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Foundation"));
     514             :         if (foundationBundle != NULL)
     515             :         {
     516             :                 getter = CFBundleGetFunctionPointerForName(foundationBundle, CFSTR("_NSLogCStringFunction"));
     517             :                 setter = CFBundleGetFunctionPointerForName(foundationBundle, CFSTR("_NSSetLogCStringFunction"));
     518             :                 
     519             :                 if (getter != NULL && setter != NULL)
     520             :                 {
     521             :                         _NSLogCStringFunction = getter;
     522             :                         _NSSetLogCStringFunction = setter;
     523             :                 }
     524             :         }
     525             : }
     526             : 
     527             : 
     528           0 : static void OONSLogCStringFunction(const char *string, unsigned length, BOOL withSyslogBanner)
     529             : {
     530             :         if (OOLogWillDisplayMessagesInClass(@"system"))
     531             :         {
     532             :                 OOLogWithFunctionFileAndLine(@"system", NULL, NULL, 0, @"%s", string);
     533             :         }
     534             : }
     535             : 
     536             : #elif OOLITE_GNUSTEP
     537             : 
     538             : static void OONSLogPrintfHandler(NSString *message)
     539             : {
     540             :         if (OOLogWillDisplayMessagesInClass(@"gnustep"))
     541             :         {
     542             :                 OOLogWithFunctionFileAndLine(@"gnustep", NULL, NULL, 0, @"%@", message);
     543             :         }
     544             : }
     545             : 
     546             : #endif
     547             : 
     548             : 
     549           0 : static BOOL DirectoryExistCreatingIfNecessary(NSString *path)
     550             : {
     551             :         BOOL                            exists, directory;
     552             :         NSFileManager           *fmgr =  [NSFileManager defaultManager];
     553             :         
     554             :         exists = [fmgr fileExistsAtPath:path isDirectory:&directory];
     555             :         
     556             :         if (exists && !directory)
     557             :         {
     558             :                 NSLog(@"Log setup: expected %@ to be a folder, but it is a file.", path);
     559             :                 return NO;
     560             :         }
     561             :         if (!exists)
     562             :         {
     563             :                 if (![fmgr oo_createDirectoryAtPath:path attributes:nil])
     564             :                 {
     565             :                         NSLog(@"Log setup: could not create folder %@.", path);
     566             :                         return NO;
     567             :                 }
     568             :         }
     569             :         
     570             :         return YES;
     571             : }
     572             : 
     573             : 
     574             : #if OOLITE_MAC_OS_X
     575             : 
     576             : static void ExcludeFromTimeMachine(NSString *path);
     577             : 
     578             : 
     579           0 : NSString *OOLogHandlerGetLogBasePath(void)
     580             : {
     581             :         static NSString         *basePath = nil;
     582             :         
     583             :         if (basePath == nil)
     584             :         {
     585             :                 // ~/Library
     586             :                 basePath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
     587             :                 
     588             :                 // ~/Library/Logs
     589             :                 basePath = [basePath stringByAppendingPathComponent:@"Logs"];
     590             :                 if (!DirectoryExistCreatingIfNecessary(basePath))  return nil;
     591             :                 
     592             :                 // ~/Library/Logs/Oolite
     593             :                 basePath = [basePath stringByAppendingPathComponent:GetAppName()];
     594             :                 if (!DirectoryExistCreatingIfNecessary(basePath))  return nil;
     595             :                 ExcludeFromTimeMachine(basePath);
     596             :                 
     597             :                 [basePath retain];
     598             :         }
     599             :         
     600             :         return basePath;
     601             : }
     602             : 
     603             : 
     604           0 : static void ExcludeFromTimeMachine(NSString *path)
     605             : {
     606             :         OSStatus (*CSBackupSetItemExcluded)(NSURL *item, Boolean exclude, Boolean excludeByPath) = NULL;
     607             :         CFBundleRef carbonCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices.CarbonCore"));
     608             :         if (carbonCoreBundle)
     609             :         {
     610             :                 CSBackupSetItemExcluded = CFBundleGetFunctionPointerForName(carbonCoreBundle, CFSTR("CSBackupSetItemExcluded"));
     611             :                 if (CSBackupSetItemExcluded != NULL)
     612             :                 {
     613             :                         (void)CSBackupSetItemExcluded([NSURL fileURLWithPath:path], YES, NO);
     614             :                 }
     615             :         }
     616             : }
     617             : 
     618             : 
     619           0 : static NSString *GetAppName(void)
     620             : {
     621             :         static NSString         *appName = nil;
     622             :         NSBundle                        *bundle = nil;
     623             :         
     624             :         if (appName == nil)
     625             :         {
     626             :                 bundle = [NSBundle mainBundle];
     627             :                 appName = [bundle objectForInfoDictionaryKey:@"CFBundleName"];
     628             :                 if (appName == nil)  appName = [bundle bundleIdentifier];
     629             :                 if (appName == nil)  appName = @"<unknown application>";
     630             :                 [appName retain];
     631             :         }
     632             :         
     633             :         return appName;
     634             : }
     635             : 
     636             : #elif OOLITE_LINUX
     637             : 
     638             : NSString *OOLogHandlerGetLogBasePath(void)
     639             : {
     640             :         static NSString         *basePath = nil;
     641             :         
     642             :         if (basePath == nil)
     643             :         {
     644             :                 // ~
     645             :                 basePath = NSHomeDirectory();
     646             :                 
     647             :                 // ~/.Oolite
     648             :                 basePath = [basePath stringByAppendingPathComponent:@".Oolite"];
     649             :                 if (!DirectoryExistCreatingIfNecessary(basePath))  return nil;
     650             :                 
     651             :                 // ~/.Oolite/Logs
     652             :                 basePath = [basePath stringByAppendingPathComponent:@"Logs"];
     653             :                 if (!DirectoryExistCreatingIfNecessary(basePath))  return nil;
     654             :                 
     655             :                 [basePath retain];
     656             :         }
     657             :         
     658             :         return basePath;
     659             : }
     660             : 
     661             : #elif OOLITE_WINDOWS
     662             : 
     663             : NSString *OOLogHandlerGetLogBasePath(void)
     664             : {
     665             :         static NSString         *basePath = nil;
     666             :         
     667             :         if (basePath == nil)
     668             :         {
     669             :                 // <Install path>\Oolite
     670             :                 basePath = NSHomeDirectory();
     671             :                 
     672             :                 // <Install path>\Oolite\Logs
     673             :                 basePath = [basePath stringByAppendingPathComponent:@"Logs"];
     674             :                 if (!DirectoryExistCreatingIfNecessary(basePath))  return nil;
     675             :                 
     676             :                 [basePath retain];
     677             :         }
     678             :         
     679             :         return basePath;
     680             : }
     681             : 
     682             : #endif
     683             : 
     684             : 
     685             : #if SET_CRASH_REPORTER_INFO
     686             : 
     687           0 : static char **sCrashReporterInfo = NULL;
     688           0 : static char *sOldCrashReporterInfo = NULL;
     689           0 : static NSLock *sCrashReporterInfoLock = nil;
     690             : 
     691             : // Evil hackery based on http://www.allocinit.net/blog/2008/01/04/application-specific-information-in-leopard-crash-reports/
     692           0 : static void InitCrashReporterInfo(void)
     693             : {
     694             :         sCrashReporterInfo = dlsym(RTLD_DEFAULT, "__crashreporter_info__");
     695             :         if (sCrashReporterInfo != NULL)
     696             :         {
     697             :                 sCrashReporterInfoLock = [[NSLock alloc] init];
     698             :                 if (sCrashReporterInfoLock != nil)
     699             :                 {
     700             :                         sCrashReporterInfoAvailable = YES;
     701             :                 }
     702             :                 else
     703             :                 {
     704             :                         sCrashReporterInfo = NULL;
     705             :                 }
     706             :         }
     707             : }
     708             : 
     709           0 : static void SetCrashReporterInfo(const char *info)
     710             : {
     711             :         char                                    *copy = NULL, *old = NULL;
     712             :         
     713             :         /*      Don't do anything if setup failed or the string is NULL or empty.
     714             :                 (The NULL and empty checks may not be desirable in other uses.)
     715             :         */
     716             :         if (!sCrashReporterInfoAvailable || info == NULL || *info == '\0')  return;
     717             :         
     718             :         // Copy the string, which we assume to be dynamic...
     719             :         copy = strdup(info);
     720             :         if (copy == NULL)  return;
     721             :         
     722             :         /*      ...and swap it in.
     723             :                 Note that we keep a separate pointer to the old value, in case
     724             :                 something else overwrites __crashreporter_info__.
     725             :         */
     726             :         [sCrashReporterInfoLock lock];
     727             :         *sCrashReporterInfo = copy;
     728             :         old = sOldCrashReporterInfo;
     729             :         sOldCrashReporterInfo = copy;
     730             :         [sCrashReporterInfoLock unlock];
     731             :         
     732             :         // Delete our old string.
     733             :         if (old != NULL)  free(old);
     734             : }
     735             : 
     736             : #endif

Generated by: LCOV version 1.14