This is MOString.m in view mode; [Download] [Up]
// MOString.m // // by Mike Ferris // Part of MOKit // Copyright 1993, all rights reserved. // ABOUT MOKit // by Mike Ferris (mike@lorax.com) // // MOKit is a collection of useful and general objects. Permission is // granted by the author to use MOKit in your own programs in any way // you see fit. All other rights pertaining to the kit are reserved by the // author including the right to sell these objects as objects, as part // of a LIBRARY, or as SOURCE CODE. In plain English, I wish to retain // rights to these objects as objects, but allow the use of the objects // as pieces in a fully functional program. Permission is also granted to // redistribute the source code of MOKit for FREE as long as this copyright // notice is left intact and unchanged. NO WARRANTY is expressed or implied. // The author will under no circumstances be held responsible for ANY // consequences from the use of these objects. Since you don't have to pay // for them, and full source is provided, I think this is perfectly fair. #import "MOKit/MOString.h" #import <objc/objc-runtime.h> #define CLASS_VERSION 0 #define CLASS_NAME "MOString" extern char *MOBuildStringFromFormatV(const char *formatStr, va_list param_list); @implementation MOString // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=- Initializing the class -=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + initialize // Set our version. { if (self == objc_lookUpClass(CLASS_NAME)) { [self setVersion:CLASS_VERSION]; } return self; } // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-= Initializing, copying, and freeing MOStrings =-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - init // Initializes a NULL instance of the string { [self initStringValueNoCopy:NULL shouldFree:NO]; return self; } - initStringValue:(const char *)s // Initializes an instance with a copy of s { char *copyOfS=NULL; if (s) { NX_MALLOC(copyOfS, char, strlen(s)+1); strcpy(copyOfS, s); } [self initStringValueNoCopy:copyOfS shouldFree:YES]; return self; } - initStringValueNoCopy:(char *)s // Initializes an instance with s. No copy is made, but the string takes // responsibility for the memory. { [self initStringValueNoCopy:s shouldFree:YES]; return self; } - initStringValueNoCopy:(char *)s shouldFree:(BOOL)flag // DESIGNATED INITIALIZER: inits an instance using the string passed. // No copy is made and the String object assumes responsibility for // freeing it's memory only if flag is YES. // Override this and the other initializers should work properly without // having to override them (unless you want to change their behavior). { [super init]; [self setStringValueNoCopy:s shouldFree:flag]; return self; } - initStringValueUnique:(const char *)s // Initializes the string as a unique string. { [self initStringValueNoCopy:NULL shouldFree:NO]; [self setStringValueUnique:s]; return self; } - initFromFormat:(const char *)formatStr, ... // Initializes the string from printf style format string and arguments. { va_list param_list; char *buf; va_start(param_list, formatStr); buf = MOBuildStringFromFormatV(formatStr, param_list); va_end(param_list); [self initStringValueNoCopy:buf shouldFree:YES]; return self; } - copyFromZone:(NXZone *)zone // Copies the string (making a copy of the str memory too only if the // original will free its memory.) The copy is always configured exactly // as the original except for (possibly) the memory it uses. { id obj = [super copyFromZone:zone]; // a non-freeing MOString that "owns" its memory needs its OWN memory if (shouldFree) { [obj setShouldFree:NO]; // So our original string won't get freed. [obj setStringValue:[self stringValue]]; } return obj; } - deepCopy // Returns a copy of the receiver in the same zone as the receiver. // Always copies the contents too. The new object always ends up with // shouldFree = YES. The returned MOString is NOT unique, even if the // original was. { return [self deepCopyFromZone:[self zone]]; } - deepCopyFromZone:(NXZone *)zone // Returns a copy of the receiver in the zone given. // Always copies the contents too. The new object always ends up with // shouldFree = YES. The returned MOString is NOT unique, even if the // original was. { id obj = [super copyFromZone:zone]; // always make a copy of the contents. [obj setShouldFree:NO]; // So our original string won't get freed. [obj setStringValue:[self stringValue]]; return obj; } - shallowCopy // Returns a copy of the receiver in the same zone as the receiver. // Never copies the contents. The new object always ends up with // shouldFree = NO. Everything else is preserved. This can be dangerous // because if the original string is freed before the copy, the // copy will point to oblivion. { return [self shallowCopyFromZone:[self zone]]; } - shallowCopyFromZone:(NXZone *)zone // Returns a copy of the receiver in the zone given. // Never copies the contents. The new object always ends up with // shouldFree = NO. Everything else is preserved. This can be dangerous // because if the original string is freed before the copy, the // copy will point to oblivion. { id obj = [super copyFromZone:zone]; // never make a copy of the contents, but always set the shouldFree // flag to NO. [obj setShouldFree:NO]; return obj; } - free // Frees the string object and storage. { if (shouldFree) NX_FREE(str); return [super free]; } // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-= Configuring MOStrings =-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - setStringValue:(const char *)s // Sets the string to a copy of s. { if (shouldFree) NX_FREE(str); if (s==NULL) { return [self setNull]; } len = strlen(s); NX_MALLOC(str, char, len+1); strcpy(str, s); isUnique = NO; uStr = NULL; shouldFree = YES; return self; } - setStringValueNoCopy:(char *)s // Sets the string ptr to s. // No copy is made and the String object does not assume responsibility for // freeing it's memory. { [self setStringValueNoCopy:s shouldFree:NO]; return self; } - setStringValueNoCopy:(char *)s shouldFree:(BOOL)flag // Sets the string ptr to s. // No copy is made and the String object assumes responsibility for // freeing it's memory if flag is YES. If flag is NO, the String will NOT // free the memory. { if (shouldFree) NX_FREE(str); if (s==NULL) { return [self setNull]; } str = s; len = strlen(s); isUnique = NO; uStr = NULL; shouldFree = flag; return self; } - setStringValueUnique:(const char *)s // Sets the string ptr to a 'Uniqued' version of s. Unique strings // are never freed by MOString. { if (shouldFree) NX_FREE(str); if (s==NULL) { return [self setNull]; } uStr = NXUniqueString(s); len = strlen(uStr); isUnique = YES; str = NULL; shouldFree = NO; return self; } - setFromFormat:(const char *)formatStr, ... // Sets the string from and printf style format string and arguments. { va_list param_list; char *buf; va_start(param_list, formatStr); buf = MOBuildStringFromFormatV(formatStr, param_list); va_end(param_list); [self setStringValueNoCopy:buf shouldFree:YES]; return self; } - setIntValue:(int)val // Sets the string by converting the given int to a string. { return [self setFromFormat:"%d", val]; } - setFloatValue:(float)val // Sets the string by converting the given float to a string. { return [self setFromFormat:"%f", val]; } - setDoubleValue:(double)val // Sets the string by converting the given double to a string. { return [self setFromFormat:"%f", val]; } - setNull // Sets the string ptr to NULL (freeing any string that used to be there // if it should). { if (shouldFree) NX_FREE(str); str = NULL; len = 0; isUnique = NO; uStr = NULL; shouldFree = NO; return self; } - makeUnique // Transforms the string into a unique string. Meaning that the string // won't be freed by the MOString. The old representation of the string // is freed after the conversion if it should be. { if ([self isNull]) { return nil; } if (isUnique) return self; uStr = NXUniqueString(str); if (shouldFree) NX_FREE(str); str = NULL; isUnique = YES; shouldFree = NO; return self; } - setShouldFree:(BOOL)flag // Set whether this string will be freed. If the string is unique, do not // allow this flag to change. { if (!isUnique) { shouldFree = flag; } return self; } // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=- Querying MOStrings -=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - (const char *)stringValue // Returns the actual internal string ptr. DO NOT MODIFY IT. { return (isUnique?uStr:str); } - (int)intValue // Returns the string converted to an int. { return atoi(isUnique?uStr:str); } - (float)floatValue // Returns the string converted to an float. { return (float)atof(isUnique?uStr:str); } - (double)doubleValue // Returns the string converted to an double. { return atof(isUnique?uStr:str); } - (char *)getCopyInto:(char *)buf // Returns a copy of the contents of the MOString. If buf is non-NULL then // the memory it points to is used and returned and it better be big enough. // If buf is NULL then exactly enough memory is allocated and returned. { if (!buf) { NX_MALLOC(buf, char, len+1); } strcpy(buf, (isUnique?uStr:str)); return buf; } - (size_t)length // Returns the length of the string. { return len; } - (unsigned int)count // Returns the length of the string. { return (unsigned int)len; } - (BOOL)isNull // Returns whether the string is null. { return (isUnique?uStr==NULL:str==NULL); } - (BOOL)isEmpty // Returns whether the length is zero. (ie returns YES if the string isNull // or is "") { return (len==0); } - (BOOL)isUnique // Returns whether the string is unique. If it isUnique you can treat // the return value of -str or -stringValue can be treated as an NXAtom. { return isUnique; } - (BOOL)shouldFree // Returns whether the MOString will free the memory used to hold its contents. { return shouldFree; } // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-= Archiving methods =-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - write:(NXTypedStream *)typedStream // Archive the string to a typed stream. { [super write:typedStream]; NXWriteType(typedStream, "c", &isUnique); if (isUnique) { NXWriteType(typedStream, "%", &uStr); } else { NXWriteType(typedStream, "*", &str); } NXWriteType(typedStream, "i", &len); NXWriteType(typedStream, "c", &shouldFree); return self; } - read:(NXTypedStream *)typedStream // int NXTypedStreamClassVersion(NXTypedStream *typedStream, // const char *className) // can be used to handle multi version reading and writing. { int classVersion; [super read:typedStream]; classVersion = NXTypedStreamClassVersion(typedStream, CLASS_NAME); switch (classVersion) { case 0: // First version. NXReadType(typedStream, "c", &isUnique); if (isUnique) { NXReadType(typedStream, "%", &uStr); str = NULL; } else { NXReadType(typedStream, "*", &str); uStr = NULL; } NXReadType(typedStream, "i", &len); NXReadType(typedStream, "c", &shouldFree); break; default: NXLogError("[%s read:] class version %d cannot read " "instances archived with version %d", CLASS_NAME, CLASS_VERSION, classVersion); [self setStringValueNoCopy:NULL shouldFree:YES]; break; } return self; } // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-= NXTransport protocol =-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - encodeRemotelyFor:(NXConnection *)connection freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isBycopy // This method is called when the string is vended over a distributed object // connection. MOString is capable of copying itself wholly over the // connection, so if byCopy is requested we honor it. { if (isBycopy) return self; return [super encodeRemotelyFor:connection freeAfterEncoding:flagp isBycopy:isBycopy]; } - encodeUsing:(id <NXEncoding>)portal // Encode the string for transmission across a distributed object connection. { // if ([super respondsTo:@selector(encodeUsing:)]) { // [super encodeUsing:portal]; // } [portal encodeData:&isUnique ofType:"c"]; if (isUnique) { [portal encodeData:&uStr ofType:"%"]; } else { [portal encodeData:&str ofType:"*"]; } [portal encodeData:&len ofType:"i"]; [portal encodeData:&shouldFree ofType:"c"]; return self; } - decodeUsing:(id <NXDecoding>)portal // Decode the data sent over the distributed object connection into // the receiving MOString. { // if ([super respondsTo:@selector(decodeUsing:)]) { // [super decodeUsing:portal]; // } else { [self init]; // } [portal decodeData:&isUnique ofType:"c"]; if (isUnique) { [portal decodeData:&uStr ofType:"%"]; str=NULL; } else { [portal decodeData:&str ofType:"*"]; uStr=NULL; } [portal decodeData:&len ofType:"i"]; [portal decodeData:&shouldFree ofType:"c"]; return self; } // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=- Hashing and isEqual -=-=-=-=-=-=-=-=-=-=-=-=-= // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - (unsigned int)hash // Use the NextStep string hashing functiuon NXStrHash() instead of // the pointer hashing function. { return NXStrHash(NULL, (isUnique?uStr:str)); } - (BOOL)isEqual:anObj // MOStrings are equal if they are identical or if their contents are // equal by NXStrIsEqual() (which I assume is constructed to be // compatible with NXStrHash() since they are described together in the // NextStep docs. { if (anObj == self) return YES; if ([anObj isKindOfClassNamed:CLASS_NAME]) { if (NXStrIsEqual(NULL, (isUnique?uStr:str), [anObj stringValue])) { return YES; } } return NO; } // ******************** Private Supporting Functions ******************** char *MOBuildStringFromFormatV(const char *formatStr, va_list param_list) // This function takes a format string and a variable argument list. // It returns a pointer to a newly allocated chunk of memory containing // the results of sprintf'ing the format string and va_list into the // new memory. { NXStream *stream; long l; char *buf; stream = NXOpenMemory(NULL, 0, NX_READWRITE); NXVPrintf(stream, formatStr, param_list); NXFlush(stream); NXSeek(stream, 0, NX_FROMEND); l = NXTell(stream); NXSeek(stream, 0, NX_FROMSTART); NX_MALLOC(buf, char, l+1); NXRead(stream, buf, l); buf[l]='\0'; NXCloseMemory(stream, NX_FREEBUFFER); return buf; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.