This is RCString.m in view mode; [Download] [Up]
#import <RCString.h> /* Copyright (C) 1992. Bruce Ediger. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License. */ @implementation RCString // Initialize the internal string rep, but not the // internal string itself. // Assumes that "self" is already allocated. - init { [super init]; if (p = (struct srep *) malloc(sizeof(struct srep))) { p->s = NULL; p->l = 0; p->n = 1; } yCaseSensitive = YES; return self; } // construct an object with zero-length string internal string rep + new { RCString *oNew = [[RCString alloc] init]; if (oNew) { oNew->p->s = malloc(1); *oNew->p->s = '\0'; oNew->p->l = 1; oNew->p->n = 1; } return oNew; } // Construct an object surrounding a given ASCII string. // Should this method make a copy of the ASCIIZ argument? // Since the object is copy-on-write, we could maybe get // away with just keeping around the pointer. No. Then // anything could change the string out from underneath the // object. + newFromString:(char *)aString { RCString *oNewString; if (aString) { oNewString = [[RCString alloc] init]; if (oNewString) { oNewString->p->l = strlen(aString) + 1; if ((oNewString->p->s = malloc(oNewString->p->l))) { bcopy(aString, oNewString->p->s, oNewString->p->l); oNewString->p->n = 1; } else oNewString->p->l = 0; // malloc() failed, retain consistency } oNewString->yCaseSensitive = YES; } else { // null argument string oNewString = [RCString new]; } return oNewString; } // Factory Method copy constructor analog: an object that // references another object's internal string rep. + newFromObject:(RCString *) oString { RCString *oNewString; if (oString && (oNewString = [RCString alloc])) { // RCString objects will share internal string rep until a write. oNewString->p = oString->p; oNewString->p->n++; oNewString->yCaseSensitive = oString->yCaseSensitive; } else { // passed a null object pointer: fill in a zero-length // internal string rep oNewString = [RCString new]; } return oNewString; } // Copy constructor analog: an object that references this // object's internal string rep. - newFromObject { RCString *oNewString; if ((oNewString = [RCString alloc])) { // RCString objects will share internal string rep until a write. oNewString->p = p; oNewString->yCaseSensitive = yCaseSensitive; if (p) p->n++; } return oNewString; } + newFilledWith: (int) bCharacter size: (int) iNumber { RCString *oNewString; char *bpTmp; if (bCharacter && iNumber > 0 && (bpTmp = malloc(iNumber + 1))) { int icCount; for (icCount = 0; icCount < iNumber + 1; ++icCount) bpTmp[icCount] = (char )bCharacter; bpTmp[iNumber] = '\0'; oNewString = [RCString newFromString:bpTmp]; } else { // args specifiy null/zero-length string or malloc() failure oNewString = [RCString new]; } return oNewString; } - free { // should the test be "==" or "<=" ? // <= would probably catch some mistakes. if (p && --p->n == 0) { // reference count's gone to zero, free internal string rep if (p->s) free(p->s); free(p); } return [super free]; } // private use method. // causes the RCString object that this message is sent to, // to copy it's internal string representation. // typically called before modifying internal string rep // in order to provide copy-on-write behavior. - copyReference { struct srep *psNewSrep = (struct srep *)malloc(sizeof(struct srep)); if (psNewSrep) { if (p) { if (p->s) { psNewSrep->s = malloc(p->l); if (psNewSrep->s) { bcopy(p->s, psNewSrep->s, p->l); psNewSrep->l = p->l; } } else { psNewSrep->s = NULL; psNewSrep->l = 0; } // check reference count on previous internal rep if (--p->n == 0) { free(p->s); free(p); } psNewSrep->n = 1; p = psNewSrep; } else { // Object didn't have an internal string rep for some // reason. Give it it's own NULL string psNewSrep->s = NULL; psNewSrep->n = 1; psNewSrep->l = 0; p = psNewSrep; } } // what if malloc() of struct srep fails? return self; } - (BOOL) isNull { if (!p && (!p->s || p->l <= 1)) // ignore trailing ASCII NULL return YES; return NO; } // returns "strlen" of internal representation. // that is, length without trailing NULL. - (unsigned)length { if (p && p->l) return(p->l - 1); return 0; } - (char *)data { return p ? p->s : NULL; } - (int)references { return p ? p->n : 0; } - (struct srep *)internal { return p; } @end @implementation RCString(Archiving) // Archiving methods borrowed from John Hassey's String // object. Try to maintain compatibility. - storeOn: (int) aFd { #ifndef NeXT [super storeOn: aFd]; #endif if (write(aFd, &p->l, sizeof(p->l)) == -1) { [self error: "storeOn: write error"]; } if (write(aFd, "\"", 1) == -1) { [self error: "storeOn: write error"]; } if (write(aFd, [self data], [self length]) == -1) { [self error: "storeOn: write error"]; } if (write(aFd, "\"", 1) == -1) { [self error: "storeOn: write error"]; } return self; } - readFrom: (int) aFd { char c; #ifndef NeXT [super readFrom: aFd]; #endif if (p == NULL) { p = (struct srep *)malloc(sizeof(struct srep)); } else { if (p->n == 1) if (p->s) free(p->s); else { // Come up with a new internal rep struct. It // will be completely redone anyway. --p->n; p = (struct srep *)malloc(sizeof(struct srep)); } } if (read(aFd, &p->l, sizeof(p->l)) == -1) [self error: "readFrom: read error"]; p->s = malloc(p->l); if (read(aFd, &c, 1) == -1) [self error: "readFrom: read error"]; if (c != '"') [self error: "readFrom: format error"]; if (read(aFd, p->s, p->l - 1) == -1) [self error: "readFrom: read error"]; if (read(aFd, &c, 1) == -1) [self error: "readFrom: read error"]; if (c != '"') [self error: "readFrom: format error"]; // null terminate string p->s[p->l - 1] = 0; return self; } #ifdef NeXT - write:(NXTypedStream *)aStream { [super write:aStream]; if (p) { int iFakeN = 1; NXWriteType(aStream, "i", &p->l); // length first, so read: can // allocate memory for string. if (p->s) NXWriteType(aStream, "*", &p->s); else { char *bpTmp = ""; NXWriteType(aStream, "*", &bpTmp); } NXWriteType(aStream, "i", &iFakeN); NXWriteType(aStream, "c", &yCaseSensitive); } else { // Fake the whole internal rep as a zero-length string. char *bpTmp = ""; int iTmpL = 1; int iTmpN = 1; BOOL yTmpCS = TRUE; NXWriteType(aStream, "i", &iTmpL); NXWriteType(aStream, "*", &bpTmp); NXWriteType(aStream, "i", &iTmpN); NXWriteType(aStream, "c", &yTmpCS); } return self; } - read:(NXTypedStream *)aStream { [super read:aStream]; // prepare internal string rep if (p) { if (p->n == 1) { if (p->s) free(p->s); } else { --p->n; p = (struct srep *)malloc(sizeof(struct srep)); } } else { p = (struct srep *)malloc(sizeof(struct srep)); } NXReadType(aStream, "i", (void *)&p->l); NXReadType(aStream, "*", (void *)&p->s); NXReadType(aStream, "i", (void *)&p->n); if (p->n != 1) [self error:"read: problem, ref count not 1"]; NXReadType(aStream, "c", (void *)&yCaseSensitive); return self; } #endif @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.