Annotation of objc/NXPropertyList.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.0 (the 'License').  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License."
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: /*     NXPropertyList.m
        !            25:        Copyright 1991, NeXT, Inc.
        !            26:        Bertrand, August 1991
        !            27: */
        !            28: #ifndef KERNEL
        !            29: #import "NXPropertyList.h"
        !            30: 
        !            31: #import <ctype.h>
        !            32: #import <streams/streams.h>
        !            33: #import <stdio.h>
        !            34: 
        !            35: /********      String extras           ********/
        !            36: 
        !            37: @interface NXMutableString (NX_BS_Extras)
        !            38: //?? SHOULD BE IN NXString, AND EFFICIENT!
        !            39: - (void)appendCharacters:(const unichar *)chars length:(unsigned)length;
        !            40: @end
        !            41: 
        !            42: @implementation NXMutableString (NX_BS_Extras)
        !            43: - (void)appendCharacters:(const unichar *)chars length:(unsigned)length {
        !            44:     NXReadWriteString  *temp = [NXReadOnlyString alloc];
        !            45:     [temp initFromCharactersNoCopy:(unichar *)chars length:length freeWhenDone:NO];
        !            46:     [self append:temp];
        !            47:     [temp free];
        !            48: }
        !            49: @end
        !            50: 
        !            51: @interface Object (NX_BS_Extras)
        !            52: //?? Should be in ObjC
        !            53: // Assumed by ipclib
        !            54: - (void)writeToStream:(NXStream *)stream;
        !            55: @end
        !            56: 
        !            57: @implementation Object (NX_BS_Extras)
        !            58: - (void)writeToStream:(NXStream *)stream {
        !            59:     NXPrintf(stream, "0x%x", self);
        !            60: }
        !            61: @end
        !            62: 
        !            63: /********      Class implementation            ********/
        !            64: 
        !            65: @implementation NXPropertyList
        !            66: 
        !            67: static void freeKeyAndValue(NXMapTable *table, void *key, void *value) {
        !            68:     [(id)key free];
        !            69:     [(id)value free];
        !            70: }
        !            71: 
        !            72: - init {
        !            73:     NXMapTablePrototype        proto = NXObjectMapPrototype;
        !            74:     proto.free = freeKeyAndValue;
        !            75:     table = NXCreateMapTable(proto, 0);
        !            76:     return self;
        !            77: }
        !            78: 
        !            79: - free {
        !            80:     /* we test for table NULL for cases when free is called during initialization */
        !            81:     if (table) NXFreeMapTable(table);
        !            82:     return [super free];
        !            83: }
        !            84: 
        !            85: - (unsigned)count {
        !            86:     return NXCountMapTable(table);
        !            87: }
        !            88: 
        !            89: - (BOOL)member:(NXString *)key {
        !            90:     id value;
        !            91:     return (NXMapMember(table, key, (void **)&value) != NX_MAPNOTAKEY);
        !            92: }
        !            93: 
        !            94: - get:(NXString *)key {
        !            95:     return NXMapGet(table, key);
        !            96: }
        !            97: 
        !            98: - insert:(NXString *)key value:value {
        !            99:     id         oldValue;
        !           100:     void       *oldKey = NXMapMember(table, key, (void **)&oldValue);
        !           101:     if (oldKey == NX_MAPNOTAKEY) {
        !           102:        oldValue = nil;
        !           103:     } else {
        !           104:        (void)NXMapRemove(table, oldKey);
        !           105:        [(id)oldKey free];
        !           106:     }
        !           107:     (void)NXMapInsert(table, [key immutableCopy], value);
        !           108:     return oldValue;
        !           109: }
        !           110: 
        !           111: - remove:(NXString *)key {
        !           112:     id         oldValue;
        !           113:     void       *oldKey = NXMapMember(table, key, (void **)&oldValue);
        !           114:     if (oldKey == NX_MAPNOTAKEY) return nil;
        !           115:     NXMapRemove(table, oldKey);
        !           116:     [(id)oldKey free];
        !           117:     return oldValue;
        !           118: }
        !           119: 
        !           120: - empty {
        !           121:     NXResetMapTable(table);
        !           122:     return self;
        !           123: }
        !           124: 
        !           125: - (NXMapState)initEnumeration {
        !           126:     return NXInitMapState(table);
        !           127: }
        !           128: 
        !           129: - (BOOL)enumerate:(NXMapState *)state key:(NXString **)refKey value:(id *)refValue {
        !           130:     return NXNextMapState(table, state, (void **)refKey, (void **)refValue) != 0;
        !           131: }
        !           132: 
        !           133: @end
        !           134: 
        !           135: /********      Basic ASCII read/write of property lists        ********/
        !           136: 
        !           137: @implementation NXPropertyList (Basic_IO)
        !           138: - initFromStream:(NXStream *)stream {
        !           139:     NXPropertyListReadContext  context = {
        !           140:                        0, [NXReadWriteString new],
        !           141:                        [NXReadOnlyString class],
        !           142:                        [NXReadOnlyString class],
        !           143:                        [NXCleanList class],
        !           144:                        [NXPropertyList class],
        !           145:                        YES,
        !           146:                        [self zone],
        !           147:                        NULL
        !           148:                        };
        !           149:     id new = [self initFromStream:stream context:&context];
        !           150:     [context.buffer free];
        !           151:     if (context.uniquingTable) NXFreeHashTable(context.uniquingTable);
        !           152:     return new;
        !           153: }
        !           154:                        
        !           155: - initFromPath:(NXString *)path {
        !           156:     NXPropertyListReadContext  context = {
        !           157:                        0, [NXReadWriteString new],
        !           158:                        [NXReadOnlyString class],
        !           159:                        [NXReadOnlyString class],
        !           160:                        [NXCleanList class],
        !           161:                        [NXPropertyList class],
        !           162:                        YES,
        !           163:                        [self zone],
        !           164:                        NULL
        !           165:                        };
        !           166:     id new = [self initFromPath:path context:&context];
        !           167:     [context.buffer free];
        !           168:     if (context.uniquingTable) NXFreeHashTable(context.uniquingTable);
        !           169:     return new;
        !           170: }
        !           171: 
        !           172: - (void)writeToStream:(NXStream *)stream {
        !           173:     NXPropertyListWriteContext context = {
        !           174:                        4, 0,
        !           175:                        NO, "\n"
        !           176:                        };
        !           177:     [self writeToStream:stream context:&context];
        !           178: }
        !           179: 
        !           180: - (BOOL)writeToPath:(NXString *)path safely:(BOOL)safe {
        !           181:     char       cpath[MAXPATHLEN];
        !           182:     char       temp[MAXPATHLEN];
        !           183:     NXStream   *stream;
        !           184:     BOOL       ok;
        !           185:     if (! path) return NO;
        !           186:     [path getCString:cpath]; cpath[[path length]] = 0;
        !           187:     stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
        !           188:     strcpy(temp, cpath);
        !           189:     if (safe) strcat(temp, "~");
        !           190:     [self writeToStream:stream];
        !           191:     ok = ! NXSaveToFile(stream, temp);
        !           192:     NXCloseMemory(stream, NX_FREEBUFFER);
        !           193:     if (safe && ok) ok = ! rename(temp, cpath);
        !           194:     return ok;
        !           195: }
        !           196: 
        !           197: - (BOOL)writeToPath:(NXString *)path {
        !           198:     return [self writeToPath:path safely:YES];
        !           199: }
        !           200: 
        !           201: @end
        !           202: 
        !           203: /********      Read/write utilities            ********/
        !           204: 
        !           205: // constants
        !           206: #define BEGIN_PAR      '('
        !           207: #define END_PAR                ')'
        !           208: #define BEGIN_CURLY    '{'
        !           209: #define END_CURLY      '}'
        !           210: 
        !           211: static int NXGetNonSpace(NXStream *stream, int *line) {
        !           212:     int                ch;
        !           213:     while ((ch = NXGetc(stream)) != EOF) {
        !           214:        if (ch == '\n') (*line)++;
        !           215:        if (ch == '/') {
        !           216:            if ((ch = NXGetc(stream)) == '/') {
        !           217:                while ((ch = NXGetc(stream)) != EOF && ch != '\n') {};
        !           218:                if (ch == '\n') (*line)++;
        !           219:            } else if (ch == '*') {
        !           220:                while ((ch = NXGetc(stream)) != EOF) {
        !           221:                    if (ch == '*') {
        !           222:                        ch = NXGetc(stream);
        !           223:                        if (ch == '/') break;
        !           224:                        NXUngetc(stream);
        !           225:                    } else if (ch == '\n') (*line)++;
        !           226:                }
        !           227:            } else {
        !           228:                NXUngetc(stream);
        !           229:                return '/';
        !           230:            }
        !           231:        } else if (! isspace(ch)) return ch;
        !           232:     }
        !           233:     return EOF;
        !           234: }
        !           235: 
        !           236: static inline int isTokenChar(int ch) {
        !           237:     return (isalnum(ch) || ch == '_' || ch == '$' || ch == ':' || ch == '.' || ch == '/') ? 1 : 0;
        !           238: }
        !           239: 
        !           240: static int NXGetSlashedChar(NXStream *stream, int *line) {
        !           241:     int        ch;
        !           242:     switch (ch = NXGetc(stream)) {
        !           243:        case '0':
        !           244:        case '1':       
        !           245:        case '2':       
        !           246:        case '3':       
        !           247:        case '4':       
        !           248:        case '5':       
        !           249:        case '6':       
        !           250:        case '7':  {
        !           251:                        int             num = ch - '0';
        !           252:                        /* three digits maximum to avoid reading \000 followed by 5 as \5 ! */
        !           253:                        if ((ch = NXGetc(stream)) >= '0' && ch <= '7') {
        !           254:                            num = (num << 3) + ch - '0';
        !           255:                            if ((ch = NXGetc(stream)) >= '0' && ch <= '7') {
        !           256:                                num = (num << 3) + ch - '0';
        !           257:                            } else NXUngetc(stream);
        !           258:                        } else NXUngetc(stream);
        !           259:                        return num;
        !           260:                    }
        !           261:        case 'a':       return '\a';
        !           262:        case 'b':       return '\b';
        !           263:        case 'f':       return '\f';
        !           264:        case 'n':       return '\n';
        !           265:        case 'r':       return '\r';
        !           266:        case 't':       return '\t';
        !           267:        case 'v':       return '\v';
        !           268:        case '"':       return '\"';
        !           269:        case '\n':      (*line)++;
        !           270:                        return '\n';
        !           271:     }
        !           272:     return ch;
        !           273: }
        !           274: 
        !           275: static id readValue(NXStream *stream, NXPropertyListReadContext *context) {
        !           276:     int        ch = NXGetNonSpace(stream, &context->line);
        !           277:     if (ch == BEGIN_CURLY || ch == BEGIN_PAR) {
        !           278:        id      factory;
        !           279:        int     endch;
        !           280:        id      value;
        !           281:        if (ch == BEGIN_CURLY) {
        !           282:            factory = context->propertyListValueFactory;
        !           283:            endch = END_CURLY;
        !           284:        } else {
        !           285:            factory = context->listValueFactory;
        !           286:            endch = END_PAR;
        !           287:        }
        !           288:        value = [[factory allocFromZone:context->zone] initFromStream:stream context:context];
        !           289:        if (! value) return nil;
        !           290:        ch = NXGetNonSpace(stream, &context->line);
        !           291:        if (ch != endch) {
        !           292:            [value free];
        !           293:            return nil;
        !           294:        }
        !           295:        return value;
        !           296:     } else {
        !           297:        NXUngetc(stream);
        !           298:        return [[context->stringValueFactory allocFromZone:context->zone] initFromStream:stream context:context];
        !           299:     }
        !           300: }
        !           301: 
        !           302: static void writeSpaces(NXStream *stream, int spaces) {
        !           303:     while (spaces >= 8) {
        !           304:        NXPutc(stream, '\t'); spaces -= 8;
        !           305:     }
        !           306:     while (spaces--) NXPutc(stream, ' ');
        !           307: }
        !           308: 
        !           309: /********      A list that really frees its elements   ********/
        !           310: 
        !           311: @implementation NXCleanList:List
        !           312: - free {
        !           313:     [self freeObjects];
        !           314:     return [super free];
        !           315: }
        !           316: @end
        !           317: 
        !           318: /********      Fancy ASCII read/write of property lists        ********/
        !           319: 
        !           320: @implementation NXPropertyList (Fancy_IO)
        !           321: - initFromStream:(NXStream *)stream context:(NXPropertyListReadContext *)context {
        !           322:     int                ch = NXGetNonSpace(stream, &context->line);
        !           323:     BOOL       ok = YES;
        !           324:     [self init];
        !           325:     while (ok && (ch == '"' || isTokenChar(ch))) {
        !           326:        NXString        *key;
        !           327:        id              value;
        !           328:        NXUngetc(stream);
        !           329:        key = [[context->keyFactory allocFromZone:context->zone] initFromStream:stream context:context];
        !           330:        if (! key) return NO;
        !           331:        ch = NXGetNonSpace(stream, &context->line);
        !           332:        if (ch == '=') {
        !           333:            value = readValue(stream, context);
        !           334:            if (! value) {
        !           335:                printf("*** NXPropertyList: Syntax error line %u\n", context->line);
        !           336:                [self free];
        !           337:                return nil;
        !           338:            }
        !           339:            [self insert:key value:value];
        !           340:            ch = NXGetNonSpace(stream, &context->line);
        !           341:        } else {
        !           342:            [self insert:key value:(context->noValueIsSame) ?  [key immutableCopy] : nil];
        !           343:        }
        !           344:        [key free];
        !           345:        ok = NO;
        !           346:        while (ch == ';') {
        !           347:            ok = YES; ch = NXGetNonSpace(stream, &context->line);
        !           348:        }
        !           349:     }
        !           350:     NXUngetc(stream);
        !           351:     return self;
        !           352: }
        !           353: 
        !           354: - (void)writeToStream:(NXStream *)stream context:(NXPropertyListWriteContext *)context {
        !           355:     NXMapState state = [self initEnumeration];
        !           356:     id         key;
        !           357:     id         value;
        !           358:     NXPropertyListWriteContext original = *context;
        !           359:     unsigned   spaces = context->indent;
        !           360:     if (original.topLevelBrackets) NXPutc(stream, BEGIN_CURLY);
        !           361:     while ([self enumerate:&state key:&key value:&value]) {
        !           362:        context->topLevelBrackets = YES;
        !           363:        context->pairSeparator = original.pairSeparator;
        !           364:        writeSpaces(stream, spaces);
        !           365:        if (key == value) {
        !           366:            [key writeToStream:stream context:context];
        !           367:            NXPrintf(stream, ";");
        !           368:        } else if ([value isKindOf:[NXPropertyList class]]) {
        !           369:            [key writeToStream:stream context:context];
        !           370:            NXPrintf(stream, " = {%s", original.pairSeparator);
        !           371:            context->topLevelBrackets = NO;
        !           372:            context->indent = spaces + context->indentDelta;
        !           373:            [value writeToStream:stream context:context];
        !           374:            writeSpaces(stream, spaces);
        !           375:            NXPrintf(stream, "};");
        !           376:        } else if (value) {
        !           377:            [key writeToStream:stream context:context];
        !           378:            NXPrintf(stream, " = ");
        !           379:            [value writeToStream:stream context:context];
        !           380:            NXPrintf(stream, ";");
        !           381:        }
        !           382:        NXPrintf(stream, "%s", original.pairSeparator);
        !           383:     }
        !           384:     if (original.topLevelBrackets) NXPutc(stream, END_CURLY);
        !           385: }
        !           386: - initFromPath:(NXString *)path context:(NXPropertyListReadContext *)context {
        !           387:     char       cpath[MAXPATHLEN];
        !           388:     NXStream   *stream;
        !           389:     id         new;
        !           390:     if (! path) goto nope;
        !           391:     [path getCString:cpath]; cpath[[path length]] = 0;
        !           392:     stream = NXMapFile(cpath, NX_READONLY);
        !           393:     if (! stream) goto nope;
        !           394:     new = [self initFromStream:stream context:context];
        !           395:     if (NXGetc(stream) != EOF) {
        !           396:        char    cpath[MAXPATHLEN];
        !           397:        [path getCString:cpath];
        !           398:        printf("NXPropertyList: discarded input at line %u of file %s\n", context->line, cpath);
        !           399:     }
        !           400:     NXCloseMemory(stream, NX_FREEBUFFER);
        !           401:     return new;
        !           402:   nope:
        !           403:     [self free];
        !           404:     return nil;
        !           405: }
        !           406: 
        !           407: @end
        !           408: 
        !           409: @implementation NXCleanList (Fancy_IO)
        !           410: - initFromStream:(NXStream *)stream context:(NXPropertyListReadContext *)context {
        !           411:     BOOL       ok = YES;
        !           412:     int                ch = NXGetNonSpace(stream, &context->line);
        !           413:     while (ok && (ch == '"' || isTokenChar(ch) || ch == BEGIN_CURLY || ch == BEGIN_PAR)) {
        !           414:        id      value;
        !           415:        NXUngetc(stream);
        !           416:        value = readValue(stream, context);
        !           417:        if (! value) {
        !           418:            printf("*** NXCleanList: Syntax error line %u\n", context->line);
        !           419:            [self free]; 
        !           420:            return nil;
        !           421:        }
        !           422:        [self addObject:value];
        !           423:        ch = NXGetNonSpace(stream, &context->line);
        !           424:        ok = NO;
        !           425:        while (ch == ',') {
        !           426:            ok = YES; ch = NXGetNonSpace(stream, &context->line);
        !           427:        }
        !           428:     }
        !           429:     NXUngetc(stream);
        !           430:     return self;
        !           431: }
        !           432: 
        !           433: 
        !           434: - (void)writeToStream:(NXStream *)stream context:(NXPropertyListWriteContext *)context {
        !           435:     unsigned   index = 0;
        !           436:     unsigned   count = [self count];
        !           437:     BOOL       top = context->topLevelBrackets;
        !           438:     if (top) NXPutc(stream, BEGIN_PAR);
        !           439:     while (index < count) {
        !           440:        context->topLevelBrackets = YES;
        !           441:        context->pairSeparator = "";
        !           442:        context->indent = 0;
        !           443:        [[self objectAt:index] writeToStream:stream context:context];
        !           444:        if (index != count-1) NXPrintf(stream, ", ");
        !           445:        index++;
        !           446:     }
        !           447:     if (top) NXPutc(stream, END_PAR);
        !           448: }
        !           449: 
        !           450: @end
        !           451: 
        !           452: @implementation NXString (Fancy_IO)
        !           453: 
        !           454: #define MAX_TOKEN      1024
        !           455: 
        !           456: static inline void append1(NXMutableString *buffer, BOOL *bufferUsed, int ch, unichar *buf, unsigned *buflen) {
        !           457:     if (*buflen == MAX_TOKEN) {
        !           458:        if (! *bufferUsed) [buffer replaceWith:@""];
        !           459:        *bufferUsed = YES;
        !           460:        [buffer appendCharacters:buf length:MAX_TOKEN];
        !           461:        *buflen = 0;
        !           462:     }
        !           463:     buf[(*buflen)++] = ch;
        !           464: }
        !           465: 
        !           466: static inline NXString *init(NXString *self, NXMutableString *buffer, BOOL bufferUsed, unichar *buf, unsigned *buflen) {
        !           467:     if (bufferUsed) {
        !           468:        [buffer appendCharacters:buf length:*buflen];
        !           469:        return [self initFromString:buffer];
        !           470:     }
        !           471:     return [self initFromCharacters:buf length:*buflen];
        !           472: }
        !           473: 
        !           474: - initFromStream:(NXStream *)stream context:(NXPropertyListReadContext *)context {
        !           475:     int                ch = NXGetNonSpace(stream, &context->line);
        !           476:     if (ch == '"') {
        !           477:        BOOL            bufferUsed = NO;
        !           478:        unichar         buf[MAX_TOKEN];
        !           479:        unsigned        buflen = 0;
        !           480:        while (((ch = NXGetc(stream)) != EOF) && (ch != '"')) {
        !           481:            if (ch == '\n') (context->line)++;
        !           482:            if (ch == '\\') ch = NXGetSlashedChar(stream, &context->line);
        !           483:            append1(context->buffer, &bufferUsed, ch, buf, &buflen);
        !           484:        }
        !           485:        if (ch == EOF) {
        !           486:            [self free];
        !           487:            return nil;
        !           488:        }
        !           489:        return init(self, context->buffer, bufferUsed, buf, &buflen);
        !           490:     } else if (isTokenChar(ch)) {
        !           491:        BOOL            bufferUsed = NO;
        !           492:        unichar         buf[MAX_TOKEN];
        !           493:        unsigned        buflen = 0;
        !           494:        append1(context->buffer, &bufferUsed, ch, buf, &buflen);
        !           495:        while (((ch = NXGetc(stream)) != EOF) && isTokenChar(ch)) {
        !           496:            append1(context->buffer, &bufferUsed, ch, buf, &buflen);
        !           497:        }
        !           498:        NXUngetc(stream);
        !           499:        return init(self, context->buffer, bufferUsed, buf, &buflen);
        !           500:     } else {
        !           501:        NXUngetc(stream);
        !           502:        [self free];
        !           503:        return nil;
        !           504:     }
        !           505: }
        !           506: 
        !           507: - (void)writeToStream:(NXStream *)stream context:(NXPropertyListWriteContext *)context {
        !           508:     unsigned   index = 0;
        !           509:     unsigned   count = [self length];
        !           510:     BOOL       token = (count != 0);
        !           511:     while (index < count) {
        !           512:        int     ch = [self characterAt:index];
        !           513:        if (! isTokenChar(ch)) { token = NO; break; }
        !           514:        index ++;
        !           515:     }
        !           516:     if (token) {
        !           517:        NXPrintf(stream, "%@", self);
        !           518:     } else {
        !           519:        NXPutc(stream, '"');
        !           520:        index = 0;
        !           521:        while (index < count) {
        !           522:            int ch = [self characterAt:index];
        !           523:            int ch1 = '\\', ch2 = 0;
        !           524:            switch (ch) {
        !           525:                case '\\':      ch2 = ch; break;
        !           526:                case '"':       ch2 = ch; break;
        !           527:                case '\a':      ch2 = 'a'; break;
        !           528:                case '\b':      ch2 = 'b'; break;
        !           529:                case '\f':      ch2 = 'f'; break;
        !           530:                case '\n':      ch2 = 'n'; break;
        !           531:                case '\t':      ch2 = 't'; break;
        !           532:                case '\v':      ch2 = 'v'; break;
        !           533:                default:
        !           534:                    if (ch >= ' ' && ch <= '~') {
        !           535:                        ch1 = ch;
        !           536:                    } else {
        !           537:                        /* attention here: if the next character is a number, we need to avoid \0 followed by 5 that would become \05.  We do that by printing 3 digits */
        !           538:                        NXPrintf(stream, "\\%+03o", ch);
        !           539:                        ch1 = 0;
        !           540:                    }
        !           541:            }
        !           542:            if (ch1) {
        !           543:                NXPutc(stream, ch1);
        !           544:                if (ch2) NXPutc(stream, ch2);
        !           545:            }
        !           546:            index ++;
        !           547:        }
        !           548:        NXPutc(stream, '"');
        !           549:     }
        !           550: }
        !           551: 
        !           552: @end
        !           553: 
        !           554: @implementation NXReadOnlyString (Fancy_IO)
        !           555:     // Only this class tries uniquing the strings
        !           556: static unsigned hashString(const void *info, const void *data) {
        !           557:     return [(NXString *)data hash];
        !           558: }
        !           559: static int isEqualString(const void *info, const void *data1, const void *data2) {
        !           560:     return [(NXString *)data1 isEqual:(NXString *)data2];
        !           561: }
        !           562: static void freeString(const void *info, const void *data) {
        !           563:     [(NXString *)data free];
        !           564: }
        !           565: 
        !           566: - initFromStream:(NXStream *)stream context:(NXPropertyListReadContext *)context {
        !           567:     NXString   *new = [super initFromStream:stream context:context];
        !           568:     NXString   *original;
        !           569:     if (! new) return new;
        !           570:     if (! context->uniquingTable) {
        !           571:        NXHashTablePrototype stringSetProto = {hashString, isEqualString, freeString, 0};
        !           572:        context->uniquingTable = NXCreateHashTable(stringSetProto, 0, 0);
        !           573:     }
        !           574:     original = NXHashGet(context->uniquingTable, new);
        !           575:     if (! original) {
        !           576:        NXHashInsert(context->uniquingTable, [new immutableCopy]);
        !           577:        return new;
        !           578:     } else {
        !           579:        [new free];
        !           580:        return [original immutableCopy];
        !           581:     }
        !           582: }
        !           583: @end
        !           584: 
        !           585: @implementation Object (Fancy_IO)
        !           586: - (void)writeToStream:(NXStream *)stream context:(NXPropertyListWriteContext *)context {
        !           587:     [self writeToStream:stream];
        !           588: }
        !           589: @end
        !           590: 
        !           591: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.