forked from pmougin/F-Script
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathFSTask.m
207 lines (195 loc) · 7.66 KB
/
FSTask.m
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// FSTask.m Copyright (c) 2002 Joerg Garbers.
// This software is open source. See the license.
#import "FSTask.h"
@implementation FSRecursiveReplacer
- (id)initWithFrom:(NSString *)f to:(NSString *)t next:(FSRecursiveReplacer *)n;
{
[super init];
from=[f copy];
to=[t copy];
next=[n retain];
return self;
}
- (void)dealloc;
{
[from release];
[to release];
[next release];
[super dealloc];
}
+ (FSRecursiveReplacer *)replacerWithFrom:(NSString *)f to:(NSString *)t next:(FSRecursiveReplacer *)n;
{
return [[[[self class] alloc] initWithFrom:f to:t next:n] autorelease];
}
+ (FSRecursiveReplacer *)replacerWithFrom:(NSString *)f to:(NSString *)t;
{
return [[[[self class] alloc] initWithFrom:f to:t next:nil] autorelease];
}
+ (FSRecursiveReplacer *)returnReplacerFromRToN; // "\r" -> "\n"
{
static FSRecursiveReplacer *myReplacer=nil;
if (!myReplacer) {
myReplacer=[[FSRecursiveReplacer alloc] initWithFrom:@"\r" to:@"\n" next:nil];
}
return myReplacer;
}
+ (FSRecursiveReplacer *)returnReplacerFromNToR; // "\n" -> "\r"
{
static FSRecursiveReplacer *myReplacer=nil;
if (!myReplacer) {
myReplacer=[[FSRecursiveReplacer alloc] initWithFrom:@"\n" to:@"\r" next:nil];
}
return myReplacer;
}
- (NSString *)transform:(NSString *)str;
{
NSString *result;
NSArray *fromA=[str componentsSeparatedByString:from];
if (next) {
NSMutableArray *toA;
NSEnumerator *e=[fromA objectEnumerator];
NSString *fromComponent;
toA=[[NSMutableArray alloc] initWithCapacity:[fromA count]];
while (fromComponent=[e nextObject])
[toA addObject:[next transform:fromComponent]];
result=[toA componentsJoinedByString:to];
[toA release];
} else {
result=[fromA componentsJoinedByString:to];
}
return result;
}
@end
@implementation FSTask
static NSStringEncoding defaultInputEncoding=NSISOLatin1StringEncoding;
static NSStringEncoding defaultOutputEncoding=NSISOLatin1StringEncoding;
static BOOL reportErrorOnNotZero=NO;
static NSTimeInterval maxInterval=10.0;
+ (void)setInputEncoding:(NSStringEncoding)enc;
{
defaultInputEncoding=enc;
}
+ (void)setOutputEncoding:(NSStringEncoding)enc;
{
defaultOutputEncoding=enc;
}
+ (void)setReportErrorOnNotZero:(BOOL)yn;
{
reportErrorOnNotZero=yn;
}
+ (void)setMaxInterval:(NSTimeInterval)interv;
{
maxInterval=interv;
}
+ (NSString *)outputOfProgram:(NSString *)program;
{
return [self outputOfProgram:program withArguments:nil withInput:nil];
}
+ (NSString *)outputOfProgram:(NSString *)program withArguments:(NSArray *)args;
{
return [self outputOfProgram:program withArguments:args withInput:nil];
}
+ (NSString *)outputOfProgram:(NSString *)program withInput:(NSString *)inputString;
{
return [self outputOfProgram:program withArguments:nil withInput:inputString];
}
+ (NSString *)outputOfProgram:(NSString *)program withArguments:(NSArray *)args withInput:(NSString *)inputString;
{
return [self outputOfProgram:program withArguments:args withInput:inputString inputEncoding:defaultInputEncoding outputEncoding:defaultOutputEncoding];
}
+ (NSString *)outputOfProgram:(NSString *)program withArguments:(NSArray *)args withInput:(NSString *)inputString inputEncoding:(NSStringEncoding)inputEncoding outputEncoding:(NSStringEncoding)outputEncoding;
/*" calls setArraysFromOutput as a side effect "*/
{
// to do?: on errors throw exception instead of error string?
static BOOL doIt=YES; // set NO for debugging
if (!inputString)
inputString=@"";
if (!args)
args = [NSArray array];
if (!program)
return @"error: programName must be set";
if (doIt) {
NSTask *aTask = [[NSTask alloc] init];
NSPipe *outPipe = [NSPipe pipe];
NSPipe *inPipe = [NSPipe pipe];
NSPipe *errPipe = [NSPipe pipe];
NSFileHandle *writeHandle = [outPipe fileHandleForWriting];
NSFileHandle *readHandle = [inPipe fileHandleForReading];
// NSFileHandle *errHandle = [errPipe fileHandleForReading];
NSString *outStr=inputString;
NSString *inStr=nil;
NSMutableString *inCollectStr=[NSMutableString string];
NSData *outData = [outStr dataUsingEncoding:inputEncoding];
NSData *inData=nil;
NSString *launchPath;
NSInteger returnValue;
NSTimeInterval startingDate;
static BOOL readBeforeCheckTerminate=YES; // if programs crash, it might be better to set this to NO.
// but there was a problem with programs, that wait with further output until
// the end of the pipe has read the allready produced output. YES seems to solve it.
static BOOL collectStepwise=NO; // YES is interesting, for seeing the updates. But the UI must have a chance to update.
launchPath=[program stringByExpandingTildeInPath];
// there is an error in debug mode, if there is an exception.
NS_DURING
[aTask setLaunchPath:launchPath];
[aTask setArguments:args];
[aTask setStandardOutput:inPipe]; // write handle is closed to this process
[aTask setStandardInput:outPipe]; // write handle is closed to this process
[aTask setStandardError:errPipe]; // write handle is closed to this process
[aTask launch];
startingDate=[NSDate timeIntervalSinceReferenceDate];
[writeHandle writeData:outData];
[writeHandle closeFile];
if (readBeforeCheckTerminate) {
if (collectStepwise) {
inData=[readHandle availableData]; // waits for output resp. data of lenght 0 if EOF
while ([inData length]) {
NSString *s=[[NSString alloc] initWithData:inData encoding:outputEncoding];
[inCollectStr appendString:s];
[s release];
inData=[readHandle availableData];
}
} else { // in one step (wait until done)
inData=[readHandle readDataToEndOfFile]; // error in debug mode, if task has terminated due to bus error
}
}
while ([aTask isRunning] &&
([NSDate timeIntervalSinceReferenceDate]-startingDate<maxInterval)) {
// [aTask waitUntilExit];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
if ([aTask isRunning]) {
inStr=[[NSString alloc] initWithFormat:@"FSTask Error for %@: Time limit %f exceeded",launchPath,maxInterval];
} else {
returnValue = [aTask terminationStatus];
if (returnValue) [aTask terminate]; // hmm?
if (reportErrorOnNotZero && returnValue) {
inStr=[[NSString alloc] initWithFormat:@"Error %ld for %@.",(long)returnValue,launchPath];
} else {
if (collectStepwise)
inStr=[inCollectStr copy];
else {
if (!readBeforeCheckTerminate)
inData=[readHandle readDataToEndOfFile];
if (inData)
inStr=[[NSString alloc] initWithData:inData encoding:outputEncoding];
}
}
}
NS_HANDLER
inStr=[[NSString alloc] initWithFormat:@"FSTask Error Exception %@ during execution of %@",[localException description],launchPath];
NS_ENDHANDLER
[aTask release];
return [inStr autorelease];
} else return @"doIt=NO";
}
@end
@implementation FSTaskRunByLisp
+ (NSString *)outputOfProgram:(NSString *)program withArguments:(NSArray *)args withInput:(NSString *)inputString inputEncoding:(NSStringEncoding)inputEncoding outputEncoding:(NSStringEncoding)outputEncoding;
{
NSString *convertedInput,*unConvertedOutput;
convertedInput=[[FSRecursiveReplacer returnReplacerFromRToN] transform:inputString]; // "\r" -> "\n"
unConvertedOutput=[super outputOfProgram:program withArguments:args withInput:convertedInput inputEncoding:inputEncoding outputEncoding:outputEncoding];
return [[FSRecursiveReplacer returnReplacerFromNToR] transform:unConvertedOutput];
}
@end