⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htanchor.c

📁 www工具包. 这是W3C官方支持的www支撑库. 其中提供通用目的的客户端的WebAPI: complete HTTP/1.1 (with caching, pipelining, PUT, POS
💻 C
📖 第 1 页 / 共 3 页
字号:
/*								     HTAnchor.c**	HYPERTEXT "ANCHOR" OBJECT****	(c) COPYRIGHT MIT 1995.**	Please first read the full copyright statement in the file COPYRIGH.**	@(#) $Id: HTAnchor.c,v 1.89 2001/03/06 16:25:09 kahan Exp $****	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**	 3-May-1995 (HF), Added a lot of methods and other stuff made an object**	July 1996	Patch for adding hash of children Michael Farrar*//* Library include files */#include "wwwsys.h"#include "WWWUtil.h"#include "HTFormat.h"#include "HTParse.h"#include "HTMethod.h"#include "HTWWWStr.h"#include "HTAncMan.h"					 /* Implemented here */#define PARENT_HASH_SIZE	HT_XL_HASH_SIZE#define CHILD_HASH_SIZE		HT_L_HASH_SIZEPRIVATE HTList **adult_table=0;  /* Point to table of lists of all parents *//* ------------------------------------------------------------------------- *//*				Creation Methods			     *//* ------------------------------------------------------------------------- *//***	Do not use "new" by itself outside this module. In order to enforce**	consistency, we insist that you furnish more information about the**	anchor you are creating : use newWithParent or newWithAddress.*/PRIVATE HTParentAnchor * HTParentAnchor_new (void){    HTParentAnchor *newAnchor;    if ((newAnchor = (HTParentAnchor *) HT_CALLOC(1, sizeof (HTParentAnchor))) == NULL)	HT_OUTOFMEM("HTParentAnchor_new");    newAnchor->parent = newAnchor;    newAnchor->content_type = WWW_UNKNOWN;    newAnchor->mainLink.method = METHOD_INVALID;    newAnchor->content_length = -1;			 /* howcome 6 dec 95 */    newAnchor->date = (time_t) -1;    newAnchor->expires = (time_t) -1;    newAnchor->last_modified = (time_t) -1;    newAnchor->age = (time_t) -1;    return newAnchor;}PRIVATE HTChildAnchor * HTChildAnchor_new (void){    HTChildAnchor *child;    if ((child = (HTChildAnchor  *) HT_CALLOC(1, sizeof(HTChildAnchor))) == NULL)        HT_OUTOFMEM("HTChildAnchor_new");    return child;}/*	Create new or find old child anchor**	-----------------------------------****	Me one is for a new anchor being edited into an existing**	document. The parent anchor must already exist. All**	children without tags (no NAME attribut) points to the same NULL**	child.**	Children are now hashed for performance reasons. Thanks to**	Michael Farrar*/PUBLIC HTChildAnchor * HTAnchor_findChild (HTParentAnchor *	parent,					   const char *		tag){    HTChildAnchor * child = NULL;    HTList * kids = NULL;    if (!parent) {	HTTRACE(ANCH_TRACE, "Child Anchor Bad argument\n");	return NULL;    }    /* Find a hash for this tag (if any) */    {	int hash = 0;	/*	** If tag is empty then use hash value 0	*/	if (tag) {	    const char * ptr = tag;	    for(; *ptr; ptr++)		hash = (int) ((hash*3 + (*(unsigned char*)ptr)) % CHILD_HASH_SIZE);	}	if (!parent->children) {	    if (!(parent->children = (HTList **)			  HT_CALLOC(CHILD_HASH_SIZE, sizeof(HTList *))))		HT_OUTOFMEM("HTAnchor_findChild");	}	if (!parent->children[hash]) parent->children[hash] = HTList_new();	kids = parent->children[hash];    }    /* First search list of children to see if tag is already there */    if (tag && *tag) {	HTList * cur = kids;	while ((child = (HTChildAnchor *) HTList_nextObject(cur))) {	    if (child->tag && !strcmp(child->tag, tag)) {		HTTRACE(ANCH_TRACE, "Child Anchor %p of parent %p with name `%s' already exists.\n" _ 			    (void *) child _ (void *) parent _ tag);		return child;	    }	}    }    /* If not found then create a new child anchor */    child = HTChildAnchor_new();    HTList_addObject(kids, (void *) child);    child->parent = parent;    if (tag) StrAllocCopy(child->tag, tag);    HTTRACE(ANCH_TRACE, "Child Anchor New Anchor %p named `%s' is child of %p\n" _ 		(void *) child _ tag ? tag : (const char *) "" _ (void *)parent);    return child;}/*	Create new or find old named anchor**	-----------------------------------****	Me one is for a reference which is found in a document, and might**	not be already loaded.**	Note: You are not guaranteed a new anchor -- you might get an old one,**	like with fonts.*/PUBLIC HTAnchor * HTAnchor_findAddress (const char * address){    char *tag = HTParse (address, "", PARSE_VIEW);	        /* Any tags? */        /* If the address represents a sub-anchor, we recursively load its parent,       then we create a child anchor within that document. */    if (*tag) {	char *addr = HTParse(address, "", PARSE_ACCESS | PARSE_HOST |			     PARSE_PATH | PARSE_PUNCTUATION);	HTParentAnchor * parent = (HTParentAnchor*) HTAnchor_findAddress(addr);	HTChildAnchor * child = HTAnchor_findChild(parent, tag);	HT_FREE(addr);	HT_FREE(tag);	return (HTAnchor *) child;    } else {		       	     /* Else check whether we have this node */	int hash;	const char *p;	HTList * adults;	HTList *grownups;	HTParentAnchor * foundAnchor;	char *newaddr = NULL;	StrAllocCopy(newaddr, address);		         /* Get our own copy */	HT_FREE(tag);	newaddr = HTSimplify(&newaddr);	/* Select list from hash table */	for(p=newaddr, hash=0; *p; p++)	    hash = (int) ((hash * 3 + (*(unsigned char*)p)) % PARENT_HASH_SIZE);	if (!adult_table) {	    if ((adult_table = (HTList* *) HT_CALLOC(PARENT_HASH_SIZE, sizeof(HTList*))) == NULL)	        HT_OUTOFMEM("HTAnchor_findAddress");	}	if (!adult_table[hash]) adult_table[hash] = HTList_new();	adults = adult_table[hash];	/* Search list for anchor */	grownups = adults;	while ((foundAnchor = (HTParentAnchor *) HTList_nextObject(grownups))){	    if (!strcmp(foundAnchor->address, newaddr)) {		HTTRACE(ANCH_TRACE, "Find Parent. %p with address `%s' already exists.\n" _ 			    (void*) foundAnchor _ newaddr);		HT_FREE(newaddr);		       /* We already have it */		return (HTAnchor *) foundAnchor;	    }	}		/* Node not found : create new anchor. */	foundAnchor = HTParentAnchor_new();	foundAnchor->address = newaddr;			/* Remember our copy */	HTList_addObject (adults, foundAnchor);	HTTRACE(ANCH_TRACE, "Find Parent. %p with hash %d and address `%s' created\n" _ (void*)foundAnchor _ hash _ newaddr);	return (HTAnchor *) foundAnchor;    }}/*	Create or find a child anchor with a possible link**	--------------------------------------------------****	Create new anchor with a given parent and possibly**	a name, and possibly a link to a _relatively_ named anchor.**	All parameters EXCEPT parent can be NULL*/PUBLIC HTChildAnchor * HTAnchor_findChildAndLink (HTParentAnchor *	parent,						  const char *		tag,						  const char *		href,						  HTLinkType		ltype){    HTChildAnchor * child = HTAnchor_findChild(parent, tag);    if (child && href && *href) {	char * relative_to = HTAnchor_expandedAddress((HTAnchor *) parent);	char * parsed_address = HTParse(href, relative_to, PARSE_ALL);	HTAnchor * dest = HTAnchor_findAddress(parsed_address);	HTLink_add((HTAnchor *) child, dest, ltype, METHOD_INVALID);	HT_FREE(parsed_address);	HT_FREE(relative_to);    }    return child;}/* ------------------------------------------------------------------------- *//*				   Link Methods				     *//* ------------------------------------------------------------------------- *//***  Upgrade the link to the main destination and and downgrade the**  current main link to the list*/PUBLIC HTLink * HTAnchor_mainLink (HTAnchor * me){    return me ? &(me->mainLink) : NULL;}PUBLIC BOOL HTAnchor_setMainLink  (HTAnchor * me, HTLink * movingLink){    if (!(me && me->links && movingLink &&	  HTList_removeObject(me->links, movingLink)))	return NO;    else {	/* First push current main link onto top of links list */	HTLink * newLink = HTLink_new();	memcpy ((void *) newLink, & me->mainLink, sizeof (HTLink));	HTList_addObject (me->links, newLink);	/* Now make movingLink the new main link, and delete it */	memcpy ((void *) &me->mainLink, movingLink, sizeof (HTLink));	HTLink_delete(movingLink);	return YES;    }}/***	Handling sub links*/PUBLIC HTList * HTAnchor_subLinks (HTAnchor * anchor){    return anchor ? anchor->links : NULL;}PUBLIC BOOL HTAnchor_setSubLinks (HTAnchor * anchor, HTList * list){    if (anchor) {	anchor->links = list;	return YES;    }    return NO;}/***  Returns the main destination of this anchor*/PUBLIC HTAnchor * HTAnchor_followMainLink (HTAnchor * me){    return me ? HTLink_destination(&me->mainLink) : NULL;}/***  Returns a link with a given link type or NULL if nothing found*/PUBLIC HTLink * HTAnchor_findLinkType (HTAnchor * me, HTLinkType type){    if (me) {	HTLink * link = HTAnchor_mainLink(me);	HTList * sublinks = HTAnchor_subLinks(me);	if (link && HTLink_type(link) == type)	    return link;	else if (sublinks) {	    while ((link = (HTLink *) HTList_nextObject (sublinks)))		if (HTLink_type(link) == type) return link;	}    }    return NULL;}/* ------------------------------------------------------------------------- *//*				Deletion Methods			     *//* ------------------------------------------------------------------------- *//*	Delete an anchor and possibly related things (auto garbage collection)**	--------------------------------------------****	The anchor is only deleted if the corresponding document is not loaded.**	All outgoing links from parent and children are deleted, and this**	anchor is removed from the sources list of all its targets.**	We also try to delete the targets whose documents are not loaded.**	If this anchor's source list is empty, we delete it and its children.*//*	Deletes all the memory allocated in a parent anchor and returns any**	hyperdoc object hanging of this anchor*/PRIVATE void * delete_parent (HTParentAnchor * me){    void * doc = me->document;    /* Remove link and address information */    if (me->links) {	HTList *cur = me->links;	HTLink *pres;	while ((pres = (HTLink *) HTList_nextObject(cur)))	    HTLink_delete(pres);	HTList_delete(me->links);    }    /* Remove children */    if (me->children) {	int cnt = 0;	for (; cnt<CHILD_HASH_SIZE; cnt++) {	    if (me->children[cnt]) HTList_delete(me->children[cnt]);	}	HT_FREE(me->children);    }    HTList_delete (me->sources);    HTList_delete (me->variants);    HT_FREE(me->physical);    HT_FREE(me->address);    /* Then remove entity header information (metainformation) */    HTAnchor_clearHeader(me);    HT_FREE(me);    return doc;}/*	Delete a parent anchor and all its children. If a hyperdoc object**	is found hanging off the parent anchor then this is returned*/PRIVATE void * delete_family (HTAnchor * me){    HTParentAnchor * parent = NULL;    if (!me) {	HTTRACE(ANCH_TRACE, "AnchorDelete No anchor found\n");	return NULL;    }    parent = me->parent;    HTTRACE(ANCH_TRACE, "AnchorDelete Remove parent %p and children\n" _ parent);    /* Delete children */    if (parent->children) {	int cnt = 0;	for (; cnt<CHILD_HASH_SIZE; cnt++) {	    HTList * kids = parent->children[cnt];	    if (kids) {		HTChildAnchor * child;		while ((child=(HTChildAnchor*)HTList_removeLastObject(kids))) {		    HT_FREE(child->tag);		    if (child->links) {			HTList * cur = child->links;			HTLink * pres;			while ((pres = (HTLink *) HTList_nextObject(cur)))			    HTLink_delete(pres);			HTList_delete(child->links);		    }		    HT_FREE(child);		}		HTList_delete(kids);		parent->children[cnt] = NULL;	    }	}    }    return delete_parent(parent);}/*	DELETE ALL ANCHORS**	------------------**	Deletes all anchors and return a list of all the HyperDocs found.**	It is for the application to delete any HyperDocs.**	If NULL then no hyperdocs are returned**	Return YES if OK, else NO*/PUBLIC BOOL HTAnchor_deleteAll (HTList * documents){    int cnt;    HTList *cur;    if (!adult_table)	return NO;    for (cnt=0; cnt<PARENT_HASH_SIZE; cnt++) {	if ((cur = adult_table[cnt])) { 	    HTParentAnchor *pres;	    while ((pres = (HTParentAnchor *) HTList_nextObject(cur)) != NULL){		void * doc = delete_family((HTAnchor *) pres);		if (doc && documents) HTList_addObject(documents, doc);	    }	}	HTList_delete(adult_table[cnt]);    }    HT_FREE(adult_table);    return YES;}/***	Deletes all the metadata associated with anchors but doesn't**	delete the anchor link structure itself. This is much safer**	than deleting the complete anchor structure as this represents the**	complete Web the application has been in touch with*/PUBLIC BOOL HTAnchor_clearAll (HTList * documents){    int cnt;    HTList * cur;    if (!adult_table) return NO;    for (cnt=0; cnt<PARENT_HASH_SIZE; cnt++) {	if ((cur = adult_table[cnt])) { 	    HTParentAnchor * pres;	    while ((pres = (HTParentAnchor *) HTList_nextObject(cur))) {		/* Then remove entity header information */		HTAnchor_clearHeader(pres);		/* Delete the physical address */		HT_FREE(pres->physical);		/* Register if we have a document on this anchor */		if (documents && pres->document)		    HTList_addObject(documents, pres->document);	    }	}    }    return YES;}PRIVATE void delete_links (HTAnchor * me){  if (! me)    return;  /* Recursively try to delete target anchors */  if (me->mainLink.dest) {    HTParentAnchor *parent = me->mainLink.dest->parent;    HTList_removeObject (parent->sources, me);    if (! parent->document)  /* Test here to avoid calling overhead */      HTAnchor_delete (parent);  }  if (me->links) {  /* Extra destinations */    HTLink *target;    while ((target = (HTLink *) HTList_removeLastObject (me->links))) {      HTParentAnchor *parent = target->dest->parent;      HTList_removeObject (parent->sources, me);      if (! parent->document)  /* Test here to avoid calling overhead */	HTAnchor_delete (parent);    }  }}PUBLIC BOOL HTAnchor_delete (HTParentAnchor * me){    /* Don't delete if document is loaded */    if (!me || me->document) {	HTTRACE(ANCH_TRACE, "Anchor...... Not deleted\n");	return NO;    }    /* Recursively try to delete target anchors */    delete_links ((HTAnchor *) me);    if (!HTList_isEmpty(me->sources)) {    /* There are still incoming links */	/*	** Delete all outgoing links from children, if any	*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -