-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
KFAppleScriptHandlerAdditionsCore.m
235 lines (200 loc) · 7.71 KB
/
KFAppleScriptHandlerAdditionsCore.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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//
// KFAppleScriptHandlerAdditionsCore.m
// KFAppleScriptHandlerAdditions v. 2.3, 12/31, 2004
//
// Copyright (c) 2003-2004 Ken Ferry. Some rights reserved.
// http://homepage.mac.com/kenferry/software.html
//
// This work is licensed under a Creative Commons license:
// http://creativecommons.org/licenses/by-nc/1.0/
//
// Send me an email if you have any problems (after you've read what there is to read).
#import "KFAppleScriptHandlerAdditionsCore.h"
#import "KFASHandlerAdditions-TypeTranslation.h"
// these are from the OpenScripting carbon framework, but I'd rather not require linking it
#ifndef kASSubroutineEvent
#define kASSubroutineEvent 'psbr'
#endif
#ifndef kASAppleScriptSuite
#define kASAppleScriptSuite 'ascr'
#endif
#ifndef keyASSubroutineName
#define keyASSubroutineName 'snam'
#endif
#ifndef keyASUserRecordFields
#define keyASUserRecordFields 'usrf'
#endif
NSString *KFASException = @"KFASException";
@implementation NSAppleScript (KFAppleScriptHandlerAdditions)
// All other execute methods cascade down to this one.
- (NSAppleEventDescriptor *)kfExecuteWithoutTranslationHandler:(NSString *)handlerName
error:(NSDictionary **)errorInfo
withParametersDesc:(NSAppleEventDescriptor *)argumentsDesc
{
NSAppleEventDescriptor* event;
NSAppleEventDescriptor* targetAddress;
NSAppleEventDescriptor* subroutineDescriptor;
NSAppleEventDescriptor* resultDesc;
int pid = [[NSProcessInfo processInfo] processIdentifier];
targetAddress = [NSAppleEventDescriptor descriptorWithDescriptorType:typeKernelProcessID
bytes:&pid
length:sizeof(pid)];
event = [[NSAppleEventDescriptor alloc] initWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:targetAddress
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
// set up the handler
subroutineDescriptor = [NSAppleEventDescriptor descriptorWithString:[handlerName lowercaseString]];
[event setParamDescriptor:subroutineDescriptor forKeyword:keyASSubroutineName];
// set up the arguments
[event setParamDescriptor:argumentsDesc forKeyword:keyDirectObject];
// execute
resultDesc = [self executeAppleEvent:event error:errorInfo];
// cleanup
[event release];
return(resultDesc);
}
// probably could use a little work. Don't currently use NSAppleScriptErrorRange, code could be tighter.
- (void)kfHandleASError:(NSDictionary *)error
{
if (error != nil)
{
NSString *errorMessage, *briefErrorMessage, *reason;
NSNumber *errorNumber;
if ((errorMessage = [error objectForKey:NSAppleScriptErrorMessage]) != nil)
{
reason = errorMessage;
}
else if ((briefErrorMessage = [error objectForKey:NSAppleScriptErrorBriefMessage]) != nil)
{
reason = briefErrorMessage;
}
else if ((errorNumber = [error objectForKey:NSAppleScriptErrorNumber]) != nil)
{
reason = [NSString stringWithFormat:@"Error number %@.", errorNumber];
}
else
{
reason = @"AppleScript error, no further info.";
}
NSException *exception = [NSException exceptionWithName:KFASException
reason:reason
userInfo:error];
[exception raise];
}
}
// these next four execute methods make up the recommended API.
// Each calls upon the next and the last calls kfExecuteWithoutTranslationHandler:error:withParametersDesc:.
- (id)executeHandler:(NSString *)handlerName
{
return([self executeHandler:handlerName
withParameters:nil]);
}
- (id)executeHandler:(NSString *)handlerName
withParameter:(id)arg
{
if (arg == nil)
{
[NSException raise:NSInvalidArgumentException format:@"Parameter cannot be nil."];
}
return([self executeHandler:handlerName
withParameters:arg, nil]);
}
- (id)executeHandler:(NSString *)handlerName
withParameters:(NSObject *)firstArg, ...
{
NSMutableArray *argumentsArray;
va_list argList;
id anArg;
argumentsArray = [NSMutableArray array];
if (firstArg != nil)
{
[argumentsArray addObject:firstArg];
va_start(argList, firstArg);
while((anArg = va_arg(argList, id)) != nil)
[argumentsArray addObject:anArg];
va_end(argList);
}
return([self executeHandler:handlerName
withParametersFromArray:argumentsArray]);
}
- (id)executeHandler:(NSString *)handlerName
withParametersFromArray:(NSArray *)argumentsArray
{
NSAppleEventDescriptor *resultDesc;
NSDictionary *errorInfo = nil;
resultDesc = [self kfExecuteWithoutTranslationHandler:handlerName
error:&errorInfo
withParametersDesc:[argumentsArray aeDescriptorValue]];
if (errorInfo != nil)
{
[self kfHandleASError:errorInfo];
}
return([resultDesc objCObjectValue]);
}
// compatibility methods. It'd be a little strong to call these deprecated, but I think
// the above batch are more convenient. Who wants to deal with an error dictionary?
// Exceptions are much nicer, and you can retrieve the error dict with -[NSException userInfo]
// if you want.
//
// Each method here calls the next, and the last calls up to executeHandler:withParametersFromArray:.
// Thus changes made to the recommended methods will effect the compatibility methods.
- (id)executeHandler:(NSString *)handlerName
error:(NSDictionary **)errorInfo
{
return([self executeHandler:handlerName
error:errorInfo
withParameters:nil]);
}
- (id)executeHandler:(NSString *)handlerName
error:(NSDictionary **)errorInfo
withParameter:(id)arg
{
return([self executeHandler:handlerName
error:errorInfo
withParameters:arg, nil]);
}
- (id)executeHandler:(NSString *)handlerName
error:(NSDictionary **)errorInfo
withParameters:(NSObject *)firstArg, ...
{
NSMutableArray *argumentsArray;
va_list argList;
id anArg;
argumentsArray = [NSMutableArray array];
if (firstArg != nil)
{
[argumentsArray addObject:firstArg];
va_start(argList, firstArg);
while((anArg = va_arg(argList, id)) != nil)
[argumentsArray addObject:anArg];
va_end(argList);
}
return([self executeHandler:handlerName
error:errorInfo
withParametersFromArray:argumentsArray]);
}
- (id)executeHandler:(NSString *)handlerName
error:(NSDictionary **)errorInfo
withParametersFromArray:(NSArray *)argumentsArray
{
NSAppleEventDescriptor *resultDesc = nil;
// If we use @try @catch it is necessary to use -fobjc-exceptions.
// Save some email by using the old style exception handling.
NS_DURING
resultDesc = [self executeHandler:handlerName
withParametersFromArray:argumentsArray];
NS_HANDLER
if ([[localException name] isEqualToString:KFASException])
{
*errorInfo = [localException userInfo];
}
else
{
[localException raise];
}
NS_ENDHANDLER
return resultDesc;
}
@end