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.