📄 htanchor.c
字号:
/* 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-independent** 21-Nov-1991 (JFG), first complete version**** (c) Copyright CERN 1991 - See Copyright.html*/#define HASH_SIZE 101 /* Arbitrary prime. Memory/speed tradeoff */#include <HTUtils.h>#include <HTAnchor.h>#include <HTParse.h>#include <HTString.h>#include <UCAux.h>#include <UCMap.h>#include <GridText.h>#include <LYUtils.h>#include <LYCharSets.h>#include <LYLeaks.h>#ifdef NOT_DEFINED/* * This is the hashing function used to determine which list in the * adult_table a parent anchor should be put in. This is a * much simpler function than the original used. */#define HASH_FUNCTION(cp_address) ((unsigned short int)strlen(cp_address) *\ (unsigned short int)TOUPPER(*cp_address) % HASH_SIZE)#endif /* NOT_DEFINED *//* * This is the original function. We'll use it again. - FM */PRIVATE int HASH_FUNCTION ARGS1( CONST char *, cp_address){ int hash; CONST unsigned char *p; for (p = (CONST unsigned char *)cp_address, hash = 0; *p; p++) hash = (int) (hash * 3 + (*(CONST unsigned char *)p)) % HASH_SIZE; return(hash);}typedef struct _HyperDoc Hyperdoc;#ifdef VMSstruct _HyperDoc { int junk; /* VMS cannot handle pointers to undefined structs */};#endif /* VMS *//* Table of lists of all parents */PRIVATE HTList adult_table[HASH_SIZE] = { {NULL, NULL} };/* 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 HTParentAnchor0 * HTParentAnchor0_new ARGS2( CONST char *, address, short, hash){ HTParentAnchor0 *newAnchor = typecalloc(HTParentAnchor0); if (newAnchor == NULL) outofmem(__FILE__, "HTParentAnchor0_new"); newAnchor->parent = newAnchor; /* self */ StrAllocCopy(newAnchor->address, address); newAnchor->adult_hash = hash; return(newAnchor);}PRIVATE HTParentAnchor * HTParentAnchor_new ARGS1( HTParentAnchor0 *, parent){ HTParentAnchor *newAnchor = typecalloc(HTParentAnchor); if (newAnchor == NULL) outofmem(__FILE__, "HTParentAnchor_new"); newAnchor->parent = parent; /* cross reference */ parent->info = newAnchor; /* cross reference */ newAnchor->address = parent->address; /* copy pointer */ newAnchor->isISMAPScript = FALSE; /* Lynx appends ?0,0 if TRUE. - FM */ newAnchor->isHEAD = FALSE; /* HEAD request if TRUE. - FM */ newAnchor->safe = FALSE; /* Safe. - FM */ newAnchor->no_cache = FALSE; /* no-cache? - FM */ newAnchor->inBASE = FALSE; /* duplicated from HTML.c/h */ newAnchor->content_length = 0; /* Content-Length. - FM */ return(newAnchor);}PRIVATE HTChildAnchor * HTChildAnchor_new ARGS1( HTParentAnchor0 *, parent){ HTChildAnchor *p = typecalloc(HTChildAnchor); if (p == NULL) outofmem(__FILE__, "HTChildAnchor_new"); p->parent = parent; /* parent reference */ return p;}PRIVATE HTChildAnchor * HText_pool_ChildAnchor_new ARGS1( HTParentAnchor *, parent){ HTChildAnchor *p = (HTChildAnchor *)HText_pool_calloc((HText*)(parent->document), sizeof(HTChildAnchor)); if (p == NULL) outofmem(__FILE__, "HText_pool_ChildAnchor_new"); p->parent = parent->parent; /* parent reference */ return p;}#ifdef CASE_INSENSITIVE_ANCHORS/* Case insensitive string comparison */#define HT_EQUIV(a,b) (TOUPPER(a) == TOUPPER(b))#else/* Case sensitive string comparison */#define HT_EQUIV(a,b) ((a) == (b))#endif/* Null-terminated string comparison** ---------------------------------** On entry,** s Points to one string, null terminated** t points to the other.** On exit,** returns YES if the strings are equivalent** NO if they differ.*/PRIVATE BOOL HTSEquivalent ARGS2( CONST char *, s, CONST char *, t){ if (s && t) { /* Make sure they point to something */ for (; *s && *t; s++, t++) { if (!HT_EQUIV(*s, *t)) { return(NO); } } return(HT_EQUIV(*s, *t)); } else { return(s == t); /* Two NULLs are equivalent, aren't they ? */ }}/* Binary string comparison** ------------------------** On entry,** s Points to one bstring** t points to the other.** On exit,** returns YES if the strings are equivalent** NO if they differ.*/PRIVATE BOOL HTBEquivalent ARGS2( CONST bstring *, s, CONST bstring *, t){ if (s && t && BStrLen(s) == BStrLen(t)) { int j; int len = BStrLen(s); for (j = 0; j < len; ++j) { if (!HT_EQUIV(BStrData(s)[j], BStrData(t)[j])) { return(NO); } } return(YES); } else { return(s == t); /* Two NULLs are equivalent, aren't they ? */ }}/* * Three-way compare function */PRIVATE int compare_anchors ARGS2( void *, l, void *, r){ CONST char* a = ((HTChildAnchor *)l)->tag; CONST char* b = ((HTChildAnchor *)r)->tag; /* both tags are not NULL */#ifdef CASE_INSENSITIVE_ANCHORS return strcasecomp(a, b); /* Case insensitive */#else return strcmp(a, b); /* Case sensitive - FM */#endif /* CASE_INSENSITIVE_ANCHORS */}/* Create new or find old sub-anchor** ---------------------------------**** This one is for a named child.** The parent anchor must already exist.*/PRIVATE HTChildAnchor * HTAnchor_findNamedChild ARGS2( HTParentAnchor0 *, parent, CONST char *, tag){ HTChildAnchor *child; if (parent && tag && *tag) { /* TBL */ if (parent->children) { /* ** Parent has children. Search them. */ HTChildAnchor sample; sample.tag = (char*)tag; /* for compare_anchors() only */ child = (HTChildAnchor *)HTBTree_search(parent->children, &sample); if (child != NULL) { CTRACE((tfp, "Child anchor %p of parent %p with name `%s' already exists.\n", (void *)child, (void *)parent, tag)); return(child); } } else { /* parent doesn't have any children yet : create family */ parent->children = HTBTree_new(compare_anchors); } child = HTChildAnchor_new(parent); CTRACE((tfp, "HTAnchor: New Anchor %p named `%s' is child of %p\n", (void *)child, NonNull(tag), (void *)child->parent)); StrAllocCopy(child->tag, tag); /* should be set before HTBTree_add */ HTBTree_add(parent->children, child); return(child); } else { CTRACE((tfp, "HTAnchor_findNamedChild called with NULL parent.\n")); return(NULL); }}/*** This one is for a new unnamed child being edited into an existing** document. The parent anchor and the document must already exist.** (Just add new unnamed child).*/PRIVATE HTChildAnchor * HTAnchor_addChild ARGS1( HTParentAnchor *, parent){ HTChildAnchor *child; if (!parent) { CTRACE((tfp, "HTAnchor_addChild called with NULL parent.\n")); return(NULL); } child = HText_pool_ChildAnchor_new(parent); CTRACE((tfp, "HTAnchor: New unnamed Anchor %p is child of %p\n", (void *)child, (void *)child->parent)); child->tag = 0; HTList_linkObject(&parent->children_notag, child, &child->_add_children_notag); return(child);}PRIVATE HTParentAnchor0 * HTAnchor_findAddress_in_adult_table PARAMS(( CONST DocAddress * newdoc));PRIVATE BOOL HTAnchor_link PARAMS(( HTChildAnchor * child, HTAnchor * destination, HTLinkType * type));/* 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.** (Code originally in ParseHTML.h)*/PUBLIC HTChildAnchor * HTAnchor_findChildAndLink ARGS4( HTParentAnchor *, parent, /* May not be 0 */ CONST char *, tag, /* May be "" or 0 */ CONST char *, href, /* May be "" or 0 */ HTLinkType *, ltype) /* May be 0 */{ HTChildAnchor * child; CTRACE((tfp,"Entered HTAnchor_findChildAndLink: tag=`%s',%s href=`%s'\n", NonNull(tag), (ltype == HTInternalLink) ? " (internal link)" : "", NonNull(href) )); if (tag && *tag) { child = HTAnchor_findNamedChild(parent->parent, tag); } else { child = HTAnchor_addChild(parent); } if (href && *href) { CONST char *fragment = NULL; HTParentAnchor0 * dest; if (ltype == HTInternalLink && *href == '#') { dest = parent->parent; } else { CONST char *relative_to = (parent->inBASE && *href != '#') ? parent->content_base : parent->address; DocAddress parsed_doc; parsed_doc.address = HTParse(href, relative_to, PARSE_ALL_WITHOUT_ANCHOR); parsed_doc.post_data = NULL; parsed_doc.post_content_type = NULL; if (ltype && parent->post_data && ltype == HTInternalLink) { /* for internal links, find a destination with the same post data if the source of the link has post data. - kw Example: LYNXIMGMAP: */ parsed_doc.post_data = parent->post_data; parsed_doc.post_content_type = parent->post_content_type; } parsed_doc.bookmark = NULL; parsed_doc.isHEAD = FALSE; parsed_doc.safe = FALSE; dest = HTAnchor_findAddress_in_adult_table(&parsed_doc); FREE(parsed_doc.address); } /* ** [from HTAnchor_findAddress()] ** If the address represents a sub-anchor, we load its parent (above), ** then we create a named child anchor within that parent. */ fragment = (*href == '#') ? href+1 : HTParseAnchor(href); if (*fragment) dest = (HTParentAnchor0 *)HTAnchor_findNamedChild(dest, fragment); if (tag && *tag) { if (child->dest) { /* DUPLICATE_ANCHOR_NAME_WORKAROUND - kw */ CTRACE((tfp, "*** Duplicate ChildAnchor %p named `%s'", child, tag)); if ((HTAnchor *)dest != child->dest || ltype != child->type) { CTRACE((tfp, ", different dest %p or type, creating unnamed child\n", child->dest)); child = HTAnchor_addChild(parent); } } } HTAnchor_link(child, (HTAnchor *)dest, ltype); } return child;}/* Create new or find old parent 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 HTParentAnchor * HTAnchor_findAddress ARGS1( CONST DocAddress *, newdoc){ /* Anchor tag specified ? */ CONST char *tag = HTParseAnchor(newdoc->address); CTRACE((tfp,"Entered HTAnchor_findAddress\n")); /* ** If the address represents a sub-anchor, we load its parent, ** then we create a named child anchor within that parent. */ if (*tag) { DocAddress parsed_doc; HTParentAnchor0 * foundParent; HTChildAnchor * foundAnchor; parsed_doc.address = HTParse(newdoc->address, "", PARSE_ALL_WITHOUT_ANCHOR); parsed_doc.post_data = newdoc->post_data; parsed_doc.post_content_type = newdoc->post_content_type; parsed_doc.bookmark = newdoc->bookmark; parsed_doc.isHEAD = newdoc->isHEAD; parsed_doc.safe = newdoc->safe; foundParent = HTAnchor_findAddress_in_adult_table(&parsed_doc); foundAnchor = HTAnchor_findNamedChild (foundParent, tag); FREE(parsed_doc.address); return HTAnchor_parent((HTAnchor *)foundParent); } return HTAnchor_parent((HTAnchor *)HTAnchor_findAddress_in_adult_table(newdoc));}/* The address has no anchor tag, for sure. */PRIVATE HTParentAnchor0 * HTAnchor_findAddress_in_adult_table ARGS1( CONST DocAddress *, newdoc){ /* ** Check whether we have this node. */ int hash; HTList * adults; HTList *grownups; HTParentAnchor0 * foundAnchor; BOOL need_extra_info = (newdoc->post_data || newdoc->post_content_type || newdoc->bookmark || newdoc->isHEAD || newdoc->safe); /* * We need not free adult_table[] atexit - * it should be perfectly empty after free'ing all HText's. * (There is an error if it is not empty at exit). -LP */ /* ** Select list from hash table, */ hash = HASH_FUNCTION(newdoc->address); adults = &(adult_table[hash]); /* ** Search list for anchor. */ grownups = adults; while (NULL != (foundAnchor = (HTParentAnchor0 *)HTList_nextObject(grownups))) { if (HTSEquivalent(foundAnchor->address, newdoc->address) && ((!foundAnchor->info && !need_extra_info) || (foundAnchor->info && HTBEquivalent(foundAnchor->info->post_data, newdoc->post_data) && foundAnchor->info->isHEAD == newdoc->isHEAD))) { CTRACE((tfp, "Anchor %p with address `%s' already exists.\n", (void *)foundAnchor, newdoc->address)); return foundAnchor; } } /* ** Node not found: create new anchor. */ foundAnchor = HTParentAnchor0_new(newdoc->address, hash); CTRACE((tfp, "New anchor %p has hash %d and address `%s'\n", (void *)foundAnchor, hash, newdoc->address)); if (need_extra_info) { /* rare case, create a big structure */ HTParentAnchor *p = HTParentAnchor_new(foundAnchor); if (newdoc->post_data) BStrCopy(p->post_data, newdoc->post_data); if (newdoc->post_content_type) StrAllocCopy(p->post_content_type, newdoc->post_content_type); if (newdoc->bookmark) StrAllocCopy(p->bookmark, newdoc->bookmark); p->isHEAD = newdoc->isHEAD; p->safe = newdoc->safe; } HTList_linkObject(adults, foundAnchor, &foundAnchor->_add_adult);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -