Annotation of objc/NXBundle.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: /*     NXBundle.m
        !            25:        Copyright 1990, 1991, NeXT, Inc.
        !            26:        IPC, November 1990
        !            27: */
        !            28: 
        !            29: #ifndef KERNEL
        !            30: #ifdef SHLIB
        !            31: #import "shlib.h"
        !            32: #endif SHLIB
        !            33: 
        !            34: 
        !            35: #import "NXBundle.h"
        !            36: #import "NXBundlePrivate.h"
        !            37: #import "maptable.h"
        !            38: #import "NXStringTable.h"
        !            39: #import "objc-load.h"
        !            40: #import "hashtable.h"
        !            41: #import "objc-private.h"
        !            42: 
        !            43: #import <sys/file.h>
        !            44: #import <sys/dir.h>
        !            45: #import <sys/stat.h>
        !            46: #import <sys/types.h>
        !            47: 
        !            48: #import <strings.h>
        !            49: 
        !            50: static void warning(const char *format, ...) {}
        !            51: 
        !            52: /* For the LProj cache */
        !            53: static id bundleTable = nil;
        !            54: static id mainBundleStringTableTable = nil;
        !            55: 
        !            56: #define BUNDLE_SUFFIX  "bundle"
        !            57: 
        !            58: /*******       Bundle          ********/
        !            59: 
        !            60: @implementation NXBundle
        !            61: 
        !            62: static NXMapTable *classToBundle = NULL;
        !            63: 
        !            64: static NXBundle *mainBundle = nil;
        !            65: static NXMapTable *pathToBundle = NULL;
        !            66: 
        !            67: - initForDirectory:(const char *)bp {
        !            68:     struct stat statInfo;
        !            69:     id bb;
        !            70:     
        !            71:     if (! pathToBundle) pathToBundle = NXCreateMapTable(NXStrValueMapPrototype, 1);
        !            72:     bb = NXMapGet(pathToBundle, bp);
        !            73:     if (bb) {
        !            74:        [self free];
        !            75:        return bb;
        !            76:     } else {
        !            77:        BOOL allOK = YES;
        !            78:        
        !            79:        if (stat(bp, &statInfo) == 0) {
        !            80:            while (allOK && (statInfo.st_mode & S_IFLNK)) {
        !            81:                char linkPath[MAXPATHLEN + 1];
        !            82:                
        !            83:                allOK = ((readlink(bp, linkPath, sizeof(linkPath)) != -1)
        !            84:                         && (stat(linkPath, &statInfo) == 0));
        !            85:            }
        !            86:            allOK = allOK
        !            87:                    && ((statInfo.st_mode & (S_IFDIR | S_IREAD | S_IEXEC))
        !            88:                        ? YES : NO);
        !            89:        }
        !            90:        if (allOK) {
        !            91:            _directory = NXCopyStringBuffer(bp);
        !            92:            _codeLoaded = NO;
        !            93:            NXMapInsert(pathToBundle, _directory, self);
        !            94:            return self;
        !            95:        } else {
        !            96:            [self free];
        !            97:            return nil;
        !            98:        }
        !            99:     }
        !           100: }
        !           101: 
        !           102: - free
        !           103: {
        !           104:     if (_codeLoaded)
        !           105:        return self;
        !           106:     else {
        !           107:        NXMapRemove(pathToBundle, _directory);
        !           108:        free(_directory);
        !           109:        return [super free];
        !           110:     }
        !           111: }
        !           112: 
        !           113: + mainBundle {
        !           114:     if (! mainBundle) {
        !           115:        char    prog[MAXPATHLEN];
        !           116:        char    *last;
        !           117:        char    **argv;
        !           118: #if defined(__DYNAMIC__)
        !           119:         extern char ***_NSGetArgv();
        !           120:         argv = *_NSGetArgv();
        !           121: #else
        !           122:                extern char **NXArgv;
        !           123:         argv = NXArgv;
        !           124: #endif
        !           125:         if (argv[0][0] != '/') { getwd(prog); strcat(prog, "/"); }
        !           126:        else prog[0] = 0;
        !           127:        strcat(prog, argv[0]);
        !           128:        last = rindex(prog, '/');
        !           129:        last[0] = 0;
        !           130:        mainBundle = [[self alloc] initForDirectory: prog];
        !           131:        mainBundle->_codeLoaded = YES;
        !           132:     }
        !           133:     return mainBundle;
        !           134: }
        !           135: 
        !           136: + bundleForClass:class {
        !           137:     id bundle;
        !           138:     if (! classToBundle) return [self mainBundle];
        !           139:     bundle = NXMapGet(classToBundle, class);
        !           140:     return (bundle) ? bundle : [self mainBundle];
        !           141: }
        !           142:     
        !           143: - (const char *)directory {
        !           144:     return _directory;
        !           145: }
        !           146: 
        !           147: static Class globalPrincipalClass = NULL;
        !           148: static id globalBundle = nil;
        !           149: 
        !           150: static void loadCallback(Class cls, Category cat ) {
        !           151:     warning("Loading %s '%s'\n", (cat) ? "category of" : "class", cls->name);
        !           152:     if (cat) return;
        !           153:     if (! classToBundle) classToBundle = NXCreateMapTable(NXPtrValueMapPrototype, 1);
        !           154:     NXMapInsert(classToBundle, cls, globalBundle);
        !           155:     if (! globalPrincipalClass) globalPrincipalClass = cls;
        !           156: }
        !           157: 
        !           158: static NXStream* bundleErrorStream = 0;
        !           159: 
        !           160: + (NXStream*) setErrorStream:(NXStream*)stream
        !           161: {
        !           162:   NXStream* s = bundleErrorStream;
        !           163:   bundleErrorStream = stream;
        !           164:   return s;
        !           165: }
        !           166: 
        !           167: - (BOOL)ensureLoaded {
        !           168:     if (! _codeLoaded) {
        !           169:        char            name[MAXPATHLEN];
        !           170:        char            path[MAXPATHLEN];
        !           171:        char            *moduleList[2] = {path, NULL};
        !           172:        NXStream        *errorStream;
        !           173:        long            err;
        !           174:        char            *slash, *dot;
        !           175: 
        !           176:        globalPrincipalClass = NULL;
        !           177:        globalBundle = self;
        !           178:        slash = rindex(_directory, '/');
        !           179:        if (slash) {
        !           180:            strcpy(name, slash + 1);
        !           181:        } else {
        !           182:            strcpy(name, _directory);
        !           183:        }
        !           184:        dot = rindex(name, '.');
        !           185:        if (dot)
        !           186:            *dot = '\0';
        !           187:        if ([self getPath: path forResource: name ofType: NULL]) {
        !           188:            errorStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
        !           189: 
        !           190:            err = objc_loadModules(moduleList, errorStream, loadCallback,
        !           191:                                    NULL, NULL);
        !           192:            if (err) {
        !           193:                char *streamBuf;
        !           194:                int len, maxLen;
        !           195:                
        !           196:                NXGetMemoryBuffer(errorStream, &streamBuf, &len, &maxLen);
        !           197:                if (!bundleErrorStream)
        !           198:                  {
        !           199:                    _NXLogError("Error loading %s", path);
        !           200:                    if (len) {
        !           201:                      streamBuf[len] = 0;
        !           202:                      _NXLogError(streamBuf);
        !           203:                    }   
        !           204:                    _NXLogError("\n");
        !           205:                  }
        !           206:                else
        !           207:                  {
        !           208:                    NXPrintf (bundleErrorStream, "Error loading %s", path);
        !           209:                    if (len) {
        !           210:                      streamBuf[len] = 0;
        !           211:                      NXPrintf (bundleErrorStream, streamBuf);
        !           212:                    }
        !           213:                    NXPrintf (bundleErrorStream, "\n");
        !           214:                  }
        !           215:            } else {
        !           216:                _principalClass = globalPrincipalClass;
        !           217:                _codeLoaded = YES;
        !           218:            }
        !           219:            NXCloseMemory(errorStream, NX_FREEBUFFER|NX_TRUNCATEBUFFER);
        !           220:            if (err) return NO;
        !           221:        } else {
        !           222:          if (! bundleErrorStream)
        !           223:            _NXLogError("Couldn't find %s in bundle for %s", name, _directory);
        !           224:          else
        !           225:            NXPrintf (bundleErrorStream,
        !           226:                      "Couldn't find %s in bundle for %s", name, _directory);
        !           227:          return NO;
        !           228:        }
        !           229:          
        !           230:     }
        !           231:     return YES;
        !           232: }
        !           233: 
        !           234: - classNamed:(const char *)className {
        !           235:     if (![self ensureLoaded]) return nil;
        !           236:     return objc_getClass((char *)className); 
        !           237: }
        !           238: 
        !           239: - principalClass {
        !           240:     if (![self ensureLoaded]) return nil;
        !           241:     return (id)_principalClass;
        !           242: }
        !           243: 
        !           244: - setVersion:(int)version {
        !           245:     _bundleVersion = version;
        !           246:     return self;
        !           247: }
        !           248: 
        !           249: - (int)version {
        !           250:     return _bundleVersion;
        !           251: }
        !           252: 
        !           253: /*******       International Routines          ********/
        !           254: 
        !           255: static BOOL systemHasLanguages = YES;
        !           256: static const char *const *systemLanguages = NULL;
        !           257: 
        !           258: static const char *const *getDefaultSystemLanguages(void) {
        !           259:     int count, length;
        !           260:     const char *language, *separator;
        !           261:     char **defaultSystemLanguages = NULL;
        !           262: 
        !           263:     if (systemHasLanguages) {
        !           264:        language = "English";
        !           265:        if (language && *language) {
        !           266:            count = 1;
        !           267:            separator = strchr(language, ';');
        !           268:            while (separator) {
        !           269:                count++;
        !           270:                separator = strchr(separator+1, ';');
        !           271:            }
        !           272:            defaultSystemLanguages = malloc((count + 1) * sizeof(char *));
        !           273:            defaultSystemLanguages[count] = NULL;
        !           274:            for (count = 0; language; count++) {
        !           275:                separator = strchr(language, ';');
        !           276:                if (separator) {
        !           277:                    length = separator - language;
        !           278:                    separator++;
        !           279:                } else {
        !           280:                    length = strlen(language);
        !           281:                }
        !           282:                while (*language == ' ' || *language == '\t') {
        !           283:                    language++; length--;
        !           284:                }
        !           285:                while (language[length-1] == ' ' || language[length-1] == '\t') length--;
        !           286:                defaultSystemLanguages[count] = malloc((length + 1) * sizeof(char));
        !           287:                strncpy(defaultSystemLanguages[count], language, length);
        !           288:                defaultSystemLanguages[count][length] = '\0';
        !           289:                language = separator;
        !           290:            }
        !           291:        } else {
        !           292:            systemHasLanguages = NO;
        !           293:        }
        !           294:     }
        !           295: 
        !           296:     return defaultSystemLanguages;
        !           297: }
        !           298: 
        !           299: #ifdef DEBUG
        !           300: static int ACCESS(const char *path, int way)
        !           301: {
        !           302:     int retval = access(path, way);
        !           303:     printf("access(%s, R_OK) returns %d\n", path, retval);
        !           304:     return retval;
        !           305: }
        !           306: #else
        !           307: #define ACCESS access
        !           308: #endif
        !           309: 
        !           310: #define LINE_BUFFER_SIZE 256
        !           311: 
        !           312: /* The passed-in path is the .lproj directory to look in for the version.  It's not clear what the best way to encode a version into an .lproj directory, but this is probably as good as any...it parses through a file named "version" (if found) looking for an integer value starting a line.  If it finds one, that's the version.  If no version file exists in the .lproj directory, then its version is 0. */
        !           313:  
        !           314: static int readLprojVersion(char *path) {
        !           315:     FILE *file;
        !           316:     int version = 0;
        !           317:     int pathLength = strlen(path);
        !           318: 
        !           319:     strcat(path, "/version");
        !           320:     file = fopen(path, "r");
        !           321:     if (file) {
        !           322:        char *eof;
        !           323:        char lineBuffer[LINE_BUFFER_SIZE+1];
        !           324:        *lineBuffer = '\0';
        !           325:        do {
        !           326:            eof = fgets(lineBuffer, LINE_BUFFER_SIZE, file);
        !           327:            version = atoi(lineBuffer);
        !           328:        } while (!eof && !version);
        !           329:     }
        !           330:     path[pathLength] = '\0';
        !           331:     fclose(file);
        !           332: 
        !           333:     return version;
        !           334: }
        !           335: 
        !           336: /* Adds the passed extension to the passed name iff the extension is not already on that name. */
        !           337: 
        !           338: static void addExtension(char *name, const char *extension)
        !           339: {
        !           340:     if (extension) {
        !           341:        const char *existingExtension = strrchr(name, '.');
        !           342:        if (existingExtension && extension[0] != '.') existingExtension++;
        !           343:        if (!existingExtension || strcmp(existingExtension, extension)) {
        !           344:            if (extension[0] != '.' && extension[0]) strcat(name, ".");
        !           345:            strcat(name, extension);
        !           346:        }
        !           347:     }
        !           348: }
        !           349: 
        !           350: /* This function takes a string and does a readdir() on the passed directory and adds the names of all the files in the directory to that string.  Returns a potentially newly realloc()'ed version of the string. */
        !           351: 
        !           352: static char *addDirectoryEntriesTo(char *files, const char *directory)
        !           353: {
        !           354:     DIR *dirp;
        !           355:     struct direct *dp;
        !           356:     int length;
        !           357: 
        !           358:     length = strlen(files);
        !           359:     if ((dirp = opendir(directory))) {
        !           360:        dp = readdir(dirp); /* Skip . */
        !           361:        dp = readdir(dirp); /* Skip .. */
        !           362:        for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
        !           363:            files = realloc(files, length + dp->d_namlen + 2);
        !           364:            strncpy(files + length, dp->d_name, dp->d_namlen);
        !           365:            length += dp->d_namlen;
        !           366:            files[length++] = '/';
        !           367:        }
        !           368:        files[length] = '\0';
        !           369:        closedir(dirp);
        !           370:     }
        !           371: 
        !           372:     return files;
        !           373: }
        !           374: 
        !           375: /* There's a little bit of an efficiency hack in this function.  The NXMapTable lprojTable is a map table with keys and values both null-terminated strings.  The keys are the path up to and including the .lproj directory.  The value is of the form "version/file1/file2/file3/file4".  atoi() is used to suck the version out of the front. */
        !           376: 
        !           377: static BOOL isFileInValidLproj(char *path, const char *name, const char *extension, int bundleVersion)
        !           378: {
        !           379:     char *lprojInfo, *slash;
        !           380:     int length, version = -1;
        !           381:     char buffer[MAXPATHLEN+1];
        !           382:     static NXMapTable *lprojTable = NULL;
        !           383: 
        !           384:     if (!lprojTable) lprojTable = NXCreateMapTable(NXStrValueMapPrototype, 0);
        !           385: 
        !           386:     lprojInfo = NXMapGet(lprojTable, path);
        !           387: 
        !           388:     if (!lprojInfo) {
        !           389:        if (ACCESS(path, R_OK) >= 0) version = readLprojVersion(path);
        !           390:        sprintf(buffer, "%d/", version);
        !           391:        lprojInfo = NXCopyStringBuffer(buffer);
        !           392:        lprojInfo = addDirectoryEntriesTo(lprojInfo, path);
        !           393:        NXMapInsert(lprojTable, NXCopyStringBuffer(path), lprojInfo);
        !           394:     } else {
        !           395:        version = atoi(lprojInfo);
        !           396:     }
        !           397: 
        !           398:     if (version == bundleVersion && (lprojInfo = strchr(lprojInfo, '/'))) {
        !           399:        strcpy(buffer, name);
        !           400:         slash = buffer;
        !           401:        while (*slash == '/') slash++;
        !           402:        if ((slash = strchr(buffer, '/'))) {
        !           403:            *(slash+1) = '\0';
        !           404:        } else {
        !           405:            addExtension(buffer, extension);
        !           406:            strcat(buffer, "/");
        !           407:        }
        !           408:        length = strlen(buffer);
        !           409:        while (*++lprojInfo) {
        !           410:            if (!strncmp(lprojInfo, buffer, length)) {
        !           411:                if (path[strlen(path)-1] != '/') strcat(path, "/");
        !           412:                strcat(path, name);
        !           413:                addExtension(path, extension);
        !           414:                return slash ? (ACCESS(path, R_OK) >= 0) : YES;
        !           415:            }
        !           416:            lprojInfo = strchr(lprojInfo, '/');
        !           417:            if (!lprojInfo) return NO;  /* should never happen */
        !           418:        }
        !           419:     }
        !           420: 
        !           421:     return NO;
        !           422: }
        !           423: 
        !           424: /* Returns a path to the appropriate shadow .lproj in /NextLibrary/Languages. */
        !           425: 
        !           426: static BOOL getPathToNextLibraryLanguages(char *path, const char *realPath, const char *language)
        !           427: {
        !           428:     const char *s, *t;
        !           429:     char scratch[ MAXPATHLEN+1 ];
        !           430: 
        !           431:     s = strchr(realPath, '.');
        !           432:     while (s) {
        !           433:        if (!strncmp(s, ".app", 4)) {
        !           434:            char *p;
        !           435:            strcpy(scratch, realPath);
        !           436:            p = scratch + (s - realPath);
        !           437:            t = p+4;
        !           438:            if (*t == '/') t++;
        !           439:            *p = '\0';
        !           440:            s = strrchr(scratch, '/');
        !           441:            if (s) {
        !           442:                if (*t) {
        !           443:                    sprintf(path, "/NextLibrary/Languages/%s%s.lproj/%s", language, s, t);
        !           444:                } else {
        !           445:                    sprintf(path, "/NextLibrary/Languages/%s%s.lproj", language, s);
        !           446:                }
        !           447:            }
        !           448:            return YES;
        !           449:        } else {
        !           450:            s = strchr(s+1, '.');
        !           451:        }
        !           452:     }
        !           453:     if (!s && !strncmp(realPath, "/usr/lib/", 9)) {
        !           454:        s = realPath+8;
        !           455:        while (*s == '/') s++;
        !           456:        if (*s) {
        !           457:            s = strchr(s, '/');
        !           458:            if (s) {
        !           459:                char *tmp;
        !           460:                
        !           461:                strcpy(scratch, realPath);
        !           462:                tmp = scratch + (s - realPath);
        !           463:                *tmp++ = '\0';
        !           464:                s = tmp;
        !           465:            }
        !           466:            if (s && *s) {
        !           467:                sprintf(path, "/NextLibrary/Languages/%s%s.lproj/%s", language, scratch+8, s);
        !           468:            } else {
        !           469:                sprintf(path, "/NextLibrary/Languages/%s%s.lproj", language, realPath+8);
        !           470:            }
        !           471:            return YES;
        !           472:        }
        !           473:     }
        !           474: 
        !           475:     return NO;
        !           476: }
        !           477: 
        !           478: + (BOOL)getPath:(char *)path forResource:(const char *)name
        !           479:          ofType:(const char *)ext inDirectory: (const char *)bundlePath
        !           480:     withVersion: (int)version
        !           481: {
        !           482:     const char         *const *cur;
        !           483:     char               searchPath[MAXPATHLEN+1];
        !           484: 
        !           485:     if (!name) return NO;
        !           486:     if (!path) path = searchPath;
        !           487: 
        !           488:     if (!systemLanguages) systemLanguages = getDefaultSystemLanguages();
        !           489: 
        !           490:     if (systemLanguages) {
        !           491:        for (cur = systemLanguages; *cur; cur++) {
        !           492:            /* First look for a language in the bundle. */
        !           493:            if (bundlePath) {
        !           494:                sprintf(path, "%s/%s.lproj", bundlePath, *cur);
        !           495:                if (isFileInValidLproj(path, name, ext, version)) return YES;
        !           496:            }
        !           497:            /* Then look in /NextLibrary/Languages. */
        !           498:            if (getPathToNextLibraryLanguages(path, bundlePath, *cur)) {
        !           499:                if (isFileInValidLproj(path, name, ext, version)) return YES;
        !           500:            }
        !           501:        }
        !           502:     }
        !           503: 
        !           504:     sprintf(path, "%s", bundlePath);
        !           505:     if (isFileInValidLproj(path, name, ext, version)) return YES;
        !           506: 
        !           507:     return NO;
        !           508: }
        !           509: 
        !           510: -(BOOL)getPath: (char *)path forResource: (const char *)name
        !           511:         ofType: (const char *)ext
        !           512: {
        !           513:     return [[self class] getPath: path forResource: name ofType: ext
        !           514:                      inDirectory: _directory withVersion: _bundleVersion];
        !           515: }
        !           516: 
        !           517: + setSystemLanguages:(const char *const *)languageList {
        !           518:     systemLanguages = languageList;
        !           519:     if (!languageList) systemHasLanguages = YES;
        !           520:     return self;
        !           521: }
        !           522: 
        !           523: @end
        !           524: 
        !           525: const char *NXLoadLocalizedStringFromTableInBundle(const char *table, NXBundle *bundle, const char *key, const char *value)
        !           526: {
        !           527:     static NXZone *LocalizedStringZone = NULL;
        !           528: 
        !           529:     #define LSZONE (LocalizedStringZone ? LocalizedStringZone : (LocalizedStringZone = NXDefaultMallocZone()))
        !           530: 
        !           531:     const char *tableValue;
        !           532:     id stringTable, stringTableTable;
        !           533:     char path[MAXPATHLEN + 1];
        !           534: 
        !           535:     if (!key) return value ? value : "";
        !           536:     if (!bundle) bundle = [NXBundle mainBundle];
        !           537:     if (!table) table = "Localizable";
        !           538: 
        !           539:     if (bundle != [NXBundle mainBundle]) {
        !           540:        stringTableTable = [bundleTable valueForKey:bundle];
        !           541:     } else {
        !           542:        stringTableTable = mainBundleStringTableTable;
        !           543:     }
        !           544: 
        !           545:     if (!(stringTable = [stringTableTable valueForKey:table])) {
        !           546:        [bundle getPath:path forResource:table ofType:"strings"];
        !           547:        stringTable = [NXStringTable newFromFile: path];
        !           548:        if (!stringTableTable) {
        !           549:            if (bundle != [NXBundle mainBundle]) {
        !           550:                if (!bundleTable) bundleTable = [[HashTable allocFromZone:LSZONE] initKeyDesc:"!"];
        !           551:                if (bundleTable) {
        !           552:                    stringTableTable = [[HashTable allocFromZone:LSZONE] initKeyDesc:"*"];
        !           553:                    if (stringTableTable) [bundleTable insertKey:bundle value:stringTableTable];
        !           554:                }
        !           555:            } else {
        !           556:                mainBundleStringTableTable = stringTableTable = [[HashTable allocFromZone:LSZONE] initKeyDesc:"*"];
        !           557:            }
        !           558:        }
        !           559:        if (stringTableTable && !stringTable) stringTable = [[NXStringTable allocFromZone:LSZONE] init];
        !           560:        if (stringTable) [stringTableTable insertKey:table value:stringTable];
        !           561:     }
        !           562: 
        !           563:     if (!(tableValue = [stringTable valueForStringKey:key])) {
        !           564:        tableValue = value ? value : key;
        !           565:        [stringTable insertKey:key value:(void *)tableValue];
        !           566:     }
        !           567: 
        !           568:     return tableValue;
        !           569: }
        !           570: const char *NXLoadLocalStringFromTableInBundle(const char *table, NXBundle *bundle, const char *key, const char *value)
        !           571: {
        !           572:   return NXLoadLocalizedStringFromTableInBundle(table, bundle, key, value);
        !           573: }
        !           574: @implementation NXBundle (Compatability)
        !           575: 
        !           576: - initForPath: (const char *)path { return [self initForDirectory: path]; }
        !           577: - (const char *)path { return [self directory]; }
        !           578: + forClass: class { return [self bundleForClass: class]; }
        !           579: + newFromPath:(const char *)bp { return [[self alloc] initForPath: bp]; }
        !           580: - initFromPath:(const char *)bp { return [self initForPath: bp]; }
        !           581: - (const char *)bundlePath { return [self path]; }
        !           582: - (BOOL)codeLoaded { return _codeLoaded; }
        !           583: - firstClass { return [self principalClass]; }
        !           584: - (BOOL)getResourcePath:(char *)path forName:(const char *)name type:(const char *)ext { return [self getPath: path forResource: name ofType: ext]; }
        !           585: - getClass: (const char *)className { return [self classNamed: className]; }
        !           586: - classForName: (const char *)className { return [self classNamed: className]; }
        !           587: 
        !           588: @end
        !           589: 
        !           590: @implementation NXBundle (Private)
        !           591: 
        !           592: static void noFree(void *ptr) {}
        !           593: static void freeObjects(void *ptr)
        !           594: {
        !           595:     [(HashTable *)ptr freeObjects];
        !           596:     [(HashTable *)ptr free];
        !           597: }
        !           598: 
        !           599: + (void)_invalidateLprojCache
        !           600: {
        !           601:     if (bundleTable) {
        !           602:        [bundleTable freeKeys: noFree values: freeObjects];
        !           603:        [bundleTable free];
        !           604:        bundleTable = nil;
        !           605:     }
        !           606:     if (mainBundleStringTableTable) {
        !           607:        [mainBundleStringTableTable freeObjects];
        !           608:        [mainBundleStringTableTable free];
        !           609:        mainBundleStringTableTable = nil;
        !           610:     }
        !           611: }
        !           612: 
        !           613: @end
        !           614: #endif

unix.superglobalmegacorp.com

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