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.