1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/**
* @file
* @date 17.5.2007
*
* Implementation of class HBOutputRedirect.
*/
#import "HBOutputRedirect.h"
/// Global pointer to HBOutputRedirect object that manages redirects for stdout.
static HBOutputRedirect *g_stdoutRedirect = nil;
/// Global pointer to HBOutputRedirect object that manages redirects for stderr.
static HBOutputRedirect *g_stderrRedirect = nil;
static int stdoutwrite(void *inFD, const char *buffer, int size);
static int stderrwrite(void *inFD, const char *buffer, int size);
@interface HBOutputRedirect ()
/// Output stream (@c stdout or @c stderr) redirected by this object.
@property (nonatomic, readonly) FILE *stream;
/// Pointer to old write function for the stream.
@property (nonatomic, readonly) int (*oldWriteFunc)(void *, const char *, int);
@end
/**
* Function that replaces stdout->_write and forwards stdout to g_stdoutRedirect.
*/
int stdoutwrite(void *inFD, const char *buffer, int size)
{
@autoreleasepool
{
NSString *string = [[NSString alloc] initWithBytes:buffer length:size encoding:NSUTF8StringEncoding];
if (string)
{
[g_stdoutRedirect forwardOutput:string];
}
}
return size;
}
int stderrwrite(void *inFD, const char *buffer, int size)
{
@autoreleasepool
{
NSString *string = [[NSString alloc] initWithBytes:buffer length:size encoding:NSUTF8StringEncoding];
if (string)
{
[g_stderrRedirect forwardOutput:string];
}
}
return size;
}
@implementation HBOutputRedirect
/**
* Returns HBOutputRedirect object used to redirect stdout.
*/
+ (instancetype)stdoutRedirect
{
if (!g_stdoutRedirect)
{
g_stdoutRedirect = [[HBOutputRedirect alloc] initWithStream:stdout type:HBRedirectTypeOutput];
}
return g_stdoutRedirect;
}
/**
* Returns HBOutputRedirect object used to redirect stderr.
*/
+ (instancetype)stderrRedirect
{
if (!g_stderrRedirect)
{
g_stderrRedirect = [[HBOutputRedirect alloc] initWithStream:stderr type:HBRedirectTypeError];
}
return g_stderrRedirect;
}
/**
* Private constructor which should not be called from outside. This is used to
* initialize the class at @c stdoutRedirect and @c stderrRedirect.
*
* @param stream Stream that will be redirected (stdout or stderr).
* @param type Type that will be called in listeners to redirect the stream.
*
* @return New HBOutputRedirect object.
*/
- (instancetype)initWithStream:(FILE *)stream type:(HBRedirectType)type
{
if (self = [self initWithType:type])
{
_stream = stream;
_oldWriteFunc = NULL;
}
return self;
}
/**
* Starts redirecting the stream by redirecting its output to function
* @c stdoutwrite() or @c stderrwrite(). Old _write function is stored to
* @c oldWriteFunc so it can be restored.
*/
- (void)startRedirect
{
if (!_oldWriteFunc)
{
_oldWriteFunc = _stream->_write;
_stream->_write = _stream == stdout ? stdoutwrite : stderrwrite;
}
}
/**
* Stops redirecting of the stream by returning the stream's _write function
* to original.
*/
- (void)stopRedirect
{
if (_oldWriteFunc)
{
_stream->_write = _oldWriteFunc;
_oldWriteFunc = NULL;
}
}
@end
|