home *** CD-ROM | disk | FTP | other *** search
- /* Hypertext "Anchor" Object HTAnchor.c
- ** ==========================
- **
- ** An anchor represents a region of a hypertext document which is linked to
- ** another anchor in the same or a different document.
- **
- ** History
- **
- ** Nov 1990 Written in Objective-C for the NeXT browser (TBL)
- ** 24-Oct-1991 (JFG), written in C, browser-independant
- ** 21-Nov-1991 (JFG), first complete version
- ** 12-Apr-1994 (GAB), rewrite and debugged for MSDOS.
- **
- ** (c) Copyright CERN 1991 - See Copyright.html
- */
-
- #include"capalloc.h"
- #include"capstdio.h"
- #include <ctype.h>
- #include "tcp.h"
- #include "HTAnchor.h"
- #include "HTUtils.h"
- #include "HTParse.h"
-
- /*
- * Abstract hypertext document. Used to define pointers of appropriate
- * type.
- */
- typedef struct _HyperDoc Hyperdoc;
-
- /*
- * This is a hash table of HTLists containg the addresses of all parent
- * anchors. Empty on startup. This memory appears to never be freed
- * once created, along with all the lists it contains also....
- */
- PRIVATE HTList **adult_table = NULL;
-
- /*
- * This is the size of the adult_table in pointers to the HTList
- * structure. Resizable for whatever you need of course.
- * The original creators intended this number to be prime, but the
- * need is not evident.
- */
- #define HASH_SIZE 101U
-
- /*
- * This is the hasing function used to determine which list in the
- * adult_table a parent anchor should be put it. It was simplified for
- * MSDOS in a drastic way.
- */
- #define HASH_FUNCTION(cp_address) ((unsigned short int)strlen(cp_address) *\
- (unsigned short int)toupper(*cp_address) % HASH_SIZE)
-
- /*
- * The following used to be a function, but has been moved to be a
- * macro for speed. It simply does a case insensitive string compare.
- */
- #define equivalent(cp_str1, cp_str2) (stricmp(cp_str1, cp_str2) ? NO : YES)
-
- static HTParentAnchor *HTParentAnchor_new(void) {
- /*
- * Purpose: Create a new parent anchor that is compeletly empty.
- * Arguments: void
- * Return Value: HTParentAnchor * The new parent anchor that
- * was allocated, or NULL.
- * Remarks/Portability/Dependencies/Restrictions:
- * Callers should eventually destroy this parent anchor.
- * See HTAnchor_delete.
- * Revision History:
- * 04-12-94 Modified for MSDOS by GAB.
- */
- /*
- * Create the new parent anchor, zero filled.
- */
- auto HTParentAnchor *newAnchor = (HTParentAnchor *)calloc (1,
- sizeof (HTParentAnchor));
-
- /*
- * If unable, of course return NULL.
- */
- if(newAnchor != NULL) {
- /*
- * The new parent anchor is it's own parent, not NULL.
- * This provides correct functionality in the remaining
- * HTAnchor functions.
- */
- newAnchor->parent = newAnchor;
- return(newAnchor);
- }
- return(NULL);
- }
-
- static HTChildAnchor *HTChildAnchor_new(void) {
- /*
- * Purpose: Create a new child anchor that is completely empty.
- * Arguments: void
- * Return Value: HTChildAnchor * The new child anchor, or NULL.
- * Remarks/Portability/Dependencies/Restrictions:
- * Callers should eventually destroy this child anchor
- * by destroying its parent. See HTAnchor_delete.
- * Revision History:
- * 04-12-94 Modified for MSDOS by GAB.
- */
- /*
- * Return the new memory, or NULL.
- */
- return((HTChildAnchor *)calloc (1, sizeof (HTChildAnchor)));
- }
-
- static HTChildAnchor *HTAnchor_findChild(HTParentAnchor *parent, const char
- *tag) {
- /*
- * Purpose: Will find a child in the parent's children and add
- * the tag, or will create a new child, add
- * the tag, and then add the new child to the
- * parent.
- * Arguments: parent The parent anchor of the child.
- * tag The tag value for the child.
- * Return Value: HTChildAnchor * The new or old child inside the
- * parents children with the tag, or
- * NULL if nothing done.
- * Remarks/Portability/Dependencies/Restrictions:
- * Memory may be allocated. Callers should eventually destroy
- * child anchors by calling HTAnchor_delete with the child's
- * parent.
- * Revision History:
- * 04-12-94 modified for MSDOS by GAB.
- */
- auto HTChildAnchor *child;
- auto HTList *kids;
-
- /*
- * Child anchors must always have a parent to own them.
- * If none, return NULL.
- */
- if(!parent) {
- #ifndef RELEASE
- if(TRACE) {
- printf ("HTAnchor_findChild called with NULL parent."
- "\n");
- }
- #endif /* RELEASE */
- return(NULL);
- }
-
- /*
- * If the parent has children, search them for a duplicate
- * child.
- */
- if(kids = parent->children) {
- /*
- * If there was a tag passed in.
- */
- if(tag && *tag) {
- while(child = HTList_nextObject(kids)) {
- /*
- * If the tags are the same, we assume
- * the same anchor. This is
- * case insensitive.
- */
- if(equivalent(child->tag, tag)) {
- #ifndef RELEASE
- if(TRACE) {
- fprintf (stderr, "Child anchor "
- "%p of parent %p with "
- "name `%s' already "
- "exists.\n", (void*)
- child, (void*)parent,
- tag);
- }
- #endif /* RELEASE */
- /*
- * return the child that was
- * found. No anchor need be
- * created since the
- * anchor already has it.
- */
- return(child);
- }
- }
- }
- }
- else {
- /*
- * The parent has no list of children, creat the family.
- * Empty as of now.
- */
- parent->children = HTList_new();
- }
-
- /*
- * Create a new empty child anchor.
- */
- child = HTChildAnchor_new();
- #ifndef RELEASE
- if(TRACE) {
- fprintf(stderr, "new Anchor %p named `%s' is child of %p\n",
- (void*)child, (int)tag ? tag : (const char *)"",
- (void*)parent);
- }
- #endif /* RELEASE */
-
- /*
- * Add the new child to the parent's list.
- * Let the child know who its parent is.
- * Tag the child.
- */
- HTList_addObject(parent->children, child);
- child->parent = parent;
- StrAllocCopy(child->tag, tag);
-
- /*
- * This is the return for the newly created child.
- */
- return(child);
- }
-
- extern HTChildAnchor *HTAnchor_findChildAndLink(HTParentAnchor *parent, const
- char *tag, const char *href, HTLinkType *ltype) {
- /*
- * Purpose: Create a new child anchor (or an already existing one)
- * with the given parent and possibly link to a
- * relatively named anchor.
- * Arguments: parent The parent anchor of the child. May not be
- * NULL.
- * tag The tag value for the child. May be NULL.
- * href The hypertext reference to which to link.
- * May be NULL.
- * ltype The type of link to make (destination anchor
- * etc.) May be NULL.
- * Return Value: HTChildAnchor * The new or old child inside the
- * parents children with the tag, or
- * NULL if nothing done.
- * Remarks/Portability/Dependencies/Restrictions:
- * Memory may be allocated. Callers should eventually destroy
- * child anchors by calling HTAnchor_delete with the child's
- * parent.
- * Revision History:
- * 04-12-94 modified for MSDOS by GAB.
- */
-
- /*
- * This may create a new child or return an older one.
- */
- auto HTChildAnchor *child = HTAnchor_findChild(parent, tag);
-
- /*
- * If there is a hypertext reference.
- * Construct it's address relative to the parent.
- */
- if (href && *href) {
- /*
- * Get the parent's address. Allocated memory returned.
- */
- auto char *relative_to = HTAnchor_address((HTAnchor *)parent);
-
- /*
- * Get the parsed address relatively. Allocated memory
- * returned.
- */
- auto char *parsed_address = HTParse(href, relative_to,
- PARSE_ALL);
-
- /*
- * Find the destination of the paresed relatvie address.
- * This could return an already existing anchor, either
- * parent or child, or new memory could be allocated.
- */
- auto HTAnchor *dest = HTAnchor_findAddress(parsed_address);
-
- /*
- * Perform the linkage of the child to the destination
- * with the appropriate link type.
- */
- HTAnchor_link((HTAnchor *)child, dest, ltype);
-
- /*
- * Free up the memory allocated by the WWW functions.
- */
- free(parsed_address);
- free(relative_to);
- }
-
- /*
- * Return the child, wether or not created and wether or not
- * linked.
- */
- return(child);
- }
-
-
- extern HTAnchor *HTAnchor_findAddress(const char *cp_address) {
- /*
- * Purpose: Create a new or find an old named anchor.
- * Arguments: cp_address The address (absolute URL?) of the
- * anchor to find or create.
- * Return Value: HTAnchor * The anchor, regardless if created or
- * if found.
- * Remarks/Portability/Dependencies/Restrictions:
- * Revision History:
- * ??-??-?? created
- * 03-28-94 modified for DosLynx
- */
-
- /*
- * Find out if the anchor has a tag on it.
- * This is allocated memory.
- */
- auto char *cp_tag = HTParse(cp_address, "", PARSE_ANCHOR);
-
- /*
- * If there exists a tag in the anchor, the address represents
- * what is called a sub-anchor (a child for sure).
- * First, load the parent anchor, and then create a child
- * anchor within the document.
- */
- if(cp_tag != NULL && *cp_tag != '\0') {
- /*
- * Create the address without the tag.
- * This is allocated memory.
- */
- auto char *cp_docAddress = HTParse(cp_address, "",
- PARSE_ACCESS | PARSE_HOST | PARSE_PATH |
- PARSE_PUNCTUATION);
- /*
- * Load the parent (no longer has the tag) recursively.
- * Could be a new or old parent.
- */
- auto HTParentAnchor *HTPAp_foundParent = (HTParentAnchor *)
- HTAnchor_findAddress(cp_docAddress);
-
- /*
- * Find the anchor within the parent anchor with the
- * particular tagged anchor. If none exists, one will
- * be created.
- */
- auto HTChildAnchor *HTCAp_foundAnchor = HTAnchor_findChild(
- HTPAp_foundParent, cp_tag);
-
- /*
- * Free memory allocated by called functions.
- */
- free(cp_docAddress);
- free(cp_tag);
-
- /*
- * Return the child anchor that was found or created.
- */
- return((HTAnchor *)HTCAp_foundAnchor);
- }
- /*
- * Otherwise there is no tagged anchor. Just load the parent.
- * If there was a tag, then we reach here anyway via recursion.
- */
- else {
- auto unsigned short int usi_hash;
- auto HTList *HTLp_adults;
- auto HTList *HTLp_grownups;
- auto HTParentAnchor *HTPAp_foundAnchor;
-
- /*
- * Free the tag if it exists, won't need it.
- */
- if(cp_tag != NULL) {
- free(cp_tag);
- }
-
- /*
- * Select a particular list from the hash table.
- */
- usi_hash = HASH_FUNCTION(cp_address);
-
- /*
- * If the adult table has not yet been created, create
- * and initialize it.
- */
- if(adult_table == NULL) {
- adult_table = (HTList**)calloc(HASH_SIZE,
- sizeof(HTList*));
- }
-
- /*
- * If a particular list in the hash table has not been
- * created, do so.
- */
- if(adult_table[usi_hash] == NULL) {
- adult_table[usi_hash] = HTList_new();
- }
-
- /*
- * We now have an adults list to look for our address.
- */
- HTLp_adults = adult_table[usi_hash];
-
- /*
- * Search the list for the anchor.
- */
- HTLp_grownups = HTLp_adults;
- while(NULL != (HTPAp_foundAnchor = HTList_nextObject(
- HTLp_grownups))) {
- /*
- * Compare the addresses to see if the same.
- * The compare is case insensitive.
- * Here is some very slow code....
- */
- if(equivalent(HTPAp_foundAnchor->address,
- cp_address)) {
- #ifndef RELEASE
- if(TRACE) {
- fprintf(stderr, "Anchor %p "
- "with address `%s' "
- "already exists.\n",
- (void *)
- HTPAp_foundAnchor,
- cp_address);
- }
- #endif /* RELEASE */
- /*
- * Return the found anchor in
- * the hash table.
- */
- return((HTAnchor *)HTPAp_foundAnchor);
- }
- }
-
- /*
- * An anchor was not found in the hast list with the same
- * address. Create a new entry.
- */
- HTPAp_foundAnchor = HTParentAnchor_new();
- #ifndef RELEASE
- if(TRACE) {
- fprintf(stderr, "New anchor %p has hash %u and "
- "address `%s'\n", (void*)HTPAp_foundAnchor,
- usi_hash, cp_address);
- }
- #endif /* RELEASE */
-
- /*
- * Allocate the address space for the new anchor and
- * copy it in.
- */
- StrAllocCopy(HTPAp_foundAnchor->address, cp_address);
-
- /*
- * Add the new anchor to the hash list.
- */
- HTList_addObject(HTLp_adults, HTPAp_foundAnchor);
-
- /*
- * Return the newly created anchor.
- */
- return((HTAnchor *)HTPAp_foundAnchor);
- }
- }
-
-
- static void deleteLinks(HTAnchor *me) {
- /*
- * Purpose: Remove the anchor me from all of it's destination
- * parent anchor's sources.
- * If the destination parent is not also loaded, then
- * call HTAnchor_delete for it also.
- * Arguments: me The anchor (child or parent) for which to
- * unregister will all the parent anchors that
- * are me's destination.
- * Return Value: void
- * Remarks/Portability/Dependencies/Restrictions:
- * This function, combined with HTAnchor_delete, form a
- * recursive relationship to clean up all unloaded
- * parent anchors.
- * Revision History:
- * 04-12-94 modified for MSDOS by GAB
- */
-
- /*
- * Anchor is NULL, do nothing.
- */
- if(me == NULL) {
- return;
- }
-
- /*
- * Unregister us with our mainLink destination anchor's parent.
- */
- if(me->mainLink.dest != NULL) {
- auto HTParentAnchor *parent = me->mainLink.dest->parent;
-
- /*
- * Remove us from the parent's sources so that the
- * parent knows one less anchor is it's destination.
- */
- if(!HTList_isEmpty(parent->sources)) {
- /*
- * Really should only need to deregister once.
- */
- HTList_removeObject(parent->sources, (void *)me);
- }
-
- /*
- * Test here to avoid calling overhead.
- * If the parent has no loaded document, then we should
- * tell it to attempt to delete itself.
- * Don't do this jazz if the anchor passed in is the same
- * as the anchor to delete.
- * Also, don't do this if the destination parent is our
- * parent.
- */
- if(parent->document == NULL && parent != (HTParentAnchor *)me
- && me->parent != parent) {
- HTAnchor_delete(parent);
- }
-
- /*
- * At this point, we haven't a mainLink. Set it to be
- * so. Leave the HTAtom pointed to by type up to WWW to
- * handle.
- */
- me->mainLink.dest = NULL;
- me->mainLink.type = NULL;
- }
-
- /*
- * Check for extra destinations in our links list.
- */
- if(!HTList_isEmpty(me->links)) {
- auto HTLink *target;
- auto HTParentAnchor *parent;
-
- /*
- * Take out our extra non mainLinks one by one, calling
- * their parents to know that they are no longer the
- * destination of me's anchor.
- */
- while(target = (HTLink *)HTList_removeLastObject(me->links))
- {
- parent = target->dest->parent;
-
- if(!HTList_isEmpty(parent->sources))
- {
- /*
- * Only need to tell destination parent
- * anchor once.
- */
- HTList_removeObject(parent->sources,
- (void *)me);
- }
-
- /*
- * Avoid calling overhead.
- * If the parent hasn't a loaded document, then
- * we will attempt to have the parent delete
- * itself.
- * Don't call twice if this is the same anchor
- * that we are trying to delete.
- * Also, Don't do this if we are trying to delete
- * our parent.
- */
- if(parent->document == NULL && (HTParentAnchor *)me
- != parent && me->parent != parent) {
- HTAnchor_delete(parent);
- }
- }
- /*
- * At this point, me no longer has any destinations in
- * out links list. Get rid of it.
- */
- HTList_delete(me->links);
- me->links = NULL;
- }
-
- /*
- * Catch in case links list exists but nothing in it.
- */
- if(me->links != NULL) {
- HTList_delete(me->links);
- me->links = NULL;
- }
- }
-
- extern BOOL HTAnchor_delete(HTParentAnchor *me) {
- /*
- * Purpose: Delete a parent anchor, it's children, and any
- * documents pointed at by either that also
- * do not have a valid HyperDoc loaded.
- * Arguments: me The parent anchor to begin deletion at.
- * Return Value: BOOL YES the parent anchor me was removed
- * completely.
- * NO the parent anchor does not exist, has
- * a valid HyperDoc loaded, or is still
- * the destination of another loaded
- * anchor.
- * Remarks/Portability/Dependencies/Restrictions:
- * Together with the deleteLinks function we form a type of
- * recursion.
- * We don't release the links member of HTAnchor here, since it
- * is really done in deleteLinks.
- * Revision History:
- * 04-12-94 modified by GAB for MSDOS.
- * Lots of memory leaks and assignment problems
- * fixed.
- */
- auto HTChildAnchor *child;
-
- /*
- * Do nothing if nothing to do.
- */
- if(me == NULL) {
- return NO;
- }
-
- #ifndef RELEASE
- if(TRACE) {
- printf("Deleting %s\n", me->address);
- }
- #endif /* RELEASE */
- /*
- * Don't delete if document is loaded
- */
- if(me->document != NULL) {
- #ifndef RELEASE
- if(TRACE) {
- printf("Can't delete, still loaded.\n");
- }
- #endif /* RELEASE */
- return NO;
- }
-
- /*
- * Recursively try to delete destination anchors of this parent.
- * In any event, this will tell all destination anchors that we
- * no longer consider them a destination.
- */
- deleteLinks((HTAnchor *)me);
-
- /*
- * There are still incoming links to this one (we are the
- * destination of another anchor).
- * Don't actually delete this anchor, but children are OK to
- * delete their links.
- */
- if(!HTList_isEmpty(me->sources)) {
- /*
- * Delete all outgoing links from children, do not
- * delete the children though.
- */
- auto HTList *kids = me->children;
-
- if(!HTList_isEmpty(kids)) {
- while(child = (HTChildAnchor *)HTList_nextObject(
- kids)) {
- if(child != NULL) {
- deleteLinks((HTAnchor *)
- child);
- }
- }
- }
-
- /*
- * Parent not deleted.
- */
- #ifndef RELEASE
- if(TRACE) {
- printf("Can't delete, still has sources.\n");
- }
- #endif /* RELEASE */
- return NO;
- }
-
- /*
- * No more incoming links : kill everything
- * First, recursively delete children and their links.
- */
- if(!HTList_isEmpty(me->children)) {
- while(child = (HTChildAnchor *)HTList_removeLastObject(me->
- children)) {
- if(child != NULL) {
- deleteLinks((HTAnchor *)child);
- if(child->tag != NULL) {
- free(child->tag);
- }
- free(child);
- }
- }
- }
-
- /*
- * Delete our empty list of children.
- */
- if(me->children != NULL) {
- HTList_delete(me->children);
- }
- /*
- * Delete our empty list of sources.
- */
- if(me->sources != NULL) {
- HTList_delete(me->sources);
- }
- /*
- * Delete the methods list.
- */
- if(me->methods != NULL) {
- /*
- * I guess leave what methods points to up in MEM for
- * WWW code.
- */
- HTList_delete(me->methods);
- }
- /*
- * Free up all allocated members.
- */
- if(me->isIndexAction != NULL) {
- free(me->isIndexAction);
- }
- if(me->title != NULL) {
- free(me->title);
- }
- if(me->physical != NULL) {
- free(me->physical);
- }
- /*
- * Remove ourselves from the hash table's list.
- */
- if(adult_table != NULL) {
- auto unsigned short int usi_hash = HASH_FUNCTION(me->address);
- if(adult_table[usi_hash] != NULL) {
- HTList_removeObject(adult_table[usi_hash],
- (void *)me);
- }
- }
- /*
- * Free our address, saved till last to figure our position in
- * the hash table.
- */
- if(me->address != NULL) {
- free(me->address);
- }
-
- /*
- * Devise a way to clean out the HTFormat if no longer needed
- * (ref count?) Leave it up to WWW since is an HTAtom....
- */
-
- /*
- * Finally, kill the parent anchor passed in.
- */
- free(me);
-
- /*
- * Parent was deleted.
- */
- return(YES);
- }
-
-
- /* Move an anchor to the head of the list of its siblings
- ** ------------------------------------------------------
- **
- ** This is to ensure that an anchor which might have already existed
- ** is put in the correct order as we load the document.
- */
-
- void HTAnchor_makeLastChild
- ARGS1(HTChildAnchor *,me)
- {
- if (me->parent != (HTParentAnchor *) me) { /* Make sure it's a child */
- HTList * siblings = me->parent->children;
- HTList_removeObject (siblings, me);
- HTList_addObject (siblings, me);
- }
- }
-
- /* Data access functions
- ** ---------------------
- */
-
- PUBLIC HTParentAnchor * HTAnchor_parent
- ARGS1 (HTAnchor *,me)
- {
- return me ? me->parent : NULL;
- }
-
- void HTAnchor_setDocument
- ARGS2 (HTParentAnchor *,me, HyperDoc *,doc)
- {
- if (me)
- me->document = doc;
- }
-
- HyperDoc * HTAnchor_document
- ARGS1 (HTParentAnchor *,me)
- {
- return me ? me->document : NULL;
- }
-
-
- /* We don't want code to change an address after anchor creation... yet ?
- void HTAnchor_setAddress
- ARGS2 (HTAnchor *,me, char *,addr)
- {
- if (me)
- StrAllocCopy (me->parent->address, addr);
- }
- */
-
- char * HTAnchor_address
- ARGS1 (HTAnchor *,me)
- {
- char *addr = NULL;
- if (me) {
- if (((HTParentAnchor *) me == me->parent) ||
- !((HTChildAnchor *) me)->tag) { /* it's an adult or no tag */
- StrAllocCopy (addr, me->parent->address);
- }
- else { /* it's a named child */
- addr = malloc (2 + strlen (me->parent->address)
- + strlen (((HTChildAnchor *) me)->tag));
- if (addr == NULL) outofmem(__FILE__, "HTAnchor_address");
- sprintf (addr, "%s#%s", me->parent->address,
- ((HTChildAnchor *) me)->tag);
- }
- }
- return addr;
- }
-
-
-
- void HTAnchor_setFormat
- ARGS2 (HTParentAnchor *,me, HTFormat ,form)
- {
- if (me)
- me->format = form;
- }
-
- HTFormat HTAnchor_format
- ARGS1 (HTParentAnchor *,me)
- {
- return me ? me->format : NULL;
- }
-
-
-
- void HTAnchor_setIndex
- ARGS2 (HTParentAnchor *,me, const char *,address)
- {
- #ifndef RELEASE
- if(TRACE) {
- fprintf(stderr, "HTAnchor_setIndex: %s is address\n", address);
- }
- #endif /* RELEASE */
-
- if (me) {
- me->isIndex = YES;
- if(address != NULL) {
- StrAllocCopy((me->isIndexAction), address);
- }
- else {
- me->isIndexAction = NULL;
- }
- }
- }
-
- BOOL HTAnchor_isIndex
- ARGS1 (HTParentAnchor *,me)
- {
- return me ? me->isIndex : NO;
- }
-
-
-
- BOOL HTAnchor_hasChildren
- ARGS1 (HTParentAnchor *,me)
- {
- return me ? ! HTList_isEmpty(me->children) : NO;
- }
-
- /* Title handling
- */
- CONST char * HTAnchor_title
- ARGS1 (HTParentAnchor *,me)
- {
- return me ? me->title : 0;
- }
-
- void HTAnchor_setTitle
- ARGS2(HTParentAnchor *,me, CONST char *,title)
- {
- StrAllocCopy(me->title, title);
- }
-
- void HTAnchor_appendTitle
- ARGS2(HTParentAnchor *,me, CONST char *,title)
- {
- StrAllocCat(me->title, title);
- }
-
- /* Link me Anchor to another given one
- ** -------------------------------------
- */
-
- BOOL HTAnchor_link
- ARGS3(HTAnchor *,source, HTAnchor *,destination, HTLinkType *,type)
- {
- if (! (source && destination))
- return NO; /* Can't link to/from non-existing anchor */
- #ifndef RELEASE
- if (TRACE) printf ("Linking anchor %p to anchor %p\n", source, destination);
- #endif /* RELEASE */
- if (! source->mainLink.dest) {
- source->mainLink.dest = destination;
- source->mainLink.type = type;
- } else {
- HTLink * newLink = (HTLink *) malloc (sizeof (HTLink));
- if (newLink == NULL) outofmem(__FILE__, "HTAnchor_link");
- newLink->dest = destination;
- newLink->type = type;
- if (! source->links)
- source->links = HTList_new ();
- HTList_addObject (source->links, newLink);
- }
- if (!destination->parent->sources)
- destination->parent->sources = HTList_new ();
- HTList_addObject (destination->parent->sources, source);
- return YES; /* Success */
- }
-
-
- /* Manipulation of links
- ** ---------------------
- */
-
- HTAnchor * HTAnchor_followMainLink
- ARGS1 (HTAnchor *,me)
- {
- return me->mainLink.dest;
- }
-
- HTAnchor * HTAnchor_followTypedLink
- ARGS2 (HTAnchor *,me, HTLinkType *,type)
- {
- if (me->mainLink.type == type)
- return me->mainLink.dest;
- if (me->links) {
- HTList *links = me->links;
- HTLink *link;
- while (link = HTList_nextObject (links))
- if (link->type == type)
- return link->dest;
- }
- return NULL; /* No link of me type */
- }
-
-
- /* Make main link
- */
- BOOL HTAnchor_makeMainLink
- ARGS2 (HTAnchor *,me, HTLink *,movingLink)
- {
- /* Check that everything's OK */
- if (! (me && HTList_removeObject (me->links, movingLink)))
- return NO; /* link not found or NULL anchor */
- else {
- /* First push current main link onto top of links list */
- HTLink *newLink = (HTLink*) malloc (sizeof (HTLink));
- if (newLink == NULL) outofmem(__FILE__, "HTAnchor_makeMainLink");
- memcpy (newLink, & me->mainLink, sizeof (HTLink));
- HTList_addObject (me->links, newLink);
-
- /* Now make movingLink the new main link, and free it */
- memcpy (& me->mainLink, movingLink, sizeof (HTLink));
- free (movingLink);
- return YES;
- }
- }
-
-
- /* Methods List
- ** ------------
- */
-
- PUBLIC HTList * HTAnchor_methods ARGS1(HTParentAnchor *, me)
- {
- if (!me->methods) {
- me->methods = HTList_new();
- }
- return me->methods;
- }
-
- /* Protocol
- ** --------
- */
-
- PUBLIC void * HTAnchor_protocol ARGS1(HTParentAnchor *, me)
- {
- return me->protocol;
- }
-
- PUBLIC void HTAnchor_setProtocol ARGS2(HTParentAnchor *, me,
- void*, protocol)
- {
- me->protocol = protocol;
- }
-
- /* Physical Address
- ** ----------------
- */
-
- PUBLIC char * HTAnchor_physical ARGS1(HTParentAnchor *, me)
- {
- return me->physical;
- }
-
- PUBLIC void HTAnchor_setPhysical ARGS2(HTParentAnchor *, me,
- char *, physical)
- {
- StrAllocCopy(me->physical, physical);
- }
-