appjam 0.1.8.6 → 0.1.8.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/lib/appjam.rb +1 -1
  2. data/lib/appjam/generators/blank.rb +133 -0
  3. data/lib/appjam/generators/help.rb +5 -3
  4. data/lib/appjam/generators/templates/blank/EiffelApplication.xcodeproj/project.pbxproj +855 -0
  5. data/lib/appjam/generators/templates/blank/EiffelApplication.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  6. data/lib/appjam/generators/templates/blank/EiffelApplication.xcodeproj/project.xcworkspace/xcuserdata/eiffel.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  7. data/lib/appjam/generators/templates/blank/EiffelApplication.xcodeproj/xcuserdata/eiffel.xcuserdatad/xcschemes/EiffelApplication.xcscheme +96 -0
  8. data/lib/appjam/generators/templates/blank/EiffelApplication.xcodeproj/xcuserdata/eiffel.xcuserdatad/xcschemes/xcschememanagement.plist +27 -0
  9. data/lib/appjam/generators/templates/blank/EiffelApplication/AppDelegate.h.tt +22 -0
  10. data/lib/appjam/generators/templates/blank/EiffelApplication/AppDelegate.m.tt +156 -0
  11. data/lib/appjam/generators/templates/blank/EiffelApplication/EiffelApplication-Info.plist +45 -0
  12. data/lib/appjam/generators/templates/blank/EiffelApplication/EiffelApplication-Prefix.pch.tt +30 -0
  13. data/lib/appjam/generators/templates/blank/EiffelApplication/en.lproj/InfoPlist.strings +2 -0
  14. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFHTTPClient.h +636 -0
  15. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFHTTPClient.m +1359 -0
  16. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFHTTPRequestOperation.h +133 -0
  17. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFHTTPRequestOperation.m +318 -0
  18. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFImageRequestOperation.h +108 -0
  19. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFImageRequestOperation.m +234 -0
  20. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFJSONRequestOperation.h +71 -0
  21. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFJSONRequestOperation.m +142 -0
  22. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFNetworkActivityIndicatorManager.h +75 -0
  23. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFNetworkActivityIndicatorManager.m +145 -0
  24. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFNetworking.h +43 -0
  25. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFPropertyListRequestOperation.h +68 -0
  26. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFPropertyListRequestOperation.m +142 -0
  27. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFURLConnectionOperation.h +379 -0
  28. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFURLConnectionOperation.m +818 -0
  29. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFXMLRequestOperation.h +89 -0
  30. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/AFXMLRequestOperation.m +166 -0
  31. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/UIImageView+AFNetworking.h +78 -0
  32. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFNetworking/UIImageView+AFNetworking.m +184 -0
  33. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/JSONKit/JSONKit.h +251 -0
  34. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/JSONKit/JSONKit.m +3067 -0
  35. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabase.h +155 -0
  36. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabase.m +1162 -0
  37. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabaseAdditions.h +37 -0
  38. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabaseAdditions.m +163 -0
  39. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabasePool.h +75 -0
  40. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabasePool.m +244 -0
  41. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabaseQueue.h +38 -0
  42. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMDatabaseQueue.m +176 -0
  43. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMResultSet.h +104 -0
  44. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/fmdb/FMResultSet.m +413 -0
  45. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/EGOCache/EGOCache.h +78 -0
  46. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/EGOCache/EGOCache.m +370 -0
  47. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDASLLogger.h +41 -0
  48. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDASLLogger.m +99 -0
  49. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDAbstractDatabaseLogger.h +102 -0
  50. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDAbstractDatabaseLogger.m +727 -0
  51. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDFileLogger.h +334 -0
  52. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDFileLogger.m +1353 -0
  53. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDLog.h +601 -0
  54. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDLog.m +1083 -0
  55. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDTTYLogger.h +167 -0
  56. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/DDTTYLogger.m +1479 -0
  57. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/Extensions/ContextFilterLogFormatter.h +65 -0
  58. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/Extensions/ContextFilterLogFormatter.m +191 -0
  59. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/Extensions/DispatchQueueLogFormatter.h +116 -0
  60. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Lumberjack/Extensions/DispatchQueueLogFormatter.m +251 -0
  61. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/ObjectiveMixin/Mixin.h +33 -0
  62. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/ObjectiveMixin/Mixin.m +122 -0
  63. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/USArrayWrapper.h +72 -0
  64. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/USArrayWrapper.m +305 -0
  65. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/USConstants.h +38 -0
  66. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/USDictionaryWrapper.h +57 -0
  67. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/USDictionaryWrapper.m +188 -0
  68. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/Underscore+Functional.h +89 -0
  69. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/Underscore+Functional.m +261 -0
  70. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/Underscore-Prefix.pch +7 -0
  71. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/Underscore.h +50 -0
  72. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/Underscore/Underscore.m +100 -0
  73. data/lib/appjam/generators/templates/blank/EiffelApplication/main.m.tt +18 -0
  74. data/lib/appjam/generators/templates/blank/EiffelApplicationTests/EiffelApplicationTests-Info.plist +22 -0
  75. data/lib/appjam/generators/templates/blank/EiffelApplicationTests/EiffelApplicationTests.h.tt +13 -0
  76. data/lib/appjam/generators/templates/blank/EiffelApplicationTests/EiffelApplicationTests.m.tt +32 -0
  77. data/lib/appjam/generators/templates/blank/EiffelApplicationTests/en.lproj/InfoPlist.strings +2 -0
  78. data/lib/appjam/generators/templates/resources/Default-568h@2x.png +0 -0
  79. data/lib/appjam/generators/templates/resources/Default.png +0 -0
  80. data/lib/appjam/generators/templates/resources/Default@2x.png +0 -0
  81. data/lib/appjam/generators/templates/resources/contents.tt +4 -0
  82. data/lib/appjam/version.rb +1 -1
  83. metadata +462 -326
  84. data/test/helper.rb +0 -132
  85. data/test/test_model_generator.rb +0 -28
  86. data/test/test_project_generator.rb +0 -38
