home *** CD-ROM | disk | FTP | other *** search
- #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
-
-