Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
OOLogging.m
Go to the documentation of this file.
1/*
2
3OOLogging.m
4
5
6Copyright (C) 2007-2013 Jens Ayton and contributors
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25
26*/
27
28
29#define OOLOG_POISON_NSLOG 0
30
31#import "OOLoggingExtended.h"
32#import "OOPListParsing.h"
34#import "ResourceManager.h"
37#import "OOLogHeader.h"
39
40#undef NSLog // We need to be able to call the real NSLog.
41
42
43#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 #define USE_INDENT_GLOBALS 0
52 static NSString * const kIndentLevelKey = @"org.aegidian.oolite.oolog.indentLevel";
53 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#define OOLOG_NOT_INITED 1
63#define OOLOG_SETTING_SET 0
64#define OOLOG_SETTING_RETRIEVE 0
65#define OOLOG_UNDEFINED_METACLASS 1
66#define OOLOG_BAD_SETTING 1
67#define OOLOG_BAD_DEFAULT_SETTING 1
68#define OOLOG_BAD_POP_INDENT 1
69#define OOLOG_EXCEPTION_IN_LOG 1
70
71
72// Used to track OOLogPushIndent()/OOLogPopIndent() state.
79
80
81// We could probably use less state variables.
82static BOOL sInited = NO;
83static NSLock *sLock = nil;
84static NSMutableDictionary *sExplicitSettings = nil;
85static NSMutableDictionary *sDerivedSettingsCache = nil;
86#if USE_INDENT_GLOBALS
87static THREAD_LOCAL unsigned sIndentLevel = 0;
88static THREAD_LOCAL OOLogIndentStackElement
89 *sIndentStack = NULL;
90#endif
91static BOOL sShowFunction = NO;
92static BOOL sShowFileAndLine = NO;
93static BOOL sShowTime = NO; // This is defaulted to YES when loading settings, but after printing log header.
94static BOOL sShowClass = NO; // Ditto.
95static BOOL sDefaultDisplay = YES;
96static BOOL sOverrideInEffect = NO;
97static 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.
100static NSString * const kTrueToken = @"on";
101static NSString * const kFalseToken = @"off";
102static NSString * const kInheritToken = @"inherit";
103
104
105// To avoid recursion/self-dependencies, OOLog gets its own logging function.
106#define OOLogInternal(cond, format, ...) do { if ((cond)) { OOLogInternal_(OOLOG_FUNCTION_NAME, format, ## __VA_ARGS__); }} while (0)
107static void OOLogInternal_(const char *inFunction, NSString *inFormat, ...);
108
109
110// Functions used internally
111static void LoadExplicitSettings(void);
112static void LoadExplicitSettingsFromDictionary(NSDictionary *inDict);
113static id ResolveDisplaySetting(NSString *inMessageClass);
114static id ResolveMetaClassReference(NSString *inMetaClass, NSMutableSet *ioSeenMetaClasses);
115
116OOINLINE unsigned GetIndentLevel(void) PURE_FUNC;
117OOINLINE void SetIndentLevel(unsigned level);
118
119
120#ifndef OOLOG_NO_FILE_NAME
121static NSMapTable *sFileNamesCache = NULL;
122#endif
123
124
125// Given a boolean, return the appropriate value for the cache dictionary.
126OOINLINE id CacheValue(BOOL inValue) PURE_FUNC;
127OOINLINE id CacheValue(BOOL inValue)
128{
129 return inValue ? kTrueToken : kFalseToken;
130}
131
132
133/* Inited()
134 Test wether OOLoggingInit() has been called.
135*/
136OOINLINE 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
144BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
145{
146 id value = nil;
147
148 if (!Inited()) return NO;
149
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
182void 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.
198 }
199 else
200 {
201 OOLogInternal(OOLOG_SETTING_SET, @"Keeping %@ %s", inClass, inFlag ? "ON" : "OFF");
202 }
203 [sLock unlock];
204}
205
206
207NSString *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
222void OOLogIndentIf(NSString *inMessageClass)
223{
224 if (OOLogWillDisplayMessagesInClass(inMessageClass)) OOLogIndent();
225}
226
227
228void 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
247OOINLINE unsigned GetIndentLevel(void)
248{
249 return sIndentLevel;
250}
251
252
253OOINLINE void SetIndentLevel(unsigned value)
254{
255 sIndentLevel = value;
256}
257
258
259void 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
273 }
274}
275
276
277void 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 }
294}
295
296#else // !USE_INDENT_GLOBALS
297
298#define INDENT_LOCK() do {} while (0)
299#define INDENT_UNLOCK() do {} while (0)
300
301
303{
304 NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
305 return [[threadDict objectForKey:kIndentLevelKey] unsignedIntValue];
306}
307
308
309OOINLINE void SetIndentLevel(unsigned value)
310{
311 NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
312 [threadDict setObject:[NSNumber numberWithUnsignedInt:value] forKey:kIndentLevelKey];
313}
314
315
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
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
366void OOLogIndent(void)
367{
368 INDENT_LOCK();
369
371
373}
374
375
376void OOLogOutdent(void)
377{
378 INDENT_LOCK();
379
380 unsigned indentLevel = GetIndentLevel();
381 if (indentLevel != 0) SetIndentLevel(indentLevel - 1);
382
384}
385
386
387void 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
397void 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
407void 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 {
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 #define INDENT_FACTOR 2 /* Spaces per indent level */
469 #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;
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
495void OOLogGenericParameterErrorForFunction(const char *inFunction)
496{
497 OOLog(kOOLogParameterError, @"***** %s: bad parameters. (This is an internal programming error, please report it.)", inFunction);
498}
499
500
502{
503 OOLog(kOOLogSubclassResponsibility, @"***** %s is a subclass responsibility. (This is an internal programming error, please report it.)", inFunction);
504}
505
506
508{
509 return sShowFunction;
510}
511
512
513void 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
526{
527 return sShowFileAndLine;
528}
529
530
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
544{
545 return sShowTime;
546}
547
548
549void 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
562{
563 return sShowClass;
564}
565
566
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
580{
581 sShowClass = !!flag; // YES or NO, not 42.
582}
583
584
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().
603
605
607
608 [pool release];
609}
610
611
613{
614 if (!sInited) return;
615
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
630
631
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];
644}
645
646NSString * const kOOLogSubclassResponsibility = @"general.error.subclassResponsibility";
647NSString * const kOOLogParameterError = @"general.error.parameterError";
648NSString * const kOOLogDeprecatedMethod = @"general.error.deprecatedMethod";
649NSString * const kOOLogAllocationFailure = @"general.error.allocationFailure";
650NSString * const kOOLogInconsistentState = @"general.error.inconsistentState";
651NSString * const kOOLogException = @"exception";
652NSString * const kOOLogFileNotFound = @"files.notFound";
653NSString * const kOOLogFileNotLoaded = @"files.notLoaded";
654NSString * const kOOLogOpenGLError = @"rendering.opengl.error";
655NSString * 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*/
662static 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*/
705static 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];
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.
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.
769
771}
772
773
774/* LoadExplicitSettingsFromDictionary()
775 Helper for LoadExplicitSettings().
776*/
777static 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*/
839NSString *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*/
861static 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*/
885static 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);
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);
905 }
906
907 // If we get here, it should be a metaclass reference.
908 return ResolveMetaClassReference(value, ioSeenMetaClasses);
909}
#define DESTROY(x)
Definition OOCocoa.h:77
#define foreachkey(VAR, DICT)
Definition OOCocoa.h:366
#define EXPECT_NOT(x)
#define OOINLINE
#define EXPECT(x)
#define PURE_FUNC
void OOPrintLogHeader(void)
Definition OOLogHeader.m:60
void OOLogOutputHandlerPrint(NSString *string)
void OOLogOutputHandlerClose(void)
void OOLogOutputHandlerInit(void)
#define OOLogOutdentIf(class)
Definition OOLogging.h:102
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define OOLogIndentIf(class)
Definition OOLogging.h:101
static BOOL sShowFunction
Definition OOLogging.m:91
void OOLogPushIndent(void)
Definition OOLogging.m:316
static BOOL sShowClass
Definition OOLogging.m:94
static NSString *const kFalseToken
Definition OOLogging.m:101
NSString *const kOOLogException
Definition OOLogging.m:651
NSString *const kOOLogOpenGLError
Definition OOLogging.m:654
NSString *const kOOLogInconsistentState
Definition OOLogging.m:650
NSString *const kOOLogDeprecatedMethod
Definition OOLogging.m:648
void OOLoggingTerminate(void)
Definition OOLogging.m:612
static NSMutableDictionary * sExplicitSettings
Definition OOLogging.m:84
OOINLINE unsigned GetIndentLevel(void) PURE_FUNC
Definition OOLogging.m:302
OOINLINE void SetIndentLevel(unsigned level)
Definition OOLogging.m:309
void OOLogPopIndent(void)
Definition OOLogging.m:340
static NSString *const kTrueToken
Definition OOLogging.m:100
static void LoadExplicitSettings(void)
Definition OOLogging.m:705
void OOLogWithPrefix(NSString *inMessageClass, const char *inFunction, const char *inFile, unsigned long inLine, NSString *inPrefix, NSString *inFormat,...)
Definition OOLogging.m:387
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
Definition OOLogging.m:144
#define OOLOG_BAD_DEFAULT_SETTING
Definition OOLogging.m:67
void OOLogWithFunctionFileAndLine(NSString *inMessageClass, const char *inFunction, const char *inFile, unsigned long inLine, NSString *inFormat,...)
Definition OOLogging.m:397
static BOOL sShowTime
Definition OOLogging.m:93
void OOLogSetShowFileAndLine(BOOL flag)
Definition OOLogging.m:531
#define OOLOG_SETTING_RETRIEVE
Definition OOLogging.m:64
void OOLogSetShowTime(BOOL flag)
Definition OOLogging.m:549
void OOLogSetShowFunction(BOOL flag)
Definition OOLogging.m:513
void OOLogWithFunctionFileAndLineAndArguments(NSString *inMessageClass, const char *inFunction, const char *inFile, unsigned long inLine, NSString *inFormat, va_list inArguments)
Definition OOLogging.m:407
static BOOL sOverrideValue
Definition OOLogging.m:97
BOOL OOLogShowFunction(void)
Definition OOLogging.m:507
NSString *const kOOLogFileNotLoaded
Definition OOLogging.m:653
void OOLogOutdent(void)
Definition OOLogging.m:376
OOINLINE BOOL Inited(void)
Definition OOLogging.m:136
static NSString *const kIndentStackKey
Definition OOLogging.m:53
static BOOL sShowFileAndLine
Definition OOLogging.m:92
void OOLoggingReloadSettings(void)
Definition OOLogging.m:626
void OOLogGenericSubclassResponsibilityForFunction(const char *inFunction)
Definition OOLogging.m:501
#define OOLOG_EXCEPTION_IN_LOG
Definition OOLogging.m:69
static NSLock * sLock
Definition OOLogging.m:83
#define OOLOG_SETTING_SET
Definition OOLogging.m:63
void OOLoggingInit(void)
Definition OOLogging.m:585
BOOL OOLogShowMessageClass(void)
Definition OOLogging.m:561
BOOL OOLogShowTime(void)
Definition OOLogging.m:543
NSString * OOLogAbbreviatedFileName(const char *inName)
Definition OOLogging.m:839
#define OOLogInternal(cond, format,...)
Definition OOLogging.m:106
static BOOL sOverrideInEffect
Definition OOLogging.m:96
static NSString *const kIndentLevelKey
Definition OOLogging.m:52
void OOLogSetDisplayMessagesInClass(NSString *inClass, BOOL inFlag)
Definition OOLogging.m:182
static BOOL sInited
Definition OOLogging.m:82
OOINLINE id CacheValue(BOOL inValue) PURE_FUNC
Definition OOLogging.m:127
#define MAX_INDENT
static void LoadExplicitSettingsFromDictionary(NSDictionary *inDict)
Definition OOLogging.m:777
#define OOLOG_UNDEFINED_METACLASS
Definition OOLogging.m:65
NSString *const kOOLogAllocationFailure
Definition OOLogging.m:649
NSString *const kOOLogParameterError
Definition OOLogging.m:647
static id ResolveDisplaySetting(NSString *inMessageClass)
Definition OOLogging.m:861
#define OOLOG_BAD_POP_INDENT
Definition OOLogging.m:68
NSString *const kOOLogUnconvertedNSLog
Definition OOLogging.m:655
NSString *const kOOLogFileNotFound
Definition OOLogging.m:652
static void OOLogInternal_(const char *inFunction, NSString *inFormat,...)
Definition OOLogging.m:662
#define OOLOG_BAD_SETTING
Definition OOLogging.m:66
void OOLogInsertMarker(void)
Definition OOLogging.m:632
NSString *const kOOLogSubclassResponsibility
Definition OOLogging.m:646
NSString * OOLogGetParentMessageClass(NSString *inClass)
Definition OOLogging.m:207
static NSString *const kInheritToken
Definition OOLogging.m:102
void OOLogSetShowMessageClass(BOOL flag)
Definition OOLogging.m:567
static NSMapTable * sFileNamesCache
Definition OOLogging.m:121
static BOOL sDefaultDisplay
Definition OOLogging.m:95
static NSMutableDictionary * sDerivedSettingsCache
Definition OOLogging.m:85
#define INDENT_LOCK()
Definition OOLogging.m:298
static id ResolveMetaClassReference(NSString *inMetaClass, NSMutableSet *ioSeenMetaClasses)
Definition OOLogging.m:885
#define INDENT_UNLOCK()
Definition OOLogging.m:299
void OOLogSetShowMessageClassTemporary(BOOL flag)
Definition OOLogging.m:579
#define OOLOG_NOT_INITED
Definition OOLogging.m:62
#define INDENT_FACTOR
BOOL OOLogShowFileAndLine(void)
Definition OOLogging.m:525
void OOLogGenericParameterErrorForFunction(const char *inFunction)
Definition OOLogging.m:495
void OOLogIndent(void)
Definition OOLogging.m:366
NSDictionary * OODictionaryFromFile(NSString *path)
return nil
NSString * builtInPath()
NSDictionary * logControlDictionary()
OOLogIndentStackElement * link
Definition OOLogging.m:76