[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Modifications on gnustep-base for OSX compatibility
From: |
Stéphane Corthésy |
Subject: |
Modifications on gnustep-base for OSX compatibility |
Date: |
Thu, 27 Mar 2003 20:36:50 -0000 |
Hi,
Here are some methods missing in gnustep-base for MacOS X
compatibility; they are defined in gnustep, but should/could be moved
in Additions/GSCategories.h/m. They are needed to compile gsweb on OSX.
I'm not sure at all that my reimplementation of
GSCurrentThreadDictionary() is correct!
I also have a question concerning GCxxx classes: shouldn't all
retain/release/autorelease calls be replaced by macros too? If so, I'll
provide a patch.
Other question: in base/Source/Additions/GSMime.m, in -[GSMimeDocument
copyWithZone:], shouldn't the implementation do a real copy, as the
instances are mutable, instead of simply performing a RETAIN() on self?
Same question for -[GSXMLDocument copyWithZone:].
Stéphane
===========
Changelog
base/Headers/gnustep/base/GSCategories.h: declared new methods
base/Source/Additions/GSCategories.m: new compatibility methods for
NSString and NSMutableString (copied from NSString.m); implemented
+[NSDistantObject setDebug:] by using Apple's private method, if method
exists; copied -[NSNumber valueFromString:] from NSNumber.m; added
simple implementation of GSCurrentThreadDictionary(); provided
implementations of -[NSFileHandle
initAsServerAtAddress:service:protocol:], +[NSFileHandle
fileHandleAsServerAtAddress:service:protocol:] and -[NSFileHandle
socketAddress] - code has been adapted from GSFileHandle;
Index: GSCategories.h
===================================================================
RCS file:
/cvsroot/gnustep/gnustep/core/base/Headers/gnustep/base/GSCategories.h,v
retrieving revision 1.7
diff -r1.7 GSCategories.h
36a37
> #include <gnustep/base/GSObjCRuntime.h>
55a57,61
> - (NSString*) stringByTrimmingLeadSpaces;
> - (NSString*) stringByTrimmingTailSpaces;
> - (NSString*) stringByTrimmingSpaces;
> - (NSString*) stringByReplacingString: (NSString*)replace
> withString: (NSString*)by;
60a67,71
> - (void) replaceString: (NSString*)replace
> withString: (NSString*)by;
> - (void) trimLeadSpaces;
> - (void) trimTailSpaces;
> - (void) trimSpaces;
73a85,101
>
> @interface NSDistantObject (GSCategories)
> + (void) setDebug: (int)val;
> @end
>
> @interface NSNumber(GSCategories)
> + (NSValue*) valueFromString: (NSString *)string;
> @end
>
> GS_EXPORT NSMutableDictionary *GSCurrentThreadDictionary();
>
> @interface NSFileHandle(GSCompatibility)
> + (id) fileHandleAsServerAtAddress: (NSString*)address
> service: (NSString*)service
> protocol: (NSString*)protocol;
> - (NSString*) socketAddress;
> @end
Index: GSCategories.m
===================================================================
RCS file:
/cvsroot/gnustep/gnustep/core/base/Source/Additions/GSCategories.m,v
retrieving revision 1.9
diff -r1.9 GSCategories.m
608a609,742
> /**
> * Returns a string formed by removing leading white space from the
> * receiver.
> */
> - (NSString*) stringByTrimmingLeadSpaces
> {
> static SEL caiSel = NULL;
> unsigned length = [self length];
>
> if (length > 0)
> {
> unsigned start = 0;
> unichar (*caiImp)(NSString*, SEL, unsigned int);
>
> if(caiSel == NULL)
> caiSel = @selector(characterAtIndex:);
> caiImp = (unichar (*)())[self methodForSelector: caiSel];
> while (start < length && isspace((*caiImp)(self, caiSel,
start)))
> {
> start++;
> }
> if (start > 0)
> {
> return [self substringFromIndex: start];
> }
> }
> return self;
> }
>
> /**
> * Returns a string formed by removing trailing white space from the
> * receiver.
> */
> - (NSString*) stringByTrimmingTailSpaces
> {
> static SEL caiSel = NULL;
> unsigned length = [self length];
>
> if (length > 0)
> {
> unsigned end = length;
> unichar (*caiImp)(NSString*, SEL, unsigned int);
>
> if(caiSel == NULL)
> caiSel = @selector(characterAtIndex:);
> caiImp = (unichar (*)())[self methodForSelector: caiSel];
> while (end > 0)
> {
> if (!isspace((*caiImp)(self, caiSel, end - 1)))
> {
> break;
> }
> end--;
> }
> if (end < length)
> {
> return [self substringToIndex: end];
> }
> }
> return self;
> }
>
> /**
> * Returns a string formed by removing both leading and trailing
> * white space from the receiver.
> */
> - (NSString*) stringByTrimmingSpaces
> {
> static SEL caiSel = NULL;
> unsigned length = [self length];
>
> if (length > 0)
> {
> unsigned start = 0;
> unsigned end = length;
> unichar (*caiImp)(NSString*, SEL, unsigned int);
>
> if(caiSel == NULL)
> caiSel = @selector(characterAtIndex:);
> caiImp = (unichar (*)())[self methodForSelector: caiSel];
> while (start < length && isspace((*caiImp)(self, caiSel,
start)))
> {
> start++;
> }
> while (end > start)
> {
> if (!isspace((*caiImp)(self, caiSel, end - 1)))
> {
> break;
> }
> end--;
> }
> if (start > 0 || end < length)
> {
> if (start < end)
> {
> return [self substringWithRange:
> NSMakeRange(start, end - start)];
> }
> else
> {
> return [NSString string];
> }
> }
> }
> return self;
> }
>
> /**
> * Returns a string in which any (and all) occurrances of
> * replace in the receiver have been replaced with by.
> * Returns the receiver if replace
> * does not occur within the receiver. NB. an empty string is
> * not considered to exist within the receiver.
> */
> - (NSString*) stringByReplacingString: (NSString*)replace
> withString: (NSString*)by
> {
> NSRange range = [self rangeOfString: replace];
>
> if (range.length > 0)
> {
> NSMutableString *tmp = [self mutableCopy];
> NSString *str;
>
> [tmp replaceString: replace withString: by];
> str = AUTORELEASE([tmp copy]);
> RELEASE(tmp);
> return str;
> }
> else
> return self;
> }
>
633a768,1075
> }
>
> /**
> * Replaces all occurrances of the string replace with the string by
> * in the receiver.<br />
> * Has no effect if replace does not occur within the
> * receiver. NB. an empty string is not considered to exist within
> * the receiver.<br />
> * Calls - replaceOccurrencesOfString:withString:options:range:
passing
> * zero for the options and a range from 0 with the length of the
receiver.
> */
> - (void) replaceString: (NSString*)replace
> withString: (NSString*)by
> {
> [self replaceOccurrencesOfString: replace
> withString: by
> options: 0
> range: NSMakeRange(0, [self
length])];
> }
>
> /**
> * Removes all leading white space from the receiver.
> */
> - (void) trimLeadSpaces
> {
> static SEL caiSel = NULL;
> unsigned length = [self length];
>
> if (length > 0)
> {
> unsigned start = 0;
> unichar (*caiImp)(NSString*, SEL, unsigned int);
>
> if(caiSel == NULL)
> caiSel = @selector(characterAtIndex:);
> caiImp = (unichar (*)())[self methodForSelector: caiSel];
> while (start < length && isspace((*caiImp)(self, caiSel,
start)))
> {
> start++;
> }
> if (start > 0)
> {
> [self deleteCharactersInRange: NSMakeRange(0, start)];
> }
> }
> }
>
> /**
> * Removes all trailing white space from the receiver.
> */
> - (void) trimTailSpaces
> {
> static SEL caiSel = NULL;
> unsigned length = [self length];
>
> if (length > 0)
> {
> unsigned end = length;
> unichar (*caiImp)(NSString*, SEL, unsigned int);
>
> if(caiSel == NULL)
> caiSel = @selector(characterAtIndex:);
> caiImp = (unichar (*)())[self methodForSelector: caiSel];
> while (end > 0 && isspace((*caiImp)(self, caiSel, end - 1)))
> {
> end--;
> }
> if (end < length)
> {
> [self deleteCharactersInRange: NSMakeRange(end, length -
end)];
> }
> }
> }
>
> /**
> * Removes all leading or trailing white space from the receiver.
> */
> - (void) trimSpaces
> {
> [self trimTailSpaces];
> [self trimLeadSpaces];
> }
>
> @end
>
> @interface NSDistantObject (GSCategoriesRevealed)
> // This method is implemented in MacOS X 10.2.4, but is not public
> + (void) _enableLogging:(BOOL)flag;
> @end
>
> @implementation NSDistantObject (GSCategories)
>
> + (void) setDebug: (int)val
> {
> if([self respondsToSelector:@selector(_enableLogging:)])
> [self _enableLogging:!!val];
> }
>
> @end
>
> @implementation NSNumber(GSCategories)
>
> + (NSValue*) valueFromString: (NSString*)string
> {
> /* FIXME: implement this better */
> const char *str;
>
> str = [string cString];
> if (strchr(str, '.') >= 0 || strchr(str, 'e') >= 0
> || strchr(str, 'E') >= 0)
> return [NSNumber numberWithDouble: atof(str)];
> else if (strchr(str, '-') >= 0)
> return [NSNumber numberWithInt: atoi(str)];
> else
> return [NSNumber numberWithUnsignedInt: atoi(str)];
> return [NSNumber numberWithInt: 0];
> }
>
> @end
>
> NSMutableDictionary *GSCurrentThreadDictionary()
> {
> return [[NSThread currentThread] threadDictionary];
> }
>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <netinet/in.h>
> #include <arpa/inet.h>
> #include <netdb.h>
> #include <unistd.h>
>
>
> @implementation NSFileHandle(GSCompatibility)
> // From GSFileHandle.m
>
> static BOOL
> getAddr(NSString* name, NSString* svc, NSString* pcl, struct
sockaddr_in *sin)
> {
> const char *proto = "tcp";
> struct servent *sp;
>
> if (pcl)
> {
> proto = [pcl lossyCString];
> }
> memset(sin, '\0', sizeof(*sin));
> sin->sin_family = AF_INET;
>
> /*
> * If we were given a hostname, we use any address for that host.
> * Otherwise we expect the given name to be an address unless it
is
> * a null (any address).
> */
> if (name)
> {
> NSHost* host = [NSHost hostWithName: name];
>
> if (host != nil)
> {
> name = [host address];
> }
> #ifndef HAVE_INET_ATON
> sin->sin_addr.s_addr = inet_addr([name lossyCString]);
> if (sin->sin_addr.s_addr == INADDR_NONE)
> #else
> if (inet_aton([name lossyCString], &sin->sin_addr) == 0)
> #endif
> {
> return NO;
> }
> }
> else
> {
> sin->sin_addr.s_addr = NSSwapHostIntToBig(INADDR_ANY);
> }
> if (svc == nil)
> {
> sin->sin_port = 0;
> return YES;
> }
> else if ((sp = getservbyname([svc lossyCString], proto)) == 0)
> {
> const char* ptr = [svc lossyCString];
> int val = atoi(ptr);
>
> while (isdigit(*ptr))
> {
> ptr++;
> }
> if (*ptr == '\0' && val <= 0xffff)
> {
> unsigned short v = val;
>
> sin->sin_port = NSSwapHostShortToBig(v);
> return YES;
> }
> else if (strcmp(ptr, "gdomap") == 0)
> {
> unsigned short v;
> #ifdef GDOMAP_PORT_OVERRIDE
> v = GDOMAP_PORT_OVERRIDE;
> #else
> v = 538; // IANA allocated port
> #endif
> sin->sin_port = NSSwapHostShortToBig(v);
> return YES;
> }
> else
> {
> return NO;
> }
> }
> else
> {
> sin->sin_port = sp->s_port;
> return YES;
> }
> }
>
> - (id) initAsServerAtAddress: (NSString*)a
> service: (NSString*)s
> protocol: (NSString*)p
> {
> #ifndef BROKEN_SO_REUSEADDR
> int status = 1;
> #endif
> int net;
> struct sockaddr_in sin;
> int size = sizeof(sin);
>
> if (getAddr(a, s, p, &sin) == NO)
> {
> RELEASE(self);
> NSLog(@"bad address-service-protocol combination");
> return nil;
> }
>
> if ((net = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0)
> {
> NSLog(@"unable to create socket - %s", GSLastErrorStr(errno));
> RELEASE(self);
> return nil;
> }
>
> #ifndef BROKEN_SO_REUSEADDR
> /*
> * Under decent systems, SO_REUSEADDR means that the port can be
reused
> * immediately that this process exits. Under some it means
> * that multiple processes can serve the same port simultaneously.
> * We don't want that broken behavior!
> */
> setsockopt(net, SOL_SOCKET, SO_REUSEADDR, (char *)&status,
sizeof(status));
> #endif
>
> if (bind(net, (struct sockaddr *)&sin, sizeof(sin)) < 0)
> {
> NSLog(@"unable to bind to port %s:%d - %s",
inet_ntoa(sin.sin_addr),
> NSSwapBigShortToHost(sin.sin_port),
GSLastErrorStr(errno));
> (void) close(net);
> RELEASE(self);
> return nil;
> }
>
> if (listen(net, 5) < 0)
> {
> NSLog(@"unable to listen on port - %s",
GSLastErrorStr(errno));
> (void) close(net);
> RELEASE(self);
> return nil;
> }
>
> if (getsockname(net, (struct sockaddr*)&sin, &size) < 0)
> {
> NSLog(@"unable to get socket name - %s",
GSLastErrorStr(errno));
> (void) close(net);
> RELEASE(self);
> return nil;
> }
>
> self = [self initWithFileDescriptor: net closeOnDealloc: YES];
>
> return self;
> }
>
> + (id) fileHandleAsServerAtAddress: (NSString*)address
> service: (NSString*)service
> protocol: (NSString*)protocol
> {
> id o = [self allocWithZone: NSDefaultMallocZone()];
>
> return AUTORELEASE([o initAsServerAtAddress: address
> service: service
> protocol: protocol]);
> }
>
> - (NSString*) socketAddress
> {
> struct sockaddr_in sin;
> int size = sizeof(sin);
>
> if (getsockname([self fileDescriptor], (struct sockaddr*)&sin,
&size) < 0)
> {
> NSLog(@"unable to get socket name - %s",
GSLastErrorStr(errno));
> return nil;
> }
>
> return [[[NSString alloc] initWithCString:
(char*)inet_ntoa(sin.sin_addr)] autorelease];
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Modifications on gnustep-base for OSX compatibility,
Stéphane Corthésy <=