1
1
/** Implementation of NSProtocolChecker for GNUStep
2
2
Copyright (C) 1995 Free Software Foundation, Inc.
4
Written by: Mike Kienenberger
4
Original by: Mike Kienenberger
6
Written: Richard Frith-Macdonald
7
9
This file is part of the GNUstep Base Library.
9
11
This library is free software; you can redistribute it and/or
10
12
modify it under the terms of the GNU Library General Public
11
13
License as published by the Free Software Foundation; either
12
14
version 2 of the License, or (at your option) any later version.
14
16
This library is distributed in the hope that it will be useful,
15
17
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
19
Library General Public License for more details.
19
21
You should have received a copy of the GNU Library General Public
20
22
License along with this library; if not, write to the Free
21
23
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
23
25
<title>NSProtocolChecker class reference</title>
24
$Date: 2001/12/18 16:54:15 $ $Revision: 1.10 $
26
$Date: 2004/08/20 17:53:16 $ $Revision: 1.19 $
27
29
#include "config.h"
28
#include <base/preface.h>
29
#include <Foundation/NSProtocolChecker.h>
30
#include <Foundation/NSException.h>
31
#include <Foundation/NSInvocation.h>
32
#include <Foundation/NSMethodSignature.h>
30
#include "GNUstepBase/preface.h"
31
#include "Foundation/NSProtocolChecker.h"
32
#include "Foundation/NSException.h"
33
#include "Foundation/NSInvocation.h"
34
#include "Foundation/NSMethodSignature.h"
37
* The NSProtocolChecker and NSProxy classes provide message filtering and
38
* forwarding capabilities. If you wish to ensure at runtime that a given
39
* object will only be sent messages in a certain protocol, you create an
40
* <code>NSProtocolChecker</code> instance with the protocol and the object as
44
id versatileObject = [[ClassWithManyMethods alloc] init];
45
id narrowObject = [NSProtocolChecker protocolCheckerWithTarget: versatileObject
46
protocol: @protocol(SomeSpecificProtocol)];
50
* This is often used in conjunction with distributed objects to expose only a
51
* subset of an objects methods to remote processes
34
53
@implementation NSProtocolChecker
37
* Allocates and initializes an NSProtocolChecker instance that will
38
* forward any messages in the aProtocol protocol to anObject, its
39
* target. Thus, the checker can be vended in lieu of anObject to
40
* restrict the messages that can be sent to anObject. Returns the
56
* Allocates and initializes an NSProtocolChecker instance by calling
57
* -initWithTarget:protocol:<br />
58
* Autoreleases and returns the new instance.
44
60
+ (id) protocolCheckerWithTarget: (NSObject*)anObject
45
61
protocol: (Protocol*)aProtocol
48
64
protocol: aProtocol]);
73
- (struct objc_method_description*) _methodDescription: (SEL)aSelector
75
extern struct objc_method_description *GSDescriptionForInstanceMethod();
76
extern struct objc_method_description *GSDescriptionForClassMethod();
78
if (_myProtocol != nil && _myTarget != nil)
80
struct objc_method_description* mth;
82
/* Older gcc versions may not initialise Protocol objects properly
83
* so we have an evil hack which checks for a known bad value of
84
* the class pointer, and uses an internal function
85
* (implemented in NSObject.m) to examine the protocol contents
86
* without sending any ObjectiveC message to it.
88
if (GSObjCIsInstance(_myTarget))
90
if ((int)GSObjCClass(_myProtocol) == 0x2)
92
mth = GSDescriptionForInstanceMethod(_myProtocol, aSelector);
96
mth = [_myProtocol descriptionForInstanceMethod: aSelector];
101
if ((int)GSObjCClass(_myProtocol) == 0x2)
103
mth = GSDescriptionForClassMethod(_myProtocol, aSelector);
107
mth = [_myProtocol descriptionForClassMethod: aSelector];
52
116
* Forwards any message to the delegate if the method is declared in
53
* the checker's protocol; otherwise raises an NSInvalidArgumentException.
117
* the checker's protocol; otherwise raises an
118
* <code>NSInvalidArgumentException</code>.
55
120
- (void) forwardInvocation: (NSInvocation*)anInvocation
60
if ((struct objc_method_description *)NULL
61
!= [self methodDescriptionForSelector: [anInvocation selector]])
62
[[NSException exceptionWithName: NSInvalidArgumentException
63
reason: @"Method not declared in current protocol"
64
userInfo: nil] raise];
124
if ([self _methodDescription: [anInvocation selector]] == 0)
126
if (GSObjCIsInstance(_myTarget))
128
[NSException raise: NSInvalidArgumentException
129
format: @"<%s -%@> not declared",
130
[_myProtocol name], NSStringFromSelector([anInvocation selector])];
134
[NSException raise: NSInvalidArgumentException
135
format: @"<%s +%@> not declared",
136
[_myProtocol name], NSStringFromSelector([anInvocation selector])];
66
139
[anInvocation invokeWithTarget: _myTarget];
68
length = [[anInvocation methodSignature] methodReturnLength];
69
buffer = (void *)malloc(length);
70
[anInvocation getReturnValue: buffer];
72
if (0 == strcmp([[anInvocation methodSignature] methodReturnType],
73
[[anInvocation methodSignatureForSelector:
74
@selector(init: )] methodReturnType]) )
142
* If the method returns 'self' (ie the target object) replace the
143
* returned value with the protocol checker.
145
type = [[anInvocation methodSignature] methodReturnType];
146
if (strcmp(type, @encode(id)) == 0)
76
if (((id)buffer) == _myTarget)
79
[anInvocation setReturnValue: buffer];
150
[anInvocation getReturnValue: &buf];
151
if (buf == _myTarget)
154
[anInvocation setReturnValue: &buf];
161
self = [self initWithTarget: nil protocol: nil];
96
166
* Initializes a newly allocated NSProtocolChecker instance that will
97
167
* forward any messages in the aProtocol protocol to anObject, its
98
168
* delegate. Thus, the checker can be vended in lieu of anObject to
99
* restrict the messages that can be sent to anObject. If anObject is
100
* allowed to be freed or dereferenced by clients, the free method
101
* should be included in aProtocol. Returns the new instance.
169
* restrict the messages that can be sent to anObject. If any method
170
* in the protocol returns anObject, the checker will replace the returned
171
* value with itself rather than the target object.<br />
172
* Returns the new instance.
103
174
- (id) initWithTarget: (NSObject*)anObject protocol: (Protocol*)aProtocol
107
176
_myProtocol = aProtocol;
109
177
ASSIGN(_myTarget, anObject);
115
* Returns an Objective C description for a method in the checker's
116
* protocol, or NULL if aSelector isn't declared as an instance method
119
- (struct objc_method_description*) methodDescriptionForSelector: (SEL)aSelector
181
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
121
return [_myProtocol descriptionForInstanceMethod: aSelector];
184
struct objc_method *mth;
188
[NSException raise: NSInvalidArgumentException
189
format: @"%@ null selector given", NSStringFromSelector(_cmd)];
192
* Evil hack to prevent recursion - if we are asking a remote
193
* object for a method signature, we can't ask it for the
194
* signature of methodSignatureForSelector:, so we hack in
195
* the signature required manually :-(
197
if (sel_eq(aSelector, _cmd))
199
static NSMethodSignature *sig = nil;
203
sig = [NSMethodSignature signatureWithObjCTypes: "@@::"];
209
if (_myProtocol != nil)
211
const char *types = 0;
212
struct objc_method_description *desc;
214
desc = [self _methodDescription: aSelector];
223
return [NSMethodSignature signatureWithObjCTypes: types];
226
c = GSObjCClass(self);
227
mth = GSGetMethod(c, aSelector, YES, YES);
230
return nil; // Method not implemented
232
types = mth->method_types;
235
* If there are protocols that this class conforms to,
236
* the method may be listed in a protocol with more
237
* detailed type information than in the class itself
238
* and we must therefore use the information from the
240
* This is because protocols also carry information
241
* used by the Distributed Objects system, which the
242
* runtime does not maintain in classes.
244
if (c->protocols != 0)
246
struct objc_protocol_list *protocols = c->protocols;
249
while (found == NO && protocols != 0)
253
while (found == NO && i < protocols->count)
256
struct objc_method_description *pmth;
258
p = protocols->list[i++];
259
if (c == (Class)self)
261
pmth = [p descriptionForClassMethod: aSelector];
265
pmth = [p descriptionForInstanceMethod: aSelector];
273
protocols = protocols->next;
281
return [NSMethodSignature signatureWithObjCTypes: types];
125
285
* Returns the protocol object the checker uses to verify whether a
126
* given message should be forwarded to its delegate, or the protocol
127
* checker should raise an NSInvalidArgumentException.
286
* given message should be forwarded to its delegate.
129
288
- (Protocol*) protocol
131
if (nil == _myProtocol)
132
[[NSException exceptionWithName: NSInvalidArgumentException
133
reason: @"No protocol specified"
134
userInfo: nil] raise];
136
290
return _myProtocol;
140
294
* Returns the target of the NSProtocolChecker.
142
296
- (NSObject*) target