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