This is IExternalD.m in view mode; [Download] [Up]
#import "IExternalD.h" #import <c.h> #import <libc.h> #import <sys/types.h> #import <sys/stat.h> #import <sys/dir.h> #import <ctype.h> #import <streams/streams.h> #import <objc/hashtable.h> #import <appkit/Panel.h> #import "data_types.h" #import "IExternalTable.h" #import "ILocalFileD.h" #import "INewsD.h" #import "InfoD.h" #import "ITextD.h" #import "IMediaD.h" #import "IBinaryD.h" #import "IMMEditor.h" #import "IMediaTable.h" #import "Localization.h" #import "errdebug.h" // IExternalD links an object to its external representations. Currently, the // external representation is either a file on the local disk or an article on // the NNTP server. In the future a file on an anonymous ftp server can also // be an external representation of an object. The local disk and the NNTP // server are considered to be distinct domains. The link for an object in a // domain is the name of the external representation for that object in the // domain. For the file on the local disk the link is the path name of the // file. For an article on the NNTP server the link is the message-id of the // article. An object is allowed to more than one external representation. It // may have a representation on the disk and a representation on the NNTP // server. However, in this implementation only one link is allowed per // domain. This is logically incorrect and should be fixed. IGraphicImage // objects and IEditor objects reference external representations of media // objects and articles through an IExternalD object. IExternalD also // maintains a reference count to manage freeing. If there is more than one // domain the last referenced domain is considered the current domain. Since // some methods (due to the way this software has evolved) will not allow you // to specify the domain it is very important to set the current domain first. // IExternalD exists only when they are referenced by a IGraphicImage or a // IMMEditor object. Further, at any time one of the following is true: // Only the IExternalD exists for an object. // The IExternalD and the object exists. // The IExternalD, the object and a viewer/editor for the object exists. @implementation IExternalD static NXAtom fileExtension; static NXImage *image; static NXImage *icon; static List *externalsList; // list of all IExternalD's + initialize { fileExtension = NXUniqueStringNoCopy("external"); image = [[NXImage alloc] initFromSection:"multi_icon.tiff"]; externalsList = [[List allocFromZone:[self zone]] init]; return(self); } + (NXAtom)fileExtension { return(fileExtension); } + setIcon:(NXImage *)theIcon { icon = theIcon; return(self); } + (NXAtom)pasteboardType { return(NULL); } + (NXImage *)icon { return(icon); } // externalExistsWithDomain:andPath: is a Class method used search to all // IExternalD's. Neccessary since there should be only one IExternalD // for an external representation. + externalExistsWithDomain:(NXAtom)domain andPath:(const char *)path { int i; IExternalD *external; for (i = 0; (external = [externalsList objectAt:i]) != nil; ++i) { if ([external hasDomain:domain andPath:path] == YES) { return(external); } } return(nil); } - (const char *)key // The key for the current domain is returned. You must have correctly // set the current domain for this to work properly. This is really a // bad way to do this but this code evolved from code that did not need // domains. { BOOL flag; const char *key; DBG(1, fprintf(stderr, "%s", [self keyForDomain:NULL isDirty:&flag])); key = [self keyForDomain:NULL isDirty:&flag]; if (key != NULL) { return(key); } else { return(""); } } - (const char *)keyForDomain:(NXAtom)domain isDirty:(BOOL *)dirtyFlag // If domain == NULL return key for current domain. // Representation is dirty if it is inconsistent with current object // that is the object has been edited and not resaved. { struct artaddr *addr; if (domain != NULL) { for (addr = addrlist; addr != NULL && addr->aa_domain != domain; addr = addr->aa_next); if (addr != NULL) { curaddr = addr; } else { curaddr = NULL; } } if (curaddr != NULL) { if (curkey != NULL) { NXZoneFree([self zone], (char *)curkey); } curkey = NXZoneMalloc([self zone], strlen(curaddr->aa_name) + strlen(curaddr->aa_domain) + 2); sprintf((char *)curkey, "%s.%s", curaddr->aa_name, curaddr->aa_domain); // path is dirty if it is inconsistent with current article or path // belongs to a temporary article *dirtyFlag = (curaddr->aa_status && AS_DIRTY_MASK) != 0 || strncmp(curaddr->aa_name, "/tmp/", 5) == 0; return(curkey); } else { return(NULL); } } - init { addrlist = NULL; curaddr = NULL; object = nil; [externalsList addObject:self]; return(self); } - initWithDomain:(NXAtom)domain andPath:(const char *)path { int i; IExternalD *external; for (i = 0; (external = [externalsList objectAt:i]) != nil; ++i) { if ([external hasDomain:domain andPath:path] == YES) { // already exists! [self free]; return(external); } } addrlist = NXZoneMalloc([self zone], sizeof(struct artaddr) + strlen(path)); addrlist->aa_next = NULL; addrlist->aa_domain = domain; addrlist->aa_status = 0; strcpy(addrlist->aa_name, path); curaddr = addrlist; object = nil; [externalsList addObject:self]; return(self); } // setDomain:andPath: sets the current domain and path and also clears the // dirty flag. This is used when writing a new representation to an // external domain. - setDomain:(NXAtom)domain andPath:(const char *)path { struct artaddr **addrp, *next; next = NULL; for (addrp = &addrlist; *addrp != NULL; addrp = &(*addrp)->aa_next) { if ((*addrp)->aa_domain == domain) { if (strcmp((*addrp)->aa_name, path) == 0) { // already exists so just exit curaddr = *addrp; curaddr->aa_status = 0; return(self); } else { // remove previous path for this domain next = (*addrp)->aa_next; NXZoneFree([self zone], *addrp); break; } } } // add new path *addrp = NXZoneMalloc([self zone], sizeof(struct artaddr) + strlen(path)); (*addrp)->aa_next = next; (*addrp)->aa_domain = domain; (*addrp)->aa_status = 0; strcpy((*addrp)->aa_name, path); curaddr = *addrp; return(self); } - (BOOL)hasDomain:(NXAtom)domain andPath:(const char *)path { struct artaddr *addr; for (addr = addrlist; addr != NULL; addr = addr->aa_next) { if (addr->aa_domain == domain && strcmp(addr->aa_name, path) == 0) { return(YES); } } return(NO); } - (NXAtom)currentDomain { if (curaddr != NULL) { return(curaddr->aa_domain); } else { return(addrlist->aa_domain); } } - (const char *)currentPath { if (curaddr != NULL) { return(curaddr->aa_name); } else { return(addrlist->aa_name); } } - (NXImage *)image { return(image); } - setReferenceCount:(int)newCount { refCount = newCount; return self; } - (int)referenceCount { return (refCount); } - (int)incrementReferenceCount { return(++refCount); } - (int)decrementReferenceCount { return(--refCount); } - (int)size { return(0); } // object returns the object. If the object is not loaded object will // load it from the current domain - object { if (object == nil) { if (curaddr == NULL) { curaddr = addrlist; } if ((object = [(id)[IExternalTable externalModuleForDomain: curaddr->aa_domain] loadFromName:curaddr->aa_name inZone:[self zone]]) != nil) { [object setExternal:self]; } } return(object); } - setObject:theObject { object = theObject; return(self); } - objectExists { return(object); } - performDoubleClickAction:sender { [self perform:@selector(performDoubleClickAction2:) with:sender afterDelay:1 cancelPrevious:YES]; return(self); } // performDoubleClickAction2: is neccessary because of race condition - performDoubleClickAction2:sender { if (object == nil) { [self object]; } if (object != nil) { [object openEditor]; } return(self); } // free only if reference count is 0 - markAsDirty { struct artaddr *addr; for (addr = addrlist; addr != NULL; addr = addr->aa_next) { addr->aa_status |= AS_DIRTY_MASK; } return(self); } - free { NXZone *zone; if (--refCount <= 0) { if (object != nil) { [object free]; } [externalsList removeObject:self]; zone = [self zone]; [super free]; NXDestroyZone(zone); return(nil); } return(self); } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.