@@ -0,0 +1,167 @@
1
+ #import <Foundation/Foundation.h>
2
+ #if TARGET_OS_IPHONE
3
+ #import <UIKit/UIColor.h>
4
+ #else
5
+ #import <AppKit/NSColor.h>
6
+ #endif
7
+
8
+ #import "DDLog.h"
9
+
10
+ /**
11
+ * Welcome to Cocoa Lumberjack!
12
+ *
13
+ * The project page has a wealth of documentation if you have any questions.
14
+ * https://github.com/robbiehanson/CocoaLumberjack
15
+ *
16
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
17
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
18
+ *
19
+ *
20
+ * This class provides a logger for Terminal output or Xcode console output,
21
+ * depending on where you are running your code.
22
+ *
23
+ * As described in the "Getting Started" page,
24
+ * the traditional NSLog() function directs it's output to two places:
25
+ *
26
+ * - Apple System Log (so it shows up in Console.app)
27
+ * - StdErr (if stderr is a TTY, so log statements show up in Xcode console)
28
+ *
29
+ * To duplicate NSLog() functionality you can simply add this logger and an asl logger.
30
+ * However, if you instead choose to use file logging (for faster performance),
31
+ * you may choose to use only a file logger and a tty logger.
32
+ **/
33
+
34
+ @interface DDTTYLogger : DDAbstractLogger <DDLogger>
35
+ {
36
+ NSCalendar *calendar;
37
+ NSUInteger calendarUnitFlags;
38
+
39
+ NSString *appName;
40
+ char *app;
41
+ size_t appLen;
42
+
43
+ NSString *processID;
44
+ char *pid;
45
+ size_t pidLen;
46
+
47
+ BOOL colorsEnabled;
48
+ NSMutableArray *colorProfilesArray;
49
+ NSMutableDictionary *colorProfilesDict;
50
+ }
51
+
52
+ + (DDTTYLogger *)sharedInstance;
53
+
54
+ /* Inherited from the DDLogger protocol:
55
+ *
56
+ * Formatters may optionally be added to any logger.
57
+ *
58
+ * If no formatter is set, the logger simply logs the message as it is given in logMessage,
59
+ * or it may use its own built in formatting style.
60
+ *
61
+ * More information about formatters can be found here:
62
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters
63
+ *
64
+ * The actual implementation of these methods is inherited from DDAbstractLogger.
65
+
66
+ - (id <DDLogFormatter>)logFormatter;
67
+ - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
68
+
69
+ */
70
+
71
+ /**
72
+ * Want to use different colors for different log levels?
73
+ * Enable this property.
74
+ *
75
+ * If you run the application via the Terminal (not Xcode),
76
+ * the logger will map colors to xterm-256color or xterm-color (if available).
77
+ *
78
+ * Xcode does NOT natively support colors in the Xcode debugging console.
79
+ * You'll need to install the XcodeColors plugin to see colors in the Xcode console.
80
+ * https://github.com/robbiehanson/XcodeColors
81
+ *
82
+ * The default value if NO.
83
+ **/
84
+ @property (readwrite, assign) BOOL colorsEnabled;
85
+
86
+ /**
87
+ * The default color set (foregroundColor, backgroundColor) is:
88
+ *
89
+ * - LOG_FLAG_ERROR = (red, nil)
90
+ * - LOG_FLAG_WARN = (orange, nil)
91
+ *
92
+ * You can customize the colors however you see fit.
93
+ * Please note that you are passing a flag, NOT a level.
94
+ *
95
+ * GOOD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:LOG_FLAG_INFO]; // <- Good :)
96
+ * BAD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:LOG_LEVEL_INFO]; // <- BAD! :(
97
+ *
98
+ * LOG_FLAG_INFO = 0...00100
99
+ * LOG_LEVEL_INFO = 0...00111 <- Would match LOG_FLAG_INFO and LOG_FLAG_WARN and LOG_FLAG_ERROR
100
+ *
101
+ * If you run the application within Xcode, then the XcodeColors plugin is required.
102
+ *
103
+ * If you run the application from a shell, then DDTTYLogger will automatically map the given color to
104
+ * the closest available color. (xterm-256color or xterm-color which have 256 and 16 supported colors respectively.)
105
+ *
106
+ * This method invokes setForegroundColor:backgroundColor:forFlag:context: and passes the default context (0).
107
+ **/
108
+ #if TARGET_OS_IPHONE
109
+ - (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forFlag:(int)mask;
110
+ #else
111
+ - (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forFlag:(int)mask;
112
+ #endif
113
+
114
+ /**
115
+ * Just like setForegroundColor:backgroundColor:flag, but allows you to specify a particular logging context.
116
+ *
117
+ * A logging context is often used to identify log messages coming from a 3rd party framework,
118
+ * although logging context's can be used for many different functions.
119
+ *
120
+ * Logging context's are explained in further detail here:
121
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomContext
122
+ **/
123
+ #if TARGET_OS_IPHONE
124
+ - (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forFlag:(int)mask context:(int)ctxt;
125
+ #else
126
+ - (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forFlag:(int)mask context:(int)ctxt;
127
+ #endif
128
+
129
+ /**
130
+ * Similar to the methods above, but allows you to map DDLogMessage->tag to a particular color profile.
131
+ * For example, you could do something like this:
132
+ *
133
+ * static NSString *const PurpleTag = @"PurpleTag";
134
+ *
135
+ * #define DDLogPurple(frmt, ...) LOG_OBJC_TAG_MACRO(NO, 0, 0, 0, PurpleTag, frmt, ##__VA_ARGS__)
136
+ *
137
+ * And then in your applicationDidFinishLaunching, or wherever you configure Lumberjack:
138
+ *
139
+ * #if TARGET_OS_IPHONE
140
+ * UIColor *purple = [UIColor colorWithRed:(64/255.0) green:(0/255.0) blue:(128/255.0) alpha:1.0];
141
+ * #else
142
+ * NSColor *purple = [NSColor colorWithCalibratedRed:(64/255.0) green:(0/255.0) blue:(128/255.0) alpha:1.0];
143
+ *
144
+ * [[DDTTYLogger sharedInstance] setForegroundColor:purple backgroundColor:nil forTag:PurpleTag];
145
+ * [DDLog addLogger:[DDTTYLogger sharedInstance]];
146
+ *
147
+ * This would essentially give you a straight NSLog replacement that prints in purple:
148
+ *
149
+ * DDLogPurple(@"I'm a purple log message!");
150
+ **/
151
+ #if TARGET_OS_IPHONE
152
+ - (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forTag:(id <NSCopying>)tag;
153
+ #else
154
+ - (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forTag:(id <NSCopying>)tag;
155
+ #endif
156
+
157
+ /**
158
+ * Clearing color profiles.
159
+ **/
160
+ - (void)clearColorsForFlag:(int)mask;
161
+ - (void)clearColorsForFlag:(int)mask context:(int)context;
162
+ - (void)clearColorsForTag:(id <NSCopying>)tag;
163
+ - (void)clearColorsForAllFlags;
164
+ - (void)clearColorsForAllTags;
165
+ - (void)clearAllColors;
166
+
167
+ @end
@@ -0,0 +1,1479 @@
1
+ #import "DDTTYLogger.h"
2
+
3
+ #import <unistd.h>
4
+ #import <sys/uio.h>
5
+
6
+ /**
7
+ * Welcome to Cocoa Lumberjack!
8
+ *
9
+ * The project page has a wealth of documentation if you have any questions.
10
+ * https://github.com/robbiehanson/CocoaLumberjack
11
+ *
12
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
13
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
14
+ **/
15
+
16
+ #if ! __has_feature(objc_arc)
17
+ #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
18
+ #endif
19
+
20
+ // We probably shouldn't be using DDLog() statements within the DDLog implementation.
21
+ // But we still want to leave our log statements for any future debugging,
22
+ // and to allow other developers to trace the implementation (which is a great learning tool).
23
+ //
24
+ // So we use primitive logging macros around NSLog.
25
+ // We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
26
+
27
+ #define LOG_LEVEL 2
28
+
29
+ #define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
30
+ #define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
31
+ #define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
32
+ #define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
33
+
34
+ // Xcode does NOT natively support colors in the Xcode debugging console.
35
+ // You'll need to install the XcodeColors plugin to see colors in the Xcode console.
36
+ // https://github.com/robbiehanson/XcodeColors
37
+ //
38
+ // The following is documentation from the XcodeColors project:
39
+ //
40
+ //
41
+ // How to apply color formatting to your log statements:
42
+ //
43
+ // To set the foreground color:
44
+ // Insert the ESCAPE_SEQ into your string, followed by "fg124,12,255;" where r=124, g=12, b=255.
45
+ //
46
+ // To set the background color:
47
+ // Insert the ESCAPE_SEQ into your string, followed by "bg12,24,36;" where r=12, g=24, b=36.
48
+ //
49
+ // To reset the foreground color (to default value):
50
+ // Insert the ESCAPE_SEQ into your string, followed by "fg;"
51
+ //
52
+ // To reset the background color (to default value):
53
+ // Insert the ESCAPE_SEQ into your string, followed by "bg;"
54
+ //
55
+ // To reset the foreground and background color (to default values) in one operation:
56
+ // Insert the ESCAPE_SEQ into your string, followed by ";"
57
+
58
+ #define XCODE_COLORS_ESCAPE_SEQ "\033["
59
+
60
+ #define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE_SEQ "fg;" // Clear any foreground color
61
+ #define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE_SEQ "bg;" // Clear any background color
62
+ #define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE_SEQ ";" // Clear any foreground or background color
63
+
64
+ // Some simple defines to make life easier on ourself
65
+
66
+ #if TARGET_OS_IPHONE
67
+ #define MakeColor(r, g, b) [UIColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]
68
+ #else
69
+ #define MakeColor(r, g, b) [NSColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]
70
+ #endif
71
+
72
+ #if TARGET_OS_IPHONE
73
+ #define OSColor UIColor
74
+ #else
75
+ #define OSColor NSColor
76
+ #endif
77
+
78
+ // If running in a shell, not all RGB colors will be supported.
79
+ // In this case we automatically map to the closest available color.
80
+ // In order to provide this mapping, we have a hard-coded set of the standard RGB values available in the shell.
81
+ // However, not every shell is the same, and Apple likes to think different even when it comes to shell colors.
82
+ //
83
+ // Map to standard Terminal.app colors (1), or
84
+ // map to standard xterm colors (0).
85
+
86
+ #define MAP_TO_TERMINAL_APP_COLORS 1
87
+
88
+
89
+ @interface DDTTYLoggerColorProfile : NSObject {
90
+ @public
91
+ int mask;
92
+ int context;
93
+
94
+ uint8_t fg_r;
95
+ uint8_t fg_g;
96
+ uint8_t fg_b;
97
+
98
+ uint8_t bg_r;
99
+ uint8_t bg_g;
100
+ uint8_t bg_b;
101
+
102
+ NSUInteger fgCodeIndex;
103
+ NSString *fgCodeRaw;
104
+
105
+ NSUInteger bgCodeIndex;
106
+ NSString *bgCodeRaw;
107
+
108
+ char fgCode[24];
109
+ size_t fgCodeLen;
110
+
111
+ char bgCode[24];
112
+ size_t bgCodeLen;
113
+
114
+ char resetCode[8];
115
+ size_t resetCodeLen;
116
+ }
117
+
118
+ - (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)mask context:(int)ctxt;
119
+
120
+ @end
121
+
122
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
123
+ #pragma mark -
124
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
125
+
126
+ @implementation DDTTYLogger
127
+
128
+ static BOOL isaColorTTY;
129
+ static BOOL isaColor256TTY;
130
+ static BOOL isaXcodeColorTTY;
131
+
132
+ static NSArray *codes_fg = nil;
133
+ static NSArray *codes_bg = nil;
134
+ static NSArray *colors = nil;
135
+
136
+ static DDTTYLogger *sharedInstance;
137
+
138
+ /**
139
+ * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 16 color mode.
140
+ *
141
+ * This method is used when the application is running from within a shell that only supports 16 color mode.
142
+ * This method is not invoked if the application is running within Xcode, or via normal UI app launch.
143
+ **/
144
+ + (void)initialize_colors_16
145
+ {
146
+ if (codes_fg || codes_bg || colors) return;
147
+
148
+ NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:16];
149
+ NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:16];
150
+ NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:16];
151
+
152
+ // In a standard shell only 16 colors are supported.
153
+ //
154
+ // More information about ansi escape codes can be found online.
155
+ // http://en.wikipedia.org/wiki/ANSI_escape_code
156
+
157
+ [m_codes_fg addObject:@"30m"]; // normal - black
158
+ [m_codes_fg addObject:@"31m"]; // normal - red
159
+ [m_codes_fg addObject:@"32m"]; // normal - green
160
+ [m_codes_fg addObject:@"33m"]; // normal - yellow
161
+ [m_codes_fg addObject:@"34m"]; // normal - blue
162
+ [m_codes_fg addObject:@"35m"]; // normal - magenta
163
+ [m_codes_fg addObject:@"36m"]; // normal - cyan
164
+ [m_codes_fg addObject:@"37m"]; // normal - gray
165
+ [m_codes_fg addObject:@"1;30m"]; // bright - darkgray
166
+ [m_codes_fg addObject:@"1;31m"]; // bright - red
167
+ [m_codes_fg addObject:@"1;32m"]; // bright - green
168
+ [m_codes_fg addObject:@"1;33m"]; // bright - yellow
169
+ [m_codes_fg addObject:@"1;34m"]; // bright - blue
170
+ [m_codes_fg addObject:@"1;35m"]; // bright - magenta
171
+ [m_codes_fg addObject:@"1;36m"]; // bright - cyan
172
+ [m_codes_fg addObject:@"1;37m"]; // bright - white
173
+
174
+ [m_codes_bg addObject:@"40m"]; // normal - black
175
+ [m_codes_bg addObject:@"41m"]; // normal - red
176
+ [m_codes_bg addObject:@"42m"]; // normal - green
177
+ [m_codes_bg addObject:@"43m"]; // normal - yellow
178
+ [m_codes_bg addObject:@"44m"]; // normal - blue
179
+ [m_codes_bg addObject:@"45m"]; // normal - magenta
180
+ [m_codes_bg addObject:@"46m"]; // normal - cyan
181
+ [m_codes_bg addObject:@"47m"]; // normal - gray
182
+ [m_codes_bg addObject:@"1;40m"]; // bright - darkgray
183
+ [m_codes_bg addObject:@"1;41m"]; // bright - red
184
+ [m_codes_bg addObject:@"1;42m"]; // bright - green
185
+ [m_codes_bg addObject:@"1;43m"]; // bright - yellow
186
+ [m_codes_bg addObject:@"1;44m"]; // bright - blue
187
+ [m_codes_bg addObject:@"1;45m"]; // bright - magenta
188
+ [m_codes_bg addObject:@"1;46m"]; // bright - cyan
189
+ [m_codes_bg addObject:@"1;47m"]; // bright - white
190
+
191
+ #if MAP_TO_TERMINAL_APP_COLORS
192
+
193
+ // Standard Terminal.app colors:
194
+ //
195
+ // These are the default colors used by Apple's Terminal.app.
196
+
197
+ [m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black
198
+ [m_colors addObject:MakeColor(194, 54, 33)]; // normal - red
199
+ [m_colors addObject:MakeColor( 37, 188, 36)]; // normal - green
200
+ [m_colors addObject:MakeColor(173, 173, 39)]; // normal - yellow
201
+ [m_colors addObject:MakeColor( 73, 46, 225)]; // normal - blue
202
+ [m_colors addObject:MakeColor(211, 56, 211)]; // normal - magenta
203
+ [m_colors addObject:MakeColor( 51, 187, 200)]; // normal - cyan
204
+ [m_colors addObject:MakeColor(203, 204, 205)]; // normal - gray
205
+ [m_colors addObject:MakeColor(129, 131, 131)]; // bright - darkgray
206
+ [m_colors addObject:MakeColor(252, 57, 31)]; // bright - red
207
+ [m_colors addObject:MakeColor( 49, 231, 34)]; // bright - green
208
+ [m_colors addObject:MakeColor(234, 236, 35)]; // bright - yellow
209
+ [m_colors addObject:MakeColor( 88, 51, 255)]; // bright - blue
210
+ [m_colors addObject:MakeColor(249, 53, 248)]; // bright - magenta
211
+ [m_colors addObject:MakeColor( 20, 240, 240)]; // bright - cyan
212
+ [m_colors addObject:MakeColor(233, 235, 235)]; // bright - white
213
+
214
+ #else
215
+
216
+ // Standard xterm colors:
217
+ //
218
+ // These are the default colors used by most xterm shells.
219
+
220
+ [m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black
221
+ [m_colors addObject:MakeColor(205, 0, 0)]; // normal - red
222
+ [m_colors addObject:MakeColor( 0, 205, 0)]; // normal - green
223
+ [m_colors addObject:MakeColor(205, 205, 0)]; // normal - yellow
224
+ [m_colors addObject:MakeColor( 0, 0, 238)]; // normal - blue
225
+ [m_colors addObject:MakeColor(205, 0, 205)]; // normal - magenta
226
+ [m_colors addObject:MakeColor( 0, 205, 205)]; // normal - cyan
227
+ [m_colors addObject:MakeColor(229, 229, 229)]; // normal - gray
228
+ [m_colors addObject:MakeColor(127, 127, 127)]; // bright - darkgray
229
+ [m_colors addObject:MakeColor(255, 0, 0)]; // bright - red
230
+ [m_colors addObject:MakeColor( 0, 255, 0)]; // bright - green
231
+ [m_colors addObject:MakeColor(255, 255, 0)]; // bright - yellow
232
+ [m_colors addObject:MakeColor( 92, 92, 255)]; // bright - blue
233
+ [m_colors addObject:MakeColor(255, 0, 255)]; // bright - magenta
234
+ [m_colors addObject:MakeColor( 0, 255, 255)]; // bright - cyan
235
+ [m_colors addObject:MakeColor(255, 255, 255)]; // bright - white
236
+
237
+ #endif
238
+
239
+ codes_fg = [m_codes_fg copy];
240
+ codes_bg = [m_codes_bg copy];
241
+ colors = [m_colors copy];
242
+
243
+ NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
244
+ NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
245
+ }
246
+
247
+ /**
248
+ * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 256 color mode.
249
+ *
250
+ * This method is used when the application is running from within a shell that supports 256 color mode.
251
+ * This method is not invoked if the application is running within Xcode, or via normal UI app launch.
252
+ **/
253
+ + (void)initialize_colors_256
254
+ {
255
+ if (codes_fg || codes_bg || colors) return;
256
+
257
+ NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:(256-16)];
258
+ NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:(256-16)];
259
+ NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:(256-16)];
260
+
261
+ #if MAP_TO_TERMINAL_APP_COLORS
262
+
263
+ // Standard Terminal.app colors:
264
+ //
265
+ // These are the colors the Terminal.app uses in xterm-256color mode.
266
+ // In this mode, the terminal supports 256 different colors, specified by 256 color codes.
267
+ //
268
+ // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
269
+ // These are actually configurable, and thus we ignore them for the purposes of mapping,
270
+ // as we can't rely on them being constant. They are largely duplicated anyway.
271
+ //
272
+ // The next 216 color codes are designed to run the spectrum, with several shades of every color.
273
+ // While the color codes are standardized, the actual RGB values for each color code is not.
274
+ // Apple's Terminal.app uses different RGB values from that of a standard xterm.
275
+ // Apple's choices in colors are designed to be a little nicer on the eyes.
276
+ //
277
+ // The last 24 color codes represent a grayscale.
278
+ //
279
+ // Unfortunately, unlike the standard xterm color chart,
280
+ // Apple's RGB values cannot be calculated using a simple formula (at least not that I know of).
281
+ // Also, I don't know of any ways to programmatically query the shell for the RGB values.
282
+ // So this big giant color chart had to be made by hand.
283
+ //
284
+ // More information about ansi escape codes can be found online.
285
+ // http://en.wikipedia.org/wiki/ANSI_escape_code
286
+
287
+ // Colors
288
+
289
+ [m_colors addObject:MakeColor( 47, 49, 49)];
290
+ [m_colors addObject:MakeColor( 60, 42, 144)];
291
+ [m_colors addObject:MakeColor( 66, 44, 183)];
292
+ [m_colors addObject:MakeColor( 73, 46, 222)];
293
+ [m_colors addObject:MakeColor( 81, 50, 253)];
294
+ [m_colors addObject:MakeColor( 88, 51, 255)];
295
+
296
+ [m_colors addObject:MakeColor( 42, 128, 37)];
297
+ [m_colors addObject:MakeColor( 42, 127, 128)];
298
+ [m_colors addObject:MakeColor( 44, 126, 169)];
299
+ [m_colors addObject:MakeColor( 56, 125, 209)];
300
+ [m_colors addObject:MakeColor( 59, 124, 245)];
301
+ [m_colors addObject:MakeColor( 66, 123, 255)];
302
+
303
+ [m_colors addObject:MakeColor( 51, 163, 41)];
304
+ [m_colors addObject:MakeColor( 39, 162, 121)];
305
+ [m_colors addObject:MakeColor( 42, 161, 162)];
306
+ [m_colors addObject:MakeColor( 53, 160, 202)];
307
+ [m_colors addObject:MakeColor( 45, 159, 240)];
308
+ [m_colors addObject:MakeColor( 58, 158, 255)];
309
+
310
+ [m_colors addObject:MakeColor( 31, 196, 37)];
311
+ [m_colors addObject:MakeColor( 48, 196, 115)];
312
+ [m_colors addObject:MakeColor( 39, 195, 155)];
313
+ [m_colors addObject:MakeColor( 49, 195, 195)];
314
+ [m_colors addObject:MakeColor( 32, 194, 235)];
315
+ [m_colors addObject:MakeColor( 53, 193, 255)];
316
+
317
+ [m_colors addObject:MakeColor( 50, 229, 35)];
318
+ [m_colors addObject:MakeColor( 40, 229, 109)];
319
+ [m_colors addObject:MakeColor( 27, 229, 149)];
320
+ [m_colors addObject:MakeColor( 49, 228, 189)];
321
+ [m_colors addObject:MakeColor( 33, 228, 228)];
322
+ [m_colors addObject:MakeColor( 53, 227, 255)];
323
+
324
+ [m_colors addObject:MakeColor( 27, 254, 30)];
325
+ [m_colors addObject:MakeColor( 30, 254, 103)];
326
+ [m_colors addObject:MakeColor( 45, 254, 143)];
327
+ [m_colors addObject:MakeColor( 38, 253, 182)];
328
+ [m_colors addObject:MakeColor( 38, 253, 222)];
329
+ [m_colors addObject:MakeColor( 42, 253, 252)];
330
+
331
+ [m_colors addObject:MakeColor(140, 48, 40)];
332
+ [m_colors addObject:MakeColor(136, 51, 136)];
333
+ [m_colors addObject:MakeColor(135, 52, 177)];
334
+ [m_colors addObject:MakeColor(134, 52, 217)];
335
+ [m_colors addObject:MakeColor(135, 56, 248)];
336
+ [m_colors addObject:MakeColor(134, 53, 255)];
337
+
338
+ [m_colors addObject:MakeColor(125, 125, 38)];
339
+ [m_colors addObject:MakeColor(124, 125, 125)];
340
+ [m_colors addObject:MakeColor(122, 124, 166)];
341
+ [m_colors addObject:MakeColor(123, 124, 207)];
342
+ [m_colors addObject:MakeColor(123, 122, 247)];
343
+ [m_colors addObject:MakeColor(124, 121, 255)];
344
+
345
+ [m_colors addObject:MakeColor(119, 160, 35)];
346
+ [m_colors addObject:MakeColor(117, 160, 120)];
347
+ [m_colors addObject:MakeColor(117, 160, 160)];
348
+ [m_colors addObject:MakeColor(115, 159, 201)];
349
+ [m_colors addObject:MakeColor(116, 158, 240)];
350
+ [m_colors addObject:MakeColor(117, 157, 255)];
351
+
352
+ [m_colors addObject:MakeColor(113, 195, 39)];
353
+ [m_colors addObject:MakeColor(110, 194, 114)];
354
+ [m_colors addObject:MakeColor(111, 194, 154)];
355
+ [m_colors addObject:MakeColor(108, 194, 194)];
356
+ [m_colors addObject:MakeColor(109, 193, 234)];
357
+ [m_colors addObject:MakeColor(108, 192, 255)];
358
+
359
+ [m_colors addObject:MakeColor(105, 228, 30)];
360
+ [m_colors addObject:MakeColor(103, 228, 109)];
361
+ [m_colors addObject:MakeColor(105, 228, 148)];
362
+ [m_colors addObject:MakeColor(100, 227, 188)];
363
+ [m_colors addObject:MakeColor( 99, 227, 227)];
364
+ [m_colors addObject:MakeColor( 99, 226, 253)];
365
+
366
+ [m_colors addObject:MakeColor( 92, 253, 34)];
367
+ [m_colors addObject:MakeColor( 96, 253, 103)];
368
+ [m_colors addObject:MakeColor( 97, 253, 142)];
369
+ [m_colors addObject:MakeColor( 88, 253, 182)];
370
+ [m_colors addObject:MakeColor( 93, 253, 221)];
371
+ [m_colors addObject:MakeColor( 88, 254, 251)];
372
+
373
+ [m_colors addObject:MakeColor(177, 53, 34)];
374
+ [m_colors addObject:MakeColor(174, 54, 131)];
375
+ [m_colors addObject:MakeColor(172, 55, 172)];
376
+ [m_colors addObject:MakeColor(171, 57, 213)];
377
+ [m_colors addObject:MakeColor(170, 55, 249)];
378
+ [m_colors addObject:MakeColor(170, 57, 255)];
379
+
380
+ [m_colors addObject:MakeColor(165, 123, 37)];
381
+ [m_colors addObject:MakeColor(163, 123, 123)];
382
+ [m_colors addObject:MakeColor(162, 123, 164)];
383
+ [m_colors addObject:MakeColor(161, 122, 205)];
384
+ [m_colors addObject:MakeColor(161, 121, 241)];
385
+ [m_colors addObject:MakeColor(161, 121, 255)];
386
+
387
+ [m_colors addObject:MakeColor(158, 159, 33)];
388
+ [m_colors addObject:MakeColor(157, 158, 118)];
389
+ [m_colors addObject:MakeColor(157, 158, 159)];
390
+ [m_colors addObject:MakeColor(155, 157, 199)];
391
+ [m_colors addObject:MakeColor(155, 157, 239)];
392
+ [m_colors addObject:MakeColor(154, 156, 255)];
393
+
394
+ [m_colors addObject:MakeColor(152, 193, 40)];
395
+ [m_colors addObject:MakeColor(151, 193, 113)];
396
+ [m_colors addObject:MakeColor(150, 193, 153)];
397
+ [m_colors addObject:MakeColor(150, 192, 193)];
398
+ [m_colors addObject:MakeColor(148, 192, 232)];
399
+ [m_colors addObject:MakeColor(149, 191, 253)];
400
+
401
+ [m_colors addObject:MakeColor(146, 227, 28)];
402
+ [m_colors addObject:MakeColor(144, 227, 108)];
403
+ [m_colors addObject:MakeColor(144, 227, 147)];
404
+ [m_colors addObject:MakeColor(144, 227, 187)];
405
+ [m_colors addObject:MakeColor(142, 226, 227)];
406
+ [m_colors addObject:MakeColor(142, 225, 252)];
407
+
408
+ [m_colors addObject:MakeColor(138, 253, 36)];
409
+ [m_colors addObject:MakeColor(137, 253, 102)];
410
+ [m_colors addObject:MakeColor(136, 253, 141)];
411
+ [m_colors addObject:MakeColor(138, 254, 181)];
412
+ [m_colors addObject:MakeColor(135, 255, 220)];
413
+ [m_colors addObject:MakeColor(133, 255, 250)];
414
+
415
+ [m_colors addObject:MakeColor(214, 57, 30)];
416
+ [m_colors addObject:MakeColor(211, 59, 126)];
417
+ [m_colors addObject:MakeColor(209, 57, 168)];
418
+ [m_colors addObject:MakeColor(208, 55, 208)];
419
+ [m_colors addObject:MakeColor(207, 58, 247)];
420
+ [m_colors addObject:MakeColor(206, 61, 255)];
421
+
422
+ [m_colors addObject:MakeColor(204, 121, 32)];
423
+ [m_colors addObject:MakeColor(202, 121, 121)];
424
+ [m_colors addObject:MakeColor(201, 121, 161)];
425
+ [m_colors addObject:MakeColor(200, 120, 202)];
426
+ [m_colors addObject:MakeColor(200, 120, 241)];
427
+ [m_colors addObject:MakeColor(198, 119, 255)];
428
+
429
+ [m_colors addObject:MakeColor(198, 157, 37)];
430
+ [m_colors addObject:MakeColor(196, 157, 116)];
431
+ [m_colors addObject:MakeColor(195, 156, 157)];
432
+ [m_colors addObject:MakeColor(195, 156, 197)];
433
+ [m_colors addObject:MakeColor(194, 155, 236)];
434
+ [m_colors addObject:MakeColor(193, 155, 255)];
435
+
436
+ [m_colors addObject:MakeColor(191, 192, 36)];
437
+ [m_colors addObject:MakeColor(190, 191, 112)];
438
+ [m_colors addObject:MakeColor(189, 191, 152)];
439
+ [m_colors addObject:MakeColor(189, 191, 191)];
440
+ [m_colors addObject:MakeColor(188, 190, 230)];
441
+ [m_colors addObject:MakeColor(187, 190, 253)];
442
+
443
+ [m_colors addObject:MakeColor(185, 226, 28)];
444
+ [m_colors addObject:MakeColor(184, 226, 106)];
445
+ [m_colors addObject:MakeColor(183, 225, 146)];
446
+ [m_colors addObject:MakeColor(183, 225, 186)];
447
+ [m_colors addObject:MakeColor(182, 225, 225)];
448
+ [m_colors addObject:MakeColor(181, 224, 252)];
449
+
450
+ [m_colors addObject:MakeColor(178, 255, 35)];
451
+ [m_colors addObject:MakeColor(178, 255, 101)];
452
+ [m_colors addObject:MakeColor(177, 254, 141)];
453
+ [m_colors addObject:MakeColor(176, 254, 180)];
454
+ [m_colors addObject:MakeColor(176, 254, 220)];
455
+ [m_colors addObject:MakeColor(175, 253, 249)];
456
+
457
+ [m_colors addObject:MakeColor(247, 56, 30)];
458
+ [m_colors addObject:MakeColor(245, 57, 122)];
459
+ [m_colors addObject:MakeColor(243, 59, 163)];
460
+ [m_colors addObject:MakeColor(244, 60, 204)];
461
+ [m_colors addObject:MakeColor(242, 59, 241)];
462
+ [m_colors addObject:MakeColor(240, 55, 255)];
463
+
464
+ [m_colors addObject:MakeColor(241, 119, 36)];
465
+ [m_colors addObject:MakeColor(240, 120, 118)];
466
+ [m_colors addObject:MakeColor(238, 119, 158)];
467
+ [m_colors addObject:MakeColor(237, 119, 199)];
468
+ [m_colors addObject:MakeColor(237, 118, 238)];
469
+ [m_colors addObject:MakeColor(236, 118, 255)];
470
+
471
+ [m_colors addObject:MakeColor(235, 154, 36)];
472
+ [m_colors addObject:MakeColor(235, 154, 114)];
473
+ [m_colors addObject:MakeColor(234, 154, 154)];
474
+ [m_colors addObject:MakeColor(232, 154, 194)];
475
+ [m_colors addObject:MakeColor(232, 153, 234)];
476
+ [m_colors addObject:MakeColor(232, 153, 255)];
477
+
478
+ [m_colors addObject:MakeColor(230, 190, 30)];
479
+ [m_colors addObject:MakeColor(229, 189, 110)];
480
+ [m_colors addObject:MakeColor(228, 189, 150)];
481
+ [m_colors addObject:MakeColor(227, 189, 190)];
482
+ [m_colors addObject:MakeColor(227, 189, 229)];
483
+ [m_colors addObject:MakeColor(226, 188, 255)];
484
+
485
+ [m_colors addObject:MakeColor(224, 224, 35)];
486
+ [m_colors addObject:MakeColor(223, 224, 105)];
487
+ [m_colors addObject:MakeColor(222, 224, 144)];
488
+ [m_colors addObject:MakeColor(222, 223, 184)];
489
+ [m_colors addObject:MakeColor(222, 223, 224)];
490
+ [m_colors addObject:MakeColor(220, 223, 253)];
491
+
492
+ [m_colors addObject:MakeColor(217, 253, 28)];
493
+ [m_colors addObject:MakeColor(217, 253, 99)];
494
+ [m_colors addObject:MakeColor(216, 252, 139)];
495
+ [m_colors addObject:MakeColor(216, 252, 179)];
496
+ [m_colors addObject:MakeColor(215, 252, 218)];
497
+ [m_colors addObject:MakeColor(215, 251, 250)];
498
+
499
+ [m_colors addObject:MakeColor(255, 61, 30)];
500
+ [m_colors addObject:MakeColor(255, 60, 118)];
501
+ [m_colors addObject:MakeColor(255, 58, 159)];
502
+ [m_colors addObject:MakeColor(255, 56, 199)];
503
+ [m_colors addObject:MakeColor(255, 55, 238)];
504
+ [m_colors addObject:MakeColor(255, 59, 255)];
505
+
506
+ [m_colors addObject:MakeColor(255, 117, 29)];
507
+ [m_colors addObject:MakeColor(255, 117, 115)];
508
+ [m_colors addObject:MakeColor(255, 117, 155)];
509
+ [m_colors addObject:MakeColor(255, 117, 195)];
510
+ [m_colors addObject:MakeColor(255, 116, 235)];
511
+ [m_colors addObject:MakeColor(254, 116, 255)];
512
+
513
+ [m_colors addObject:MakeColor(255, 152, 27)];
514
+ [m_colors addObject:MakeColor(255, 152, 111)];
515
+ [m_colors addObject:MakeColor(254, 152, 152)];
516
+ [m_colors addObject:MakeColor(255, 152, 192)];
517
+ [m_colors addObject:MakeColor(254, 151, 231)];
518
+ [m_colors addObject:MakeColor(253, 151, 253)];
519
+
520
+ [m_colors addObject:MakeColor(255, 187, 33)];
521
+ [m_colors addObject:MakeColor(253, 187, 107)];
522
+ [m_colors addObject:MakeColor(252, 187, 148)];
523
+ [m_colors addObject:MakeColor(253, 187, 187)];
524
+ [m_colors addObject:MakeColor(254, 187, 227)];
525
+ [m_colors addObject:MakeColor(252, 186, 252)];
526
+
527
+ [m_colors addObject:MakeColor(252, 222, 34)];
528
+ [m_colors addObject:MakeColor(251, 222, 103)];
529
+ [m_colors addObject:MakeColor(251, 222, 143)];
530
+ [m_colors addObject:MakeColor(250, 222, 182)];
531
+ [m_colors addObject:MakeColor(251, 221, 222)];
532
+ [m_colors addObject:MakeColor(252, 221, 252)];
533
+
534
+ [m_colors addObject:MakeColor(251, 252, 15)];
535
+ [m_colors addObject:MakeColor(251, 252, 97)];
536
+ [m_colors addObject:MakeColor(249, 252, 137)];
537
+ [m_colors addObject:MakeColor(247, 252, 177)];
538
+ [m_colors addObject:MakeColor(247, 253, 217)];
539
+ [m_colors addObject:MakeColor(254, 255, 255)];
540
+
541
+ // Grayscale
542
+
543
+ [m_colors addObject:MakeColor( 52, 53, 53)];
544
+ [m_colors addObject:MakeColor( 57, 58, 59)];
545
+ [m_colors addObject:MakeColor( 66, 67, 67)];
546
+ [m_colors addObject:MakeColor( 75, 76, 76)];
547
+ [m_colors addObject:MakeColor( 83, 85, 85)];
548
+ [m_colors addObject:MakeColor( 92, 93, 94)];
549
+
550
+ [m_colors addObject:MakeColor(101, 102, 102)];
551
+ [m_colors addObject:MakeColor(109, 111, 111)];
552
+ [m_colors addObject:MakeColor(118, 119, 119)];
553
+ [m_colors addObject:MakeColor(126, 127, 128)];
554
+ [m_colors addObject:MakeColor(134, 136, 136)];
555
+ [m_colors addObject:MakeColor(143, 144, 145)];
556
+
557
+ [m_colors addObject:MakeColor(151, 152, 153)];
558
+ [m_colors addObject:MakeColor(159, 161, 161)];
559
+ [m_colors addObject:MakeColor(167, 169, 169)];
560
+ [m_colors addObject:MakeColor(176, 177, 177)];
561
+ [m_colors addObject:MakeColor(184, 185, 186)];
562
+ [m_colors addObject:MakeColor(192, 193, 194)];
563
+
564
+ [m_colors addObject:MakeColor(200, 201, 202)];
565
+ [m_colors addObject:MakeColor(208, 209, 210)];
566
+ [m_colors addObject:MakeColor(216, 218, 218)];
567
+ [m_colors addObject:MakeColor(224, 226, 226)];
568
+ [m_colors addObject:MakeColor(232, 234, 234)];
569
+ [m_colors addObject:MakeColor(240, 242, 242)];
570
+
571
+ // Color codes
572
+
573
+ int index = 16;
574
+
575
+ while (index < 256)
576
+ {
577
+ [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
578
+ [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
579
+
580
+ index++;
581
+ }
582
+
583
+ #else
584
+
585
+ // Standard xterm colors:
586
+ //
587
+ // These are the colors xterm shells use in xterm-256color mode.
588
+ // In this mode, the shell supports 256 different colors, specified by 256 color codes.
589
+ //
590
+ // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
591
+ // These are generally configurable, and thus we ignore them for the purposes of mapping,
592
+ // as we can't rely on them being constant. They are largely duplicated anyway.
593
+ //
594
+ // The next 216 color codes are designed to run the spectrum, with several shades of every color.
595
+ // The last 24 color codes represent a grayscale.
596
+ //
597
+ // While the color codes are standardized, the actual RGB values for each color code is not.
598
+ // However most standard xterms follow a well known color chart,
599
+ // which can easily be calculated using the simple formula below.
600
+ //
601
+ // More information about ansi escape codes can be found online.
602
+ // http://en.wikipedia.org/wiki/ANSI_escape_code
603
+
604
+ int index = 16;
605
+
606
+ int r; // red
607
+ int g; // green
608
+ int b; // blue
609
+
610
+ int ri; // r increment
611
+ int gi; // g increment
612
+ int bi; // b increment
613
+
614
+ // Calculate xterm colors (using standard algorithm)
615
+
616
+ int r = 0;
617
+ int g = 0;
618
+ int b = 0;
619
+
620
+ for (ri = 0; ri < 6; ri++)
621
+ {
622
+ r = (ri == 0) ? 0 : 95 + (40 * (ri - 1));
623
+
624
+ for (gi = 0; gi < 6; gi++)
625
+ {
626
+ g = (gi == 0) ? 0 : 95 + (40 * (gi - 1));
627
+
628
+ for (bi = 0; bi < 6; bi++)
629
+ {
630
+ b = (bi == 0) ? 0 : 95 + (40 * (bi - 1));
631
+
632
+ [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
633
+ [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
634
+ [m_colors addObject:MakeColor(r, g, b)];
635
+
636
+ index++;
637
+ }
638
+ }
639
+ }
640
+
641
+ // Calculate xterm grayscale (using standard algorithm)
642
+
643
+ r = 8;
644
+ g = 8;
645
+ b = 8;
646
+
647
+ while (index < 256)
648
+ {
649
+ [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
650
+ [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
651
+ [m_colors addObject:MakeColor(r, g, b)];
652
+
653
+ r += 10;
654
+ g += 10;
655
+ b += 10;
656
+
657
+ index++;
658
+ }
659
+
660
+ #endif
661
+
662
+ codes_fg = [m_codes_fg copy];
663
+ codes_bg = [m_codes_bg copy];
664
+ colors = [m_colors copy];
665
+
666
+ NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
667
+ NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
668
+ }
669
+
670
+ + (void)getRed:(CGFloat *)rPtr green:(CGFloat *)gPtr blue:(CGFloat *)bPtr fromColor:(OSColor *)color
671
+ {
672
+ #if TARGET_OS_IPHONE
673
+
674
+ // iOS
675
+
676
+ if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)])
677
+ {
678
+ [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
679
+ }
680
+ else
681
+ {
682
+ // The method getRed:green:blue:alpha: was only available starting iOS 5.
683
+ // So in iOS 4 and earlier, we have to jump through hoops.
684
+
685
+ CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
686
+
687
+ unsigned char pixel[4];
688
+ CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, kCGImageAlphaNoneSkipLast);
689
+
690
+ CGContextSetFillColorWithColor(context, [color CGColor]);
691
+ CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
692
+
693
+ if (rPtr) { *rPtr = pixel[0] / 255.0f; }
694
+ if (gPtr) { *gPtr = pixel[1] / 255.0f; }
695
+ if (bPtr) { *bPtr = pixel[2] / 255.0f; }
696
+
697
+ CGContextRelease(context);
698
+ CGColorSpaceRelease(rgbColorSpace);
699
+ }
700
+
701
+ #else
702
+
703
+ // Mac OS X
704
+
705
+ [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
706
+
707
+ #endif
708
+ }
709
+
710
+ /**
711
+ * Maps the given color to the closest available color supported by the shell.
712
+ * The shell may support 256 colors, or only 16.
713
+ *
714
+ * This method loops through the known supported color set, and calculates the closest color.
715
+ * The array index of that color, within the colors array, is then returned.
716
+ * This array index may also be used as the index within the codes_fg and codes_bg arrays.
717
+ **/
718
+ + (NSUInteger)codeIndexForColor:(OSColor *)inColor
719
+ {
720
+ CGFloat inR, inG, inB;
721
+ [self getRed:&inR green:&inG blue:&inB fromColor:inColor];
722
+
723
+ NSUInteger bestIndex = 0;
724
+ CGFloat lowestDistance = 100.0f;
725
+
726
+ NSUInteger i = 0;
727
+ for (OSColor *color in colors)
728
+ {
729
+ // Calculate Euclidean distance (lower value means closer to given color)
730
+
731
+ CGFloat r, g, b;
732
+ [self getRed:&r green:&g blue:&b fromColor:color];
733
+
734
+ #if CGFLOAT_IS_DOUBLE
735
+ CGFloat distance = sqrt(pow(r-inR, 2.0) + pow(g-inG, 2.0) + pow(b-inB, 2.0));
736
+ #else
737
+ CGFloat distance = sqrtf(powf(r-inR, 2.0f) + powf(g-inG, 2.0f) + powf(b-inB, 2.0f));
738
+ #endif
739
+
740
+ NSLogVerbose(@"DDTTYLogger: %3lu : %.3f,%.3f,%.3f & %.3f,%.3f,%.3f = %.6f",
741
+ (unsigned long)i, inR, inG, inB, r, g, b, distance);
742
+
743
+ if (distance < lowestDistance)
744
+ {
745
+ bestIndex = i;
746
+ lowestDistance = distance;
747
+
748
+ NSLogVerbose(@"DDTTYLogger: New best index = %lu", (unsigned long)bestIndex);
749
+ }
750
+
751
+ i++;
752
+ }
753
+
754
+ return bestIndex;
755
+ }
756
+
757
+ /**
758
+ * The runtime sends initialize to each class in a program exactly one time just before the class,
759
+ * or any class that inherits from it, is sent its first message from within the program. (Thus the
760
+ * method may never be invoked if the class is not used.) The runtime sends the initialize message to
761
+ * classes in a thread-safe manner. Superclasses receive this message before their subclasses.
762
+ *
763
+ * This method may also be called directly (assumably by accident), hence the safety mechanism.
764
+ **/
765
+ + (void)initialize
766
+ {
767
+ static BOOL initialized = NO;
768
+ if (!initialized)
769
+ {
770
+ initialized = YES;
771
+
772
+ char *term = getenv("TERM");
773
+ if (term)
774
+ {
775
+ if (strcasestr(term, "color") != NULL)
776
+ {
777
+ isaColorTTY = YES;
778
+ isaColor256TTY = (strcasestr(term, "256") != NULL);
779
+
780
+ if (isaColor256TTY)
781
+ [self initialize_colors_256];
782
+ else
783
+ [self initialize_colors_16];
784
+ }
785
+ }
786
+ else
787
+ {
788
+ // Xcode does NOT natively support colors in the Xcode debugging console.
789
+ // You'll need to install the XcodeColors plugin to see colors in the Xcode console.
790
+ //
791
+ // PS - Please read the header file before diving into the source code.
792
+
793
+ char *xcode_colors = getenv("XcodeColors");
794
+ if (xcode_colors && (strcmp(xcode_colors, "YES") == 0))
795
+ {
796
+ isaXcodeColorTTY = YES;
797
+ }
798
+ }
799
+
800
+ NSLogInfo(@"DDTTYLogger: isaColorTTY = %@", (isaColorTTY ? @"YES" : @"NO"));
801
+ NSLogInfo(@"DDTTYLogger: isaColor256TTY: %@", (isaColor256TTY ? @"YES" : @"NO"));
802
+ NSLogInfo(@"DDTTYLogger: isaXcodeColorTTY: %@", (isaXcodeColorTTY ? @"YES" : @"NO"));
803
+
804
+ sharedInstance = [[DDTTYLogger alloc] init];
805
+ }
806
+ }
807
+
808
+ + (DDTTYLogger *)sharedInstance
809
+ {
810
+ return sharedInstance;
811
+ }
812
+
813
+ - (id)init
814
+ {
815
+ if (sharedInstance != nil)
816
+ {
817
+ return nil;
818
+ }
819
+
820
+ if ((self = [super init]))
821
+ {
822
+ calendar = [NSCalendar autoupdatingCurrentCalendar];
823
+
824
+ calendarUnitFlags = 0;
825
+ calendarUnitFlags |= NSYearCalendarUnit;
826
+ calendarUnitFlags |= NSMonthCalendarUnit;
827
+ calendarUnitFlags |= NSDayCalendarUnit;
828
+ calendarUnitFlags |= NSHourCalendarUnit;
829
+ calendarUnitFlags |= NSMinuteCalendarUnit;
830
+ calendarUnitFlags |= NSSecondCalendarUnit;
831
+
832
+ // Initialze 'app' variable (char *)
833
+
834
+ appName = [[NSProcessInfo processInfo] processName];
835
+
836
+ appLen = [appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
837
+ app = (char *)malloc(appLen + 1);
838
+
839
+ [appName getCString:app maxLength:(appLen+1) encoding:NSUTF8StringEncoding];
840
+
841
+ // Initialize 'pid' variable (char *)
842
+
843
+ processID = [NSString stringWithFormat:@"%i", (int)getpid()];
844
+
845
+ pidLen = [processID lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
846
+ pid = (char *)malloc(pidLen + 1);
847
+
848
+ [processID getCString:pid maxLength:(pidLen+1) encoding:NSUTF8StringEncoding];
849
+
850
+ // Initialize color stuff
851
+
852
+ colorsEnabled = NO;
853
+ colorProfilesArray = [[NSMutableArray alloc] initWithCapacity:8];
854
+ colorProfilesDict = [[NSMutableDictionary alloc] initWithCapacity:8];
855
+ }
856
+ return self;
857
+ }
858
+
859
+ - (void)loadDefaultColorProfiles
860
+ {
861
+ [self setForegroundColor:MakeColor(214, 57, 30) backgroundColor:nil forFlag:LOG_FLAG_ERROR];
862
+ [self setForegroundColor:MakeColor(204, 121, 32) backgroundColor:nil forFlag:LOG_FLAG_WARN];
863
+ }
864
+
865
+ - (BOOL)colorsEnabled
866
+ {
867
+ // The design of this method is taken from the DDAbstractLogger implementation.
868
+ // For extensive documentation please refer to the DDAbstractLogger implementation.
869
+
870
+ // Note: The internal implementation MUST access the colorsEnabled variable directly,
871
+ // This method is designed explicitly for external access.
872
+ //
873
+ // Using "self." syntax to go through this method will cause immediate deadlock.
874
+ // This is the intended result. Fix it by accessing the ivar directly.
875
+ // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
876
+
877
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
878
+ NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
879
+
880
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
881
+
882
+ __block BOOL result;
883
+
884
+ dispatch_sync(globalLoggingQueue, ^{
885
+ dispatch_sync(loggerQueue, ^{
886
+ result = colorsEnabled;
887
+ });
888
+ });
889
+
890
+ return result;
891
+ }
892
+
893
+ - (void)setColorsEnabled:(BOOL)newColorsEnabled
894
+ {
895
+ dispatch_block_t block = ^{ @autoreleasepool {
896
+
897
+ colorsEnabled = newColorsEnabled;
898
+
899
+ if ([colorProfilesArray count] == 0) {
900
+ [self loadDefaultColorProfiles];
901
+ }
902
+ }};
903
+
904
+ // The design of this method is taken from the DDAbstractLogger implementation.
905
+ // For extensive documentation please refer to the DDAbstractLogger implementation.
906
+
907
+ // Note: The internal implementation MUST access the colorsEnabled variable directly,
908
+ // This method is designed explicitly for external access.
909
+ //
910
+ // Using "self." syntax to go through this method will cause immediate deadlock.
911
+ // This is the intended result. Fix it by accessing the ivar directly.
912
+ // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
913
+
914
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
915
+ NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
916
+
917
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
918
+
919
+ dispatch_async(globalLoggingQueue, ^{
920
+ dispatch_async(loggerQueue, block);
921
+ });
922
+ }
923
+
924
+ - (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask
925
+ {
926
+ [self setForegroundColor:txtColor backgroundColor:bgColor forFlag:mask context:0];
927
+ }
928
+
929
+ - (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask context:(int)ctxt
930
+ {
931
+ dispatch_block_t block = ^{ @autoreleasepool {
932
+
933
+ DDTTYLoggerColorProfile *newColorProfile =
934
+ [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
935
+ backgroundColor:bgColor
936
+ flag:mask
937
+ context:ctxt];
938
+
939
+ NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
940
+
941
+ NSUInteger i = 0;
942
+ for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray)
943
+ {
944
+ if ((colorProfile->mask == mask) && (colorProfile->context == ctxt))
945
+ {
946
+ break;
947
+ }
948
+
949
+ i++;
950
+ }
951
+
952
+ if (i < [colorProfilesArray count])
953
+ [colorProfilesArray replaceObjectAtIndex:i withObject:newColorProfile];
954
+ else
955
+ [colorProfilesArray addObject:newColorProfile];
956
+ }};
957
+
958
+ // The design of the setter logic below is taken from the DDAbstractLogger implementation.
959
+ // For documentation please refer to the DDAbstractLogger implementation.
960
+
961
+ if ([self isOnInternalLoggerQueue])
962
+ {
963
+ block();
964
+ }
965
+ else
966
+ {
967
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
968
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
969
+
970
+ dispatch_async(globalLoggingQueue, ^{
971
+ dispatch_async(loggerQueue, block);
972
+ });
973
+ }
974
+ }
975
+
976
+ - (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forTag:(id <NSCopying>)tag
977
+ {
978
+ NSAssert([(id <NSObject>)tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag");
979
+
980
+ dispatch_block_t block = ^{ @autoreleasepool {
981
+
982
+ DDTTYLoggerColorProfile *newColorProfile =
983
+ [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
984
+ backgroundColor:bgColor
985
+ flag:0
986
+ context:0];
987
+
988
+ NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
989
+
990
+ [colorProfilesDict setObject:newColorProfile forKey:tag];
991
+ }};
992
+
993
+ // The design of the setter logic below is taken from the DDAbstractLogger implementation.
994
+ // For documentation please refer to the DDAbstractLogger implementation.
995
+
996
+ if ([self isOnInternalLoggerQueue])
997
+ {
998
+ block();
999
+ }
1000
+ else
1001
+ {
1002
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
1003
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
1004
+
1005
+ dispatch_async(globalLoggingQueue, ^{
1006
+ dispatch_async(loggerQueue, block);
1007
+ });
1008
+ }
1009
+ }
1010
+
1011
+ - (void)clearColorsForFlag:(int)mask
1012
+ {
1013
+ [self clearColorsForFlag:mask context:0];
1014
+ }
1015
+
1016
+ - (void)clearColorsForFlag:(int)mask context:(int)context
1017
+ {
1018
+ dispatch_block_t block = ^{ @autoreleasepool {
1019
+
1020
+ NSUInteger i = 0;
1021
+ for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray)
1022
+ {
1023
+ if ((colorProfile->mask == mask) && (colorProfile->context == context))
1024
+ {
1025
+ break;
1026
+ }
1027
+
1028
+ i++;
1029
+ }
1030
+
1031
+ if (i < [colorProfilesArray count])
1032
+ {
1033
+ [colorProfilesArray removeObjectAtIndex:i];
1034
+ }
1035
+ }};
1036
+
1037
+ // The design of the setter logic below is taken from the DDAbstractLogger implementation.
1038
+ // For documentation please refer to the DDAbstractLogger implementation.
1039
+
1040
+ if ([self isOnInternalLoggerQueue])
1041
+ {
1042
+ block();
1043
+ }
1044
+ else
1045
+ {
1046
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
1047
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
1048
+
1049
+ dispatch_async(globalLoggingQueue, ^{
1050
+ dispatch_async(loggerQueue, block);
1051
+ });
1052
+ }
1053
+ }
1054
+
1055
+ - (void)clearColorsForTag:(id <NSCopying>)tag
1056
+ {
1057
+ NSAssert([(id <NSObject>)tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag");
1058
+
1059
+ dispatch_block_t block = ^{ @autoreleasepool {
1060
+
1061
+ [colorProfilesDict removeObjectForKey:tag];
1062
+ }};
1063
+
1064
+ // The design of the setter logic below is taken from the DDAbstractLogger implementation.
1065
+ // For documentation please refer to the DDAbstractLogger implementation.
1066
+
1067
+ if ([self isOnInternalLoggerQueue])
1068
+ {
1069
+ block();
1070
+ }
1071
+ else
1072
+ {
1073
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
1074
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
1075
+
1076
+ dispatch_async(globalLoggingQueue, ^{
1077
+ dispatch_async(loggerQueue, block);
1078
+ });
1079
+ }
1080
+ }
1081
+
1082
+ - (void)clearColorsForAllFlags
1083
+ {
1084
+ dispatch_block_t block = ^{ @autoreleasepool {
1085
+
1086
+ [colorProfilesArray removeAllObjects];
1087
+ }};
1088
+
1089
+ // The design of the setter logic below is taken from the DDAbstractLogger implementation.
1090
+ // For documentation please refer to the DDAbstractLogger implementation.
1091
+
1092
+ if ([self isOnInternalLoggerQueue])
1093
+ {
1094
+ block();
1095
+ }
1096
+ else
1097
+ {
1098
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
1099
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
1100
+
1101
+ dispatch_async(globalLoggingQueue, ^{
1102
+ dispatch_async(loggerQueue, block);
1103
+ });
1104
+ }
1105
+ }
1106
+
1107
+ - (void)clearColorsForAllTags
1108
+ {
1109
+ dispatch_block_t block = ^{ @autoreleasepool {
1110
+
1111
+ [colorProfilesDict removeAllObjects];
1112
+ }};
1113
+
1114
+ // The design of the setter logic below is taken from the DDAbstractLogger implementation.
1115
+ // For documentation please refer to the DDAbstractLogger implementation.
1116
+
1117
+ if ([self isOnInternalLoggerQueue])
1118
+ {
1119
+ block();
1120
+ }
1121
+ else
1122
+ {
1123
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
1124
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
1125
+
1126
+ dispatch_async(globalLoggingQueue, ^{
1127
+ dispatch_async(loggerQueue, block);
1128
+ });
1129
+ }
1130
+ }
1131
+
1132
+ - (void)clearAllColors
1133
+ {
1134
+ dispatch_block_t block = ^{ @autoreleasepool {
1135
+
1136
+ [colorProfilesArray removeAllObjects];
1137
+ [colorProfilesDict removeAllObjects];
1138
+ }};
1139
+
1140
+ // The design of the setter logic below is taken from the DDAbstractLogger implementation.
1141
+ // For documentation please refer to the DDAbstractLogger implementation.
1142
+
1143
+ if ([self isOnInternalLoggerQueue])
1144
+ {
1145
+ block();
1146
+ }
1147
+ else
1148
+ {
1149
+ dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
1150
+ NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
1151
+
1152
+ dispatch_async(globalLoggingQueue, ^{
1153
+ dispatch_async(loggerQueue, block);
1154
+ });
1155
+ }
1156
+ }
1157
+
1158
+ - (void)logMessage:(DDLogMessage *)logMessage
1159
+ {
1160
+ NSString *logMsg = logMessage->logMsg;
1161
+ BOOL isFormatted = NO;
1162
+
1163
+ if (formatter)
1164
+ {
1165
+ logMsg = [formatter formatLogMessage:logMessage];
1166
+ isFormatted = logMsg != logMessage->logMsg;
1167
+ }
1168
+
1169
+ if (logMsg)
1170
+ {
1171
+ // Search for a color profile associated with the log message
1172
+
1173
+ DDTTYLoggerColorProfile *colorProfile = nil;
1174
+
1175
+ if (colorsEnabled)
1176
+ {
1177
+ if (logMessage->tag)
1178
+ {
1179
+ colorProfile = [colorProfilesDict objectForKey:logMessage->tag];
1180
+ }
1181
+ if (colorProfile == nil)
1182
+ {
1183
+ for (DDTTYLoggerColorProfile *cp in colorProfilesArray)
1184
+ {
1185
+ if ((logMessage->logFlag & cp->mask) && (logMessage->logContext == cp->context))
1186
+ {
1187
+ colorProfile = cp;
1188
+ break;
1189
+ }
1190
+ }
1191
+ }
1192
+ }
1193
+
1194
+ // Convert log message to C string.
1195
+ //
1196
+ // We use the stack instead of the heap for speed if possible.
1197
+ // But we're extra cautious to avoid a stack overflow.
1198
+
1199
+ NSUInteger msgLen = [logMsg lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1200
+ const BOOL useStack = msgLen < (1024 * 4);
1201
+
1202
+ char msgStack[useStack ? (msgLen + 1) : 1]; // Analyzer doesn't like zero-size array, hence the 1
1203
+ char *msg = useStack ? msgStack : (char *)malloc(msgLen + 1);
1204
+
1205
+ [logMsg getCString:msg maxLength:(msgLen + 1) encoding:NSUTF8StringEncoding];
1206
+
1207
+ // Write the log message to STDERR
1208
+
1209
+ if (isFormatted)
1210
+ {
1211
+ // The log message has already been formatted.
1212
+
1213
+ struct iovec v[5];
1214
+
1215
+ if (colorProfile)
1216
+ {
1217
+ v[0].iov_base = colorProfile->fgCode;
1218
+ v[0].iov_len = colorProfile->fgCodeLen;
1219
+
1220
+ v[1].iov_base = colorProfile->bgCode;
1221
+ v[1].iov_len = colorProfile->bgCodeLen;
1222
+
1223
+ v[4].iov_base = colorProfile->resetCode;
1224
+ v[4].iov_len = colorProfile->resetCodeLen;
1225
+ }
1226
+ else
1227
+ {
1228
+ v[0].iov_base = "";
1229
+ v[0].iov_len = 0;
1230
+
1231
+ v[1].iov_base = "";
1232
+ v[1].iov_len = 0;
1233
+
1234
+ v[4].iov_base = "";
1235
+ v[4].iov_len = 0;
1236
+ }
1237
+
1238
+ v[2].iov_base = (char *)msg;
1239
+ v[2].iov_len = msgLen;
1240
+
1241
+ v[3].iov_base = "\n";
1242
+ v[3].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
1243
+
1244
+ writev(STDERR_FILENO, v, 5);
1245
+ }
1246
+ else
1247
+ {
1248
+ // The log message is unformatted, so apply standard NSLog style formatting.
1249
+
1250
+ int len;
1251
+
1252
+ // Calculate timestamp.
1253
+ // The technique below is faster than using NSDateFormatter.
1254
+
1255
+ NSDateComponents *components = [calendar components:calendarUnitFlags fromDate:logMessage->timestamp];
1256
+
1257
+ NSTimeInterval epoch = [logMessage->timestamp timeIntervalSinceReferenceDate];
1258
+ int milliseconds = (int)((epoch - floor(epoch)) * 1000);
1259
+
1260
+ char ts[24];
1261
+ len = snprintf(ts, 24, "%04ld-%02ld-%02ld %02ld:%02ld:%02ld:%03d", // yyyy-MM-dd HH:mm:ss:SSS
1262
+ (long)components.year,
1263
+ (long)components.month,
1264
+ (long)components.day,
1265
+ (long)components.hour,
1266
+ (long)components.minute,
1267
+ (long)components.second, milliseconds);
1268
+
1269
+ size_t tsLen = MIN(24-1, len);
1270
+
1271
+ // Calculate thread ID
1272
+ //
1273
+ // How many characters do we need for the thread id?
1274
+ // logMessage->machThreadID is of type mach_port_t, which is an unsigned int.
1275
+ //
1276
+ // 1 hex char = 4 bits
1277
+ // 8 hex chars for 32 bit, plus ending '\0' = 9
1278
+
1279
+ char tid[9];
1280
+ len = snprintf(tid, 9, "%x", logMessage->machThreadID);
1281
+
1282
+ size_t tidLen = MIN(9-1, len);
1283
+
1284
+ // Here is our format: "%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg
1285
+
1286
+ struct iovec v[13];
1287
+
1288
+ if (colorProfile)
1289
+ {
1290
+ v[0].iov_base = colorProfile->fgCode;
1291
+ v[0].iov_len = colorProfile->fgCodeLen;
1292
+
1293
+ v[1].iov_base = colorProfile->bgCode;
1294
+ v[1].iov_len = colorProfile->bgCodeLen;
1295
+
1296
+ v[12].iov_base = colorProfile->resetCode;
1297
+ v[12].iov_len = colorProfile->resetCodeLen;
1298
+ }
1299
+ else
1300
+ {
1301
+ v[0].iov_base = "";
1302
+ v[0].iov_len = 0;
1303
+
1304
+ v[1].iov_base = "";
1305
+ v[1].iov_len = 0;
1306
+
1307
+ v[12].iov_base = "";
1308
+ v[12].iov_len = 0;
1309
+ }
1310
+
1311
+ v[2].iov_base = ts;
1312
+ v[2].iov_len = tsLen;
1313
+
1314
+ v[3].iov_base = " ";
1315
+ v[3].iov_len = 1;
1316
+
1317
+ v[4].iov_base = app;
1318
+ v[4].iov_len = appLen;
1319
+
1320
+ v[5].iov_base = "[";
1321
+ v[5].iov_len = 1;
1322
+
1323
+ v[6].iov_base = pid;
1324
+ v[6].iov_len = pidLen;
1325
+
1326
+ v[7].iov_base = ":";
1327
+ v[7].iov_len = 1;
1328
+
1329
+ v[8].iov_base = tid;
1330
+ v[8].iov_len = MIN((size_t)8, tidLen); // snprintf doesn't return what you might think
1331
+
1332
+ v[9].iov_base = "] ";
1333
+ v[9].iov_len = 2;
1334
+
1335
+ v[10].iov_base = (char *)msg;
1336
+ v[10].iov_len = msgLen;
1337
+
1338
+ v[11].iov_base = "\n";
1339
+ v[11].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
1340
+
1341
+ writev(STDERR_FILENO, v, 13);
1342
+ }
1343
+
1344
+ if (!useStack) {
1345
+ free(msg);
1346
+ }
1347
+ }
1348
+ }
1349
+
1350
+ - (NSString *)loggerName
1351
+ {
1352
+ return @"cocoa.lumberjack.ttyLogger";
1353
+ }
1354
+
1355
+ @end
1356
+
1357
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1358
+
1359
+ @implementation DDTTYLoggerColorProfile
1360
+
1361
+ - (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)aMask context:(int)ctxt
1362
+ {
1363
+ if ((self = [super init]))
1364
+ {
1365
+ mask = aMask;
1366
+ context = ctxt;
1367
+
1368
+ CGFloat r, g, b;
1369
+
1370
+ if (fgColor)
1371
+ {
1372
+ [DDTTYLogger getRed:&r green:&g blue:&b fromColor:fgColor];
1373
+
1374
+ fg_r = (uint8_t)(r * 255.0f);
1375
+ fg_g = (uint8_t)(g * 255.0f);
1376
+ fg_b = (uint8_t)(b * 255.0f);
1377
+ }
1378
+ if (bgColor)
1379
+ {
1380
+ [DDTTYLogger getRed:&r green:&g blue:&b fromColor:bgColor];
1381
+
1382
+ bg_r = (uint8_t)(r * 255.0f);
1383
+ bg_g = (uint8_t)(g * 255.0f);
1384
+ bg_b = (uint8_t)(b * 255.0f);
1385
+ }
1386
+
1387
+ if (fgColor && isaColorTTY)
1388
+ {
1389
+ // Map foreground color to closest available shell color
1390
+
1391
+ fgCodeIndex = [DDTTYLogger codeIndexForColor:fgColor];
1392
+ fgCodeRaw = [codes_fg objectAtIndex:fgCodeIndex];
1393
+
1394
+ NSString *escapeSeq = @"\033[";
1395
+
1396
+ NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1397
+ NSUInteger len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1398
+
1399
+ [escapeSeq getCString:(fgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding];
1400
+ [fgCodeRaw getCString:(fgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding];
1401
+
1402
+ fgCodeLen = len1+len2;
1403
+ }
1404
+ else if (fgColor && isaXcodeColorTTY)
1405
+ {
1406
+ // Convert foreground color to color code sequence
1407
+
1408
+ const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
1409
+
1410
+ int result = snprintf(fgCode, 24, "%sfg%u,%u,%u;", escapeSeq, fg_r, fg_g, fg_b);
1411
+ fgCodeLen = MIN(result, (24-1));
1412
+ }
1413
+ else
1414
+ {
1415
+ // No foreground color or no color support
1416
+
1417
+ fgCode[0] = '\0';
1418
+ fgCodeLen = 0;
1419
+ }
1420
+
1421
+ if (bgColor && isaColorTTY)
1422
+ {
1423
+ // Map background color to closest available shell color
1424
+
1425
+ bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor];
1426
+ bgCodeRaw = [codes_bg objectAtIndex:bgCodeIndex];
1427
+
1428
+ NSString *escapeSeq = @"\033[";
1429
+
1430
+ NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1431
+ NSUInteger len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1432
+
1433
+ [escapeSeq getCString:(bgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding];
1434
+ [bgCodeRaw getCString:(bgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding];
1435
+
1436
+ bgCodeLen = len1+len2;
1437
+ }
1438
+ else if (bgColor && isaXcodeColorTTY)
1439
+ {
1440
+ // Convert background color to color code sequence
1441
+
1442
+ const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
1443
+
1444
+ int result = snprintf(bgCode, 24, "%sbg%u,%u,%u;", escapeSeq, bg_r, bg_g, bg_b);
1445
+ bgCodeLen = MIN(result, (24-1));
1446
+ }
1447
+ else
1448
+ {
1449
+ // No background color or no color support
1450
+
1451
+ bgCode[0] = '\0';
1452
+ bgCodeLen = 0;
1453
+ }
1454
+
1455
+ if (isaColorTTY)
1456
+ {
1457
+ resetCodeLen = snprintf(resetCode, 8, "\033[0m");
1458
+ }
1459
+ else if (isaXcodeColorTTY)
1460
+ {
1461
+ resetCodeLen = snprintf(resetCode, 8, XCODE_COLORS_RESET);
1462
+ }
1463
+ else
1464
+ {
1465
+ resetCode[0] = '\0';
1466
+ resetCodeLen = 0;
1467
+ }
1468
+ }
1469
+ return self;
1470
+ }
1471
+
1472
+ - (NSString *)description
1473
+ {
1474
+ return [NSString stringWithFormat:
1475
+ @"<DDTTYLoggerColorProfile: %p mask:%i ctxt:%i fg:%u,%u,%u bg:%u,%u,%u fgCode:%@ bgCode:%@>",
1476
+ self, mask, context, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b, fgCodeRaw, bgCodeRaw];
1477
+ }
1478
+
1479
+ @end