Annotation of libwww/Library/src/HTAnchor.c, revision 1.50
1.14 frystyk 1: /* HTAnchor.c
2: ** HYPERTEXT "ANCHOR" OBJECT
1.1 timbl 3: **
1.22 frystyk 4: ** (c) COPYRIGHT MIT 1995.
1.14 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.50 ! frystyk 6: ** @(#) $Id: HTAnchor.c,v 1.49 1996/04/18 01:41:35 frystyk Exp $
1.14 frystyk 7: **
8: ** An anchor represents a region of a hypertext document which is
9: ** linked to another anchor in the same or a different document.
1.1 timbl 10: **
11: ** History
12: ** Nov 1990 Written in Objective-C for the NeXT browser (TBL)
13: ** 24-Oct-1991 (JFG), written in C, browser-independant
14: ** 21-Nov-1991 (JFG), first complete version
1.41 frystyk 15: ** 3-May-1995 (HF), Added a lot of methods and other stuff made an object
1.1 timbl 16: */
17:
1.16 frystyk 18: /* Library include files */
1.46 frystyk 19: #include "sysdep.h"
1.50 ! frystyk 20: #include "WWWUtil.h"
1.7 luotonen 21: #include "HTFormat.h"
1.1 timbl 22: #include "HTParse.h"
1.24 frystyk 23: #include "HTMethod.h"
1.41 frystyk 24: #include "HTAncMan.h" /* Implemented here */
1.11 frystyk 25:
26: #define HASH_SIZE 101 /* Arbitrary prime. Memory/speed tradeoff */
1.1 timbl 27:
28: PRIVATE HTList **adult_table=0; /* Point to table of lists of all parents */
29:
1.17 frystyk 30: /* ------------------------------------------------------------------------- */
31: /* Creation Methods */
32: /* ------------------------------------------------------------------------- */
33:
34: /*
1.1 timbl 35: ** Do not use "new" by itself outside this module. In order to enforce
36: ** consistency, we insist that you furnish more information about the
37: ** anchor you are creating : use newWithParent or newWithAddress.
38: */
1.35 frystyk 39: PRIVATE HTParentAnchor * HTParentAnchor_new (void)
1.1 timbl 40: {
1.43 frystyk 41: HTParentAnchor *newAnchor;
42: if ((newAnchor = (HTParentAnchor *) HT_CALLOC(1, sizeof (HTParentAnchor))) == NULL)
43: HT_OUTOFMEM("HTParentAnchor_new");
1.16 frystyk 44: newAnchor->parent = newAnchor;
1.17 frystyk 45: newAnchor->content_type = WWW_UNKNOWN;
1.24 frystyk 46: newAnchor->mainLink.method = METHOD_INVALID;
1.41 frystyk 47: newAnchor->content_length = -1; /* howcome 6 dec 95 */
1.28 frystyk 48: newAnchor->date = (time_t) -1;
49: newAnchor->expires = (time_t) -1;
50: newAnchor->last_modified = (time_t) -1;
1.16 frystyk 51: return newAnchor;
1.1 timbl 52: }
53:
1.16 frystyk 54:
1.35 frystyk 55: PRIVATE HTChildAnchor * HTChildAnchor_new (void)
1.1 timbl 56: {
1.43 frystyk 57: HTChildAnchor *child;
58: if ((child = (HTChildAnchor *) HT_CALLOC(1, sizeof(HTChildAnchor))) == NULL)
59: HT_OUTOFMEM("HTChildAnchor_new");
1.33 frystyk 60: return child;
1.1 timbl 61: }
62:
63:
1.17 frystyk 64: /* Create new or find old child anchor
65: ** -----------------------------------
1.1 timbl 66: **
1.3 timbl 67: ** Me one is for a new anchor being edited into an existing
1.17 frystyk 68: ** document. The parent anchor must already exist. All
69: ** children without tags (no NAME attribut) points to the same NULL
70: ** child.
1.1 timbl 71: */
1.35 frystyk 72: PUBLIC HTChildAnchor * HTAnchor_findChild (HTParentAnchor * parent,
1.46 frystyk 73: const char * tag)
1.1 timbl 74: {
1.17 frystyk 75: HTChildAnchor *child;
76: HTList *kids;
77:
78: if (!parent) {
79: if (ANCH_TRACE)
1.44 eric 80: HTTrace("Find Child.. called with NULL parent.\n");
1.17 frystyk 81: return NULL;
82: }
1.1 timbl 83:
1.17 frystyk 84: /* First search list of children to see if tag is already there */
85: if ((kids = parent->children)) {
86: if (tag && *tag) { /* TBL */
87: while ((child = (HTChildAnchor *) HTList_nextObject(kids))) {
1.33 frystyk 88: if (child->tag && !strcmp(child->tag, tag)) {
1.17 frystyk 89: if (ANCH_TRACE)
1.44 eric 90: HTTrace(
1.17 frystyk 91: "Find Child.. %p of parent %p with name `%s' already exists.\n",
92: (void *) child, (void *) parent, tag);
93: return child;
94: }
1.1 timbl 95: }
96: }
1.17 frystyk 97: } else /* Create new list of children */
98: parent->children = HTList_new ();
99:
100: /* Did't find it so we need to create a new one */
101: child = HTChildAnchor_new();
102: HTList_addObject(parent->children, child);
103: child->parent = parent;
104: StrAllocCopy(child->tag, tag);
105: if (ANCH_TRACE)
1.44 eric 106: HTTrace("Find Child.. New Anchor %p named `%s' is child of %p\n",
1.46 frystyk 107: (void *) child, tag ? tag : (const char *) "", (void *)parent);
1.17 frystyk 108: return child;
1.1 timbl 109: }
110:
111:
112: /* Create new or find old named anchor
113: ** -----------------------------------
114: **
1.3 timbl 115: ** Me one is for a reference which is found in a document, and might
1.1 timbl 116: ** not be already loaded.
117: ** Note: You are not guaranteed a new anchor -- you might get an old one,
118: ** like with fonts.
119: */
1.46 frystyk 120: PUBLIC HTAnchor * HTAnchor_findAddress (const char * address)
1.1 timbl 121: {
1.16 frystyk 122: char *tag = HTParse (address, "", PARSE_ANCHOR); /* Any tags? */
1.1 timbl 123:
1.16 frystyk 124: /* If the address represents a sub-anchor, we recursively load its parent,
125: then we create a child anchor within that document. */
126: if (*tag) {
1.34 frystyk 127: char *addr = HTParse(address, "", PARSE_ACCESS | PARSE_HOST |
128: PARSE_PATH | PARSE_PUNCTUATION);
129: HTParentAnchor * parent = (HTParentAnchor*) HTAnchor_findAddress(addr);
130: HTChildAnchor * child = HTAnchor_findChild(parent, tag);
1.43 frystyk 131: HT_FREE(addr);
132: HT_FREE(tag);
1.34 frystyk 133: return (HTAnchor *) child;
1.16 frystyk 134: } else { /* Else check whether we have this node */
135: int hash;
1.46 frystyk 136: const char *p;
1.16 frystyk 137: HTList * adults;
138: HTList *grownups;
139: HTParentAnchor * foundAnchor;
1.34 frystyk 140: char *newaddr = NULL;
141: StrAllocCopy(newaddr, address); /* Get our own copy */
1.43 frystyk 142: HT_FREE(tag);
1.38 frystyk 143: newaddr = HTSimplify(&newaddr);
1.34 frystyk 144:
1.16 frystyk 145: /* Select list from hash table */
146: for(p=newaddr, hash=0; *p; p++)
147: hash = (int) ((hash * 3 + (*(unsigned char*)p)) % HASH_SIZE);
1.33 frystyk 148: if (!adult_table) {
1.43 frystyk 149: if ((adult_table = (HTList* *) HT_CALLOC(HASH_SIZE, sizeof(HTList*))) == NULL)
150: HT_OUTOFMEM("HTAnchor_findAddress");
1.33 frystyk 151: }
1.16 frystyk 152: if (!adult_table[hash]) adult_table[hash] = HTList_new();
153: adults = adult_table[hash];
154:
155: /* Search list for anchor */
156: grownups = adults;
157: while ((foundAnchor = (HTParentAnchor *) HTList_nextObject(grownups))){
1.33 frystyk 158: if (!strcmp(foundAnchor->address, newaddr)) {
1.16 frystyk 159: if (ANCH_TRACE)
1.44 eric 160: HTTrace("Find Parent. %p with address `%s' already exists.\n",
1.16 frystyk 161: (void*) foundAnchor, newaddr);
1.43 frystyk 162: HT_FREE(newaddr); /* We already have it */
1.16 frystyk 163: return (HTAnchor *) foundAnchor;
164: }
165: }
166:
167: /* Node not found : create new anchor. */
168: foundAnchor = HTParentAnchor_new();
169: foundAnchor->address = newaddr; /* Remember our copy */
170: HTList_addObject (adults, foundAnchor);
1.44 eric 171: if (ANCH_TRACE) HTTrace("Find Parent. %p with hash %d and address `%s' created\n", (void*)foundAnchor, hash, newaddr);
1.1 timbl 172: return (HTAnchor *) foundAnchor;
173: }
174: }
175:
1.17 frystyk 176: /* Create or find a child anchor with a possible link
177: ** --------------------------------------------------
178: **
179: ** Create new anchor with a given parent and possibly
180: ** a name, and possibly a link to a _relatively_ named anchor.
1.34 frystyk 181: ** All parameters EXCEPT parent can be NULL
1.17 frystyk 182: */
1.34 frystyk 183: PUBLIC HTChildAnchor * HTAnchor_findChildAndLink (HTParentAnchor * parent,
1.46 frystyk 184: const char * tag,
185: const char * href,
1.41 frystyk 186: HTLinkType ltype)
1.17 frystyk 187: {
1.34 frystyk 188: HTChildAnchor * child = HTAnchor_findChild(parent, tag);
189: if (href && *href) {
190: char * relative_to = HTAnchor_address((HTAnchor *) parent);
191: char * parsed_address = HTParse(href, relative_to, PARSE_ALL);
192: HTAnchor * dest = HTAnchor_findAddress(parsed_address);
193: HTAnchor_link((HTAnchor *) child, dest, ltype, METHOD_INVALID);
1.43 frystyk 194: HT_FREE(parsed_address);
195: HT_FREE(relative_to);
1.34 frystyk 196: }
197: return child;
1.17 frystyk 198: }
199:
1.41 frystyk 200: /* ------------------------------------------------------------------------- */
201: /* Link Methods */
202: /* ------------------------------------------------------------------------- */
203:
204: /*
205: ** Link destinations
206: */
207: PUBLIC BOOL HTLink_setDestination (HTLink * link, HTAnchor * dest)
208: {
209: if (link) {
210: link->dest = dest;
211: return YES;
212: }
213: return NO;
214: }
215:
216: PUBLIC HTAnchor * HTLink_destination (HTLink * link)
217: {
218: return link ? link->dest : NULL;
219: }
220:
221: PUBLIC BOOL HTLink_setType (HTLink * link, HTLinkType type)
222: {
223: if (link) {
224: link->type = type;
225: return YES;
226: }
227: return NO;
228: }
229:
230: PUBLIC HTLinkType HTLink_type (HTLink * link)
231: {
232: return link ? link->type : NULL;
233: }
234:
235: /*
236: ** When a link has been used for posting an object from a source to a
237: ** destination link, the result of the operation is stored as part of the
238: ** link information.
239: */
240: PUBLIC BOOL HTLink_setResult (HTLink * link, HTLinkResult result)
241: {
242: if (link) {
243: link->result = result;
244: return YES;
245: }
246: return NO;
247: }
248:
249: PUBLIC HTLinkResult HTLink_result (HTLink * link)
250: {
251: return link ? link->result : HT_LINK_INVALID;
252: }
253:
254: PUBLIC BOOL HTLink_setMethod (HTLink * link, HTMethod method)
255: {
256: if (link) {
257: link->method = method;
258: return YES;
259: }
260: return NO;
261: }
262:
263: PUBLIC HTMethod HTLink_method (HTLink * link)
264: {
265: return link ? link->method : METHOD_INVALID;
266: }
267:
1.17 frystyk 268: /* Link me Anchor to another given one
269: ** -------------------------------------
270: */
1.35 frystyk 271: PUBLIC BOOL HTAnchor_link (HTAnchor * source,
272: HTAnchor * destination,
1.41 frystyk 273: HTLinkType type,
1.35 frystyk 274: HTMethod method)
1.17 frystyk 275: {
276: if (!(source && destination))
277: return NO; /* Can't link to/from non-existing anchor */
278: if (ANCH_TRACE)
1.44 eric 279: HTTrace("Link Anchors anchor %p to anchor %p\n",
1.17 frystyk 280: (void *) source, (void *) destination);
281: if (!source->mainLink.dest) {
282: source->mainLink.dest = destination;
283: source->mainLink.type = type;
1.24 frystyk 284: source->mainLink.method = method;
1.17 frystyk 285: } else {
1.43 frystyk 286: HTLink * newLink;
287: if ((newLink = (HTLink *) HT_CALLOC(1, sizeof (HTLink))) == NULL)
288: HT_OUTOFMEM("HTAnchor_link");
1.17 frystyk 289: newLink->dest = destination;
290: newLink->type = type;
1.24 frystyk 291: newLink->method = method;
292: if (!source->links)
293: source->links = HTList_new();
1.17 frystyk 294: HTList_addObject (source->links, newLink);
295: }
296: if (!destination->parent->sources)
297: destination->parent->sources = HTList_new ();
298: HTList_addObject (destination->parent->sources, source);
299: return YES;
300: }
301:
1.24 frystyk 302: /*
1.28 frystyk 303: ** Find the anchor object between a destination and a source ancher.
304: ** Return link object if any, else NULL
305: */
1.41 frystyk 306: PUBLIC HTLink * HTAnchor_findLink (HTAnchor * src, HTAnchor * dest)
1.28 frystyk 307: {
308: if (src && dest) {
309: if (src->mainLink.dest == dest)
310: return &(src->mainLink);
311: if (src->links) {
312: HTList *cur = src->links;
313: HTLink *pres;
314: while ((pres = (HTLink *) HTList_nextObject(cur)) != NULL) {
315: if (pres->dest == dest)
316: return pres;
317: }
318: }
319: }
320: return NULL;
321: }
322:
1.41 frystyk 323: /*
324: ** Upgrade the link to the main destination and and downgrade the
325: ** current main link to the list
326: */
327: PUBLIC HTLink * HTAnchor_mainLink (HTAnchor * me)
328: {
329: return me ? &(me->mainLink) : NULL;
330: }
1.28 frystyk 331:
1.41 frystyk 332: PUBLIC BOOL HTAnchor_setMainLink (HTAnchor * me, HTLink * movingLink)
1.28 frystyk 333: {
1.41 frystyk 334: if (!(me && me->links && movingLink &&
335: HTList_removeObject(me->links, movingLink)))
336: return NO;
337: else {
338: /* First push current main link onto top of links list */
1.43 frystyk 339: HTLink *newLink;
340: if ((newLink = (HTLink *) HT_MALLOC(sizeof (HTLink))) == NULL)
341: HT_OUTOFMEM("HTAnchor_makeMainLink");
1.42 frystyk 342: memcpy ((void *) newLink, & me->mainLink, sizeof (HTLink));
1.41 frystyk 343: HTList_addObject (me->links, newLink);
344:
1.46 frystyk 345: /* Now make movingLink the new main link, and HT_FREE it */
1.42 frystyk 346: memcpy ((void *) &me->mainLink, movingLink, sizeof (HTLink));
1.43 frystyk 347: HT_FREE(movingLink);
1.28 frystyk 348: return YES;
349: }
350: }
351:
352: /*
1.41 frystyk 353: ** Handling sub links
1.24 frystyk 354: */
1.41 frystyk 355: PUBLIC HTList * HTAnchor_subLinks (HTAnchor * anchor)
1.24 frystyk 356: {
1.41 frystyk 357: return anchor ? anchor->links : NULL;
1.24 frystyk 358: }
359:
1.41 frystyk 360: PUBLIC BOOL HTAnchor_setSubLinks (HTAnchor * anchor, HTList * list)
361: {
362: if (anchor) {
363: anchor->links = list;
364: return YES;
365: }
366: return NO;
367: }
1.24 frystyk 368:
369: /*
370: ** Returns the methods registered for the main destination of this
371: ** anchor
1.17 frystyk 372: */
1.35 frystyk 373: PUBLIC HTMethod HTAnchor_mainLinkMethod (HTAnchor * me)
1.24 frystyk 374: {
375: return me ? me->mainLink.method : METHOD_INVALID;
376: }
377:
1.41 frystyk 378: /*
379: ** Returns the main destination of this anchor
380: */
381: PUBLIC HTAnchor * HTAnchor_followMainLink (HTAnchor * me)
382: {
383: return me ? me->mainLink.dest : NULL;
384: }
1.17 frystyk 385:
1.24 frystyk 386: /*
387: ** Moves all link information from one anchor to another.
388: ** This is used in redirection etc.
389: ** Returns YES if OK, else NO
390: */
1.35 frystyk 391: PUBLIC BOOL HTAnchor_moveAllLinks (HTAnchor * src, HTAnchor * dest)
1.17 frystyk 392: {
1.24 frystyk 393: if (!src || !dest) return NO;
394: if (ANCH_TRACE)
1.44 eric 395: HTTrace("Move Links.. from anchor %p to anchor %p\n",
1.24 frystyk 396: (void *) src, (void *) dest);
397:
398: /* Move main link information */
399: dest->mainLink.dest = src->mainLink.dest;
400: dest->mainLink.type = src->mainLink.type;
401: dest->mainLink.method = src->mainLink.method;
1.25 frystyk 402: dest->mainLink.result = src->mainLink.result;
1.24 frystyk 403:
404: src->mainLink.dest = NULL;
405: src->mainLink.type = NULL;
1.25 frystyk 406: src->mainLink.method = METHOD_INVALID;
1.28 frystyk 407: src->mainLink.result = HT_LINK_INVALID;
1.24 frystyk 408:
409: /* Move link information for other links */
1.26 frystyk 410: if (dest->links) {
411: HTList *cur = dest->links;
412: HTLink *pres;
413: while ((pres = (HTLink *) HTList_nextObject(cur)))
1.43 frystyk 414: HT_FREE(pres);
1.24 frystyk 415: HTList_delete(dest->links);
1.26 frystyk 416: }
1.24 frystyk 417: dest->links = src->links;
418: src->links = NULL;
419: return YES;
1.17 frystyk 420: }
421:
1.24 frystyk 422:
423: /*
1.28 frystyk 424: ** Removes all link information from one anchor to another.
425: ** Returns YES if OK, else NO
426: */
1.35 frystyk 427: PUBLIC BOOL HTAnchor_removeLink (HTAnchor * src, HTAnchor * dest)
1.28 frystyk 428: {
429: if (!src || !dest) return NO;
430: if (ANCH_TRACE)
1.44 eric 431: HTTrace("Remove Link. from anchor %p to anchor %p\n",
1.28 frystyk 432: (void *) src, (void *) dest);
433:
434: /* Remove if dest is the main link */
435: if (src->mainLink.dest == dest) {
436: src->mainLink.dest = NULL;
437: src->mainLink.type = NULL;
438: src->mainLink.method = METHOD_INVALID;
439: src->mainLink.result = HT_LINK_INVALID;
440: return YES;
441: }
442:
443: /* Remove link information for other links */
444: if (dest->links) {
445: HTList *cur = dest->links;
446: HTLink *pres;
447: while ((pres = (HTLink *) HTList_nextObject(cur))) {
448: if (pres->dest == dest) {
449: HTList_removeObject(dest->links, pres);
1.43 frystyk 450: HT_FREE(pres);
1.28 frystyk 451: return YES;
452: }
453: }
454: }
455: return NO;
456: }
457:
458: /*
459: ** Removes all link information
460: ** Returns YES if OK, else NO
461: */
1.35 frystyk 462: PUBLIC BOOL HTAnchor_removeAllLinks (HTAnchor * me)
1.28 frystyk 463: {
464: if (!me) return NO;
465: if (ANCH_TRACE)
1.44 eric 466: HTTrace("Remove Link. from anchor %p\n", (void *) me);
1.28 frystyk 467:
468: /* Remove if dest is the main link */
469: me->mainLink.dest = NULL;
470: me->mainLink.type = NULL;
471: me->mainLink.method = METHOD_INVALID;
472: me->mainLink.result = HT_LINK_INVALID;
473:
474: /* Remove link information for other links */
475: if (me->links) {
476: HTList *cur = me->links;
477: HTLink *pres;
478: while ((pres = (HTLink *) HTList_nextObject(cur)))
1.43 frystyk 479: HT_FREE(pres);
1.28 frystyk 480: HTList_delete(me->links);
481: me->links = NULL;
482: }
483: return YES;
484: }
485:
486: /*
1.24 frystyk 487: ** Returns a link with a given link type or NULL if nothing found
488: */
1.41 frystyk 489: PUBLIC HTAnchor * HTAnchor_followTypedLink (HTAnchor * me, HTLinkType type)
1.17 frystyk 490: {
1.24 frystyk 491: if (me->mainLink.type == type)
492: return me->mainLink.dest;
493: if (me->links) {
494: HTList *links = me->links;
495: HTLink *link;
496: while ((link = (HTLink *) HTList_nextObject (links)))
497: if (link->type == type)
498: return link->dest;
499: }
500: return NULL; /* No link of me type */
1.17 frystyk 501: }
502:
503:
504: /* Move an anchor to the head of the list of its siblings
505: ** ------------------------------------------------------
506: **
507: ** This is to ensure that an anchor which might have already existed
508: ** is put in the correct order as we load the document.
509: */
1.35 frystyk 510: PUBLIC void HTAnchor_makeLastChild (HTChildAnchor * me)
1.17 frystyk 511: {
1.35 frystyk 512: if (me->parent != (HTParentAnchor *) me) { /* Make sure it's a child */
513: HTList * siblings = me->parent->children;
514: HTList_removeObject (siblings, me);
515: HTList_addObject (siblings, me);
516: }
1.17 frystyk 517: }
518:
519: /* ------------------------------------------------------------------------- */
520: /* Deletion Methods */
521: /* ------------------------------------------------------------------------- */
1.1 timbl 522:
523: /* Delete an anchor and possibly related things (auto garbage collection)
524: ** --------------------------------------------
525: **
526: ** The anchor is only deleted if the corresponding document is not loaded.
1.10 frystyk 527: ** All outgoing links from parent and children are deleted, and this
528: ** anchor is removed from the sources list of all its targets.
1.1 timbl 529: ** We also try to delete the targets whose documents are not loaded.
530: ** If this anchor's source list is empty, we delete it and its children.
531: */
532:
1.41 frystyk 533: /* Deletes all the memory allocated in a parent anchor and returns any
534: ** hyperdoc object hanging of this anchor
1.19 frystyk 535: */
1.41 frystyk 536: PRIVATE void * delete_parent (HTParentAnchor * me)
1.19 frystyk 537: {
1.41 frystyk 538: void * doc = me->document;
1.19 frystyk 539:
540: /* Remove link and address information */
1.26 frystyk 541: if (me->links) {
542: HTList *cur = me->links;
543: HTLink *pres;
544: while ((pres = (HTLink *) HTList_nextObject(cur)))
1.43 frystyk 545: HT_FREE(pres);
1.26 frystyk 546: HTList_delete(me->links);
547: }
1.19 frystyk 548: HTList_delete (me->children);
549: HTList_delete (me->sources);
1.43 frystyk 550: HT_FREE(me->physical);
551: HT_FREE(me->address);
1.19 frystyk 552:
553: /* Then remove entity header information (metainformation) */
1.43 frystyk 554: HT_FREE(me->title);
1.47 frystyk 555: if (me->content_encoding) HTList_delete(me->content_encoding);
556: if (me->content_language) HTList_delete(me->content_language);
1.43 frystyk 557: HT_FREE(me->derived_from);
558: HT_FREE(me->version);
1.19 frystyk 559: if (me->extra_headers) {
560: HTList *cur = me->extra_headers;
561: char *pres;
562: while ((pres = (char *) HTList_nextObject(cur)))
1.43 frystyk 563: HT_FREE(pres);
1.19 frystyk 564: HTList_delete(me->extra_headers);
565: }
1.43 frystyk 566: HT_FREE(me);
1.19 frystyk 567: return doc;
568: }
569:
570:
1.41 frystyk 571: /* Delete a parent anchor and all its children. If a hyperdoc object
572: ** is found hanging off the parent anchor then this is returned
1.19 frystyk 573: */
1.41 frystyk 574: PRIVATE void * delete_family (HTAnchor * me)
1.19 frystyk 575: {
576: HTParentAnchor *parent = me->parent;
577: if (ANCH_TRACE)
1.44 eric 578: HTTrace("AnchorDelete Remove parent %p and children\n", parent);
1.19 frystyk 579: if (!me) {
580: if (ANCH_TRACE)
1.44 eric 581: HTTrace("AnchorDelete No anchor found\n");
1.19 frystyk 582: return NULL;
583: }
584:
585: /* Delete children */
586: if (parent->children) {
587: HTChildAnchor *child;
588: while ((child = (HTChildAnchor *)
589: HTList_removeLastObject(parent->children))) {
1.43 frystyk 590: HT_FREE(child->tag);
1.26 frystyk 591: if (child->links) {
592: HTList *cur = child->links;
593: HTLink *pres;
594: while ((pres = (HTLink *) HTList_nextObject(cur)))
1.43 frystyk 595: HT_FREE(pres);
1.26 frystyk 596: HTList_delete(child->links);
597: }
1.43 frystyk 598: HT_FREE(child);
1.19 frystyk 599: }
600: }
601: return delete_parent(parent);
602: }
603:
604:
605: /* DELETE ALL ANCHORS
606: ** ------------------
607: ** Deletes all anchors and return a list of all the HyperDocs found.
608: ** It is for the application to delete any HyperDocs.
1.39 frystyk 609: ** If NULL then no hyperdocs are returned
1.19 frystyk 610: ** Return YES if OK, else NO
611: */
1.35 frystyk 612: PUBLIC BOOL HTAnchor_deleteAll (HTList * documents)
1.19 frystyk 613: {
614: int cnt;
615: HTList *cur;
1.39 frystyk 616: if (!adult_table)
1.19 frystyk 617: return NO;
618: for (cnt=0; cnt<HASH_SIZE; cnt++) {
619: if ((cur = adult_table[cnt])) {
620: HTParentAnchor *pres;
621: while ((pres = (HTParentAnchor *) HTList_nextObject(cur)) != NULL){
1.41 frystyk 622: void * doc = delete_family((HTAnchor *) pres);
623: if (doc && documents) HTList_addObject(documents, doc);
1.19 frystyk 624: }
625: }
626: HTList_delete(adult_table[cnt]);
627: }
1.43 frystyk 628: HT_FREE(adult_table);
1.19 frystyk 629: return YES;
630: }
631:
632:
1.35 frystyk 633: PRIVATE void deleteLinks (HTAnchor * me)
1.1 timbl 634: {
1.3 timbl 635: if (! me)
1.1 timbl 636: return;
637:
638: /* Recursively try to delete target anchors */
1.3 timbl 639: if (me->mainLink.dest) {
640: HTParentAnchor *parent = me->mainLink.dest->parent;
641: HTList_removeObject (parent->sources, me);
1.1 timbl 642: if (! parent->document) /* Test here to avoid calling overhead */
643: HTAnchor_delete (parent);
644: }
1.3 timbl 645: if (me->links) { /* Extra destinations */
1.1 timbl 646: HTLink *target;
1.12 frystyk 647: while ((target = (HTLink *) HTList_removeLastObject (me->links))) {
1.1 timbl 648: HTParentAnchor *parent = target->dest->parent;
1.3 timbl 649: HTList_removeObject (parent->sources, me);
1.1 timbl 650: if (! parent->document) /* Test here to avoid calling overhead */
651: HTAnchor_delete (parent);
652: }
653: }
654: }
655:
1.35 frystyk 656: PUBLIC BOOL HTAnchor_delete (HTParentAnchor * me)
1.1 timbl 657: {
658: HTChildAnchor *child;
659:
660: /* Don't delete if document is loaded */
1.3 timbl 661: if (me->document)
1.1 timbl 662: return NO;
663:
664: /* Recursively try to delete target anchors */
1.3 timbl 665: deleteLinks ((HTAnchor *) me);
1.1 timbl 666:
1.3 timbl 667: if (! HTList_isEmpty (me->sources)) { /* There are still incoming links */
1.1 timbl 668: /* Delete all outgoing links from children, if any */
1.3 timbl 669: HTList *kids = me->children;
1.12 frystyk 670: while ((child = (HTChildAnchor *) HTList_nextObject (kids)))
1.1 timbl 671: deleteLinks ((HTAnchor *) child);
672: return NO; /* Parent not deleted */
673: }
674:
675: /* No more incoming links : kill everything */
676: /* First, recursively delete children */
1.12 frystyk 677: while ((child = (HTChildAnchor *) HTList_removeLastObject (me->children))) {
1.1 timbl 678: deleteLinks ((HTAnchor *) child);
1.43 frystyk 679: HT_FREE(child->tag);
680: HT_FREE(child);
1.1 timbl 681: }
682:
683: /* Now kill myself */
1.19 frystyk 684: delete_parent(me);
1.1 timbl 685: return YES; /* Parent deleted */
686: }
687:
1.17 frystyk 688: /* ------------------------------------------------------------------------- */
689: /* Data Access Methods */
690: /* ------------------------------------------------------------------------- */
1.1 timbl 691:
1.35 frystyk 692: PUBLIC HTParentAnchor * HTAnchor_parent (HTAnchor * me)
1.1 timbl 693: {
1.17 frystyk 694: return me ? me->parent : NULL;
1.1 timbl 695: }
696:
1.41 frystyk 697: PUBLIC void HTAnchor_setDocument (HTParentAnchor * me, void * doc)
1.1 timbl 698: {
1.41 frystyk 699: if (me) me->document = doc;
1.1 timbl 700: }
701:
1.41 frystyk 702: PUBLIC void * HTAnchor_document (HTParentAnchor * me)
1.1 timbl 703: {
1.17 frystyk 704: return me ? me->document : NULL;
1.1 timbl 705: }
706:
1.35 frystyk 707: PUBLIC char * HTAnchor_address (HTAnchor * me)
1.1 timbl 708: {
1.17 frystyk 709: char *addr = NULL;
710: if (me) {
711: if (((HTParentAnchor *) me == me->parent) ||
712: !((HTChildAnchor *) me)->tag) { /* it's an adult or no tag */
713: StrAllocCopy (addr, me->parent->address);
714: }
715: else { /* it's a named child */
1.43 frystyk 716: if ((addr = (char *) HT_MALLOC(2 + strlen (me->parent->address) + strlen (((HTChildAnchor *) me)->tag))) == NULL)
717: HT_OUTOFMEM("HTAnchor_address");
1.17 frystyk 718: sprintf (addr, "%s#%s", me->parent->address,
719: ((HTChildAnchor *) me)->tag);
720: }
1.1 timbl 721: }
1.17 frystyk 722: return addr;
1.1 timbl 723: }
724:
1.35 frystyk 725: PUBLIC BOOL HTAnchor_hasChildren (HTParentAnchor * me)
1.17 frystyk 726: {
727: return me ? ! HTList_isEmpty(me->children) : NO;
728: }
1.1 timbl 729:
1.35 frystyk 730: PUBLIC void HTAnchor_clearIndex (HTParentAnchor * me)
1.17 frystyk 731: {
1.36 frystyk 732: if (me) me->isIndex = NO;
1.17 frystyk 733: }
1.1 timbl 734:
1.35 frystyk 735: PUBLIC void HTAnchor_setIndex (HTParentAnchor * me)
1.1 timbl 736: {
1.36 frystyk 737: if (me) me->isIndex = YES;
1.17 frystyk 738: }
739:
1.35 frystyk 740: PUBLIC BOOL HTAnchor_isIndex (HTParentAnchor * me)
1.17 frystyk 741: {
742: return me ? me->isIndex : NO;
1.9 frystyk 743: }
1.1 timbl 744:
1.17 frystyk 745: /* Physical Address
746: ** ----------------
747: */
748:
1.35 frystyk 749: PUBLIC char * HTAnchor_physical (HTParentAnchor * me)
1.1 timbl 750: {
1.36 frystyk 751: return me ? me->physical : NULL;
1.1 timbl 752: }
753:
1.35 frystyk 754: PUBLIC void HTAnchor_setPhysical (HTParentAnchor * me,
755: char * physical)
1.1 timbl 756: {
1.17 frystyk 757: if (!me || !physical) {
758: if (ANCH_TRACE)
1.44 eric 759: HTTrace("HTAnchor.... setPhysical, called with null argument\n");
1.17 frystyk 760: return;
761: }
762: StrAllocCopy(me->physical, physical);
1.27 frystyk 763: }
764:
765: /* Cache Information
766: ** -----------------
767: */
1.35 frystyk 768: PUBLIC BOOL HTAnchor_cacheHit (HTParentAnchor * me)
1.27 frystyk 769: {
1.36 frystyk 770: return me ? me->cacheHit : NO;
1.27 frystyk 771: }
772:
1.35 frystyk 773: PUBLIC void HTAnchor_setCacheHit (HTParentAnchor * me, BOOL cacheHit)
1.27 frystyk 774: {
1.36 frystyk 775: if (me) me->cacheHit = cacheHit;
1.1 timbl 776: }
777:
1.17 frystyk 778: /* ------------------------------------------------------------------------- */
779: /* Entity Header Information */
780: /* ------------------------------------------------------------------------- */
781:
782: /*
783: ** Media Types (Content-Type)
784: */
1.35 frystyk 785: PUBLIC HTFormat HTAnchor_format (HTParentAnchor * me)
1.17 frystyk 786: {
787: return me ? me->content_type : NULL;
788: }
1.1 timbl 789:
1.35 frystyk 790: PUBLIC void HTAnchor_setFormat (HTParentAnchor * me, HTFormat form)
1.1 timbl 791: {
1.17 frystyk 792: if (me) me->content_type = form;
1.1 timbl 793: }
794:
1.17 frystyk 795: /*
796: ** Charset parameter to Content-Type
1.1 timbl 797: */
1.35 frystyk 798: PUBLIC HTCharset HTAnchor_charset (HTParentAnchor * me)
1.1 timbl 799: {
1.17 frystyk 800: return me ? me->charset : NULL;
1.1 timbl 801: }
802:
1.35 frystyk 803: PUBLIC void HTAnchor_setCharset (HTParentAnchor * me, HTCharset charset)
1.1 timbl 804: {
1.17 frystyk 805: if (me) me->charset = charset;
1.1 timbl 806: }
807:
1.17 frystyk 808: /*
1.20 frystyk 809: ** Level parameter to Content-Type
810: */
1.35 frystyk 811: PUBLIC HTLevel HTAnchor_level (HTParentAnchor * me)
1.20 frystyk 812: {
813: return me ? me->level : NULL;
814: }
815:
1.35 frystyk 816: PUBLIC void HTAnchor_setLevel (HTParentAnchor * me, HTLevel level)
1.20 frystyk 817: {
818: if (me) me->level = level;
819: }
820:
821: /*
1.17 frystyk 822: ** Content Encoding
823: */
1.47 frystyk 824: PUBLIC HTList * HTAnchor_encoding (HTParentAnchor * me)
1.1 timbl 825: {
1.17 frystyk 826: return me ? me->content_encoding : NULL;
1.1 timbl 827: }
828:
1.47 frystyk 829: PUBLIC BOOL HTAnchor_addEncoding (HTParentAnchor * me, HTEncoding encoding)
1.17 frystyk 830: {
1.47 frystyk 831: if (me && encoding) {
832: if (!me->content_encoding) me->content_encoding = HTList_new();
833: return HTList_addObject(me->content_encoding, encoding);
834: }
835: return NO;
1.17 frystyk 836: }
837:
838: /*
1.21 frystyk 839: ** Content Language
840: */
1.47 frystyk 841: PUBLIC HTList * HTAnchor_language (HTParentAnchor * me)
1.21 frystyk 842: {
843: return me ? me->content_language : NULL;
844: }
845:
1.47 frystyk 846: PUBLIC BOOL HTAnchor_addLanguage (HTParentAnchor * me, HTLanguage language)
1.21 frystyk 847: {
1.47 frystyk 848: if (me && language) {
849: if (!me->content_language) me->content_language = HTList_new();
850: return HTList_addObject(me->content_language, language);
851: }
852: return NO;
1.21 frystyk 853: }
854:
855: /*
1.17 frystyk 856: ** Content Transfer Encoding
1.1 timbl 857: */
1.48 frystyk 858: PUBLIC HTEncoding HTAnchor_transfer (HTParentAnchor * me)
1.17 frystyk 859: {
1.48 frystyk 860: return me ? me->transfer : NULL;
1.17 frystyk 861: }
1.1 timbl 862:
1.48 frystyk 863: PUBLIC void HTAnchor_setTransfer (HTParentAnchor * me, HTEncoding transfer)
1.17 frystyk 864: {
1.48 frystyk 865: if (me) me->transfer = transfer;
1.17 frystyk 866: }
867:
868: /*
869: ** Content Length
870: */
1.35 frystyk 871: PUBLIC long int HTAnchor_length (HTParentAnchor * me)
1.1 timbl 872: {
1.17 frystyk 873: return me ? me->content_length : -1;
1.1 timbl 874: }
875:
1.35 frystyk 876: PUBLIC void HTAnchor_setLength (HTParentAnchor * me, long int length)
1.17 frystyk 877: {
878: if (me) me->content_length = length;
879: }
1.1 timbl 880:
1.49 frystyk 881: PUBLIC void HTAnchor_addLength (HTParentAnchor * me, long int deltalength)
882: {
883: if (me) {
884: if (me->content_length < 0)
885: me->content_length = deltalength;
886: else
887: me->content_length += deltalength;
888: }
889: }
890:
1.17 frystyk 891: /*
892: ** Allowed methods (Allow)
1.1 timbl 893: */
1.45 frystyk 894: PUBLIC HTMethod HTAnchor_methods (HTParentAnchor * me)
1.17 frystyk 895: {
1.32 frystyk 896: return me ? me->methods : METHOD_INVALID;
1.17 frystyk 897: }
1.1 timbl 898:
1.45 frystyk 899: PUBLIC void HTAnchor_setMethods (HTParentAnchor * me, HTMethod methodset)
1.1 timbl 900: {
1.17 frystyk 901: if (me) me->methods = methodset;
1.1 timbl 902: }
903:
1.45 frystyk 904: PUBLIC void HTAnchor_appendMethods (HTParentAnchor * me, HTMethod methodset)
1.1 timbl 905: {
1.32 frystyk 906: if (me) me->methods |= methodset;
1.1 timbl 907: }
908:
1.17 frystyk 909: /*
910: ** Title
1.2 timbl 911: */
1.46 frystyk 912: PUBLIC const char * HTAnchor_title (HTParentAnchor * me)
1.1 timbl 913: {
1.17 frystyk 914: return me ? me->title : NULL;
915: }
1.1 timbl 916:
1.46 frystyk 917: PUBLIC void HTAnchor_setTitle (HTParentAnchor * me, const char * title)
1.17 frystyk 918: {
919: if (me && title) StrAllocCopy(me->title, title);
1.2 timbl 920: }
921:
1.46 frystyk 922: PUBLIC void HTAnchor_appendTitle (HTParentAnchor * me, const char * title)
1.17 frystyk 923: {
924: if (me && title) StrAllocCat(me->title, title);
925: }
1.2 timbl 926:
1.17 frystyk 927: /*
928: ** Version
1.2 timbl 929: */
1.41 frystyk 930: PUBLIC char * HTAnchor_version (HTParentAnchor * me)
1.17 frystyk 931: {
932: return me ? me->version : NULL;
933: }
1.2 timbl 934:
1.46 frystyk 935: PUBLIC void HTAnchor_setVersion (HTParentAnchor * me, const char * version)
1.2 timbl 936: {
1.17 frystyk 937: if (me && version) StrAllocCopy(me->version, version);
1.2 timbl 938: }
939:
1.17 frystyk 940: /*
941: ** Derived from
1.2 timbl 942: */
1.41 frystyk 943: PUBLIC char * HTAnchor_derived (HTParentAnchor * me)
1.17 frystyk 944: {
945: return me ? me->derived_from : NULL;
946: }
947:
1.46 frystyk 948: PUBLIC void HTAnchor_setDerived (HTParentAnchor * me, const char *derived_from)
1.17 frystyk 949: {
950: if (me && derived_from) StrAllocCopy(me->derived_from, derived_from);
951: }
1.2 timbl 952:
1.17 frystyk 953: /*
1.28 frystyk 954: ** Date
955: */
1.41 frystyk 956: PUBLIC time_t HTAnchor_date (HTParentAnchor * me)
957: {
958: return me ? me->date : -1;
959: }
960:
1.46 frystyk 961: PUBLIC void HTAnchor_setDate (HTParentAnchor * me, const time_t date)
1.28 frystyk 962: {
1.41 frystyk 963: if (me) me->date = date;
1.28 frystyk 964: }
965:
966: /*
967: ** Expires
968: */
1.41 frystyk 969: PUBLIC time_t HTAnchor_expires (HTParentAnchor * me)
970: {
971: return me ? me->expires : -1;
972: }
973:
1.46 frystyk 974: PUBLIC void HTAnchor_setExpires (HTParentAnchor * me, const time_t expires)
1.28 frystyk 975: {
1.41 frystyk 976: if (me) me->expires = expires;
1.28 frystyk 977: }
978:
979: /*
980: ** Last Modified
981: */
1.41 frystyk 982: PUBLIC time_t HTAnchor_lastModified (HTParentAnchor * me)
983: {
984: return me ? me->last_modified : -1;
985: }
986:
1.46 frystyk 987: PUBLIC void HTAnchor_setLastModified (HTParentAnchor * me, const time_t lm)
1.28 frystyk 988: {
1.41 frystyk 989: if (me) me->last_modified = lm;
1.28 frystyk 990: }
991:
992: /*
1.17 frystyk 993: ** Extra Header List of unknown headers
994: */
1.35 frystyk 995: PUBLIC HTList * HTAnchor_Extra (HTParentAnchor * me)
1.2 timbl 996: {
1.17 frystyk 997: return me ? me->extra_headers : NULL;
1.2 timbl 998: }
999:
1.46 frystyk 1000: PUBLIC void HTAnchor_addExtra (HTParentAnchor * me, const char * header)
1.2 timbl 1001: {
1.17 frystyk 1002: if (me) {
1.18 frystyk 1003: char *newhead = NULL;
1004: StrAllocCopy(newhead, header);
1.17 frystyk 1005: if (!me->extra_headers)
1006: me->extra_headers = HTList_new();
1.18 frystyk 1007: HTList_addObject(me->extra_headers, (void *) newhead);
1.17 frystyk 1008: }
1.2 timbl 1009: }
1010:
1.23 frystyk 1011: /*
1012: ** Has header been parsed?
1.2 timbl 1013: */
1.35 frystyk 1014: PUBLIC BOOL HTAnchor_headerParsed (HTParentAnchor * me)
1.2 timbl 1015: {
1.17 frystyk 1016: return (me ? me->header_parsed : NO);
1.23 frystyk 1017: }
1018:
1.35 frystyk 1019: PUBLIC void HTAnchor_setHeaderParsed (HTParentAnchor * me)
1.23 frystyk 1020: {
1021: if (me) me->header_parsed = YES;
1.2 timbl 1022: }
1023:
1.17 frystyk 1024: /* Clear Header Information
1025: ** ------------------------
1026: */
1.35 frystyk 1027: PUBLIC void HTAnchor_clearHeader (HTParentAnchor * me)
1.2 timbl 1028: {
1.17 frystyk 1029: me->methods = METHOD_INVALID;
1.48 frystyk 1030: if (me->content_encoding) {
1031: HTList_delete(me->content_encoding);
1032: me->content_encoding = HTList_new();
1033: }
1.17 frystyk 1034: if (me->content_language) {
1035: HTList_delete(me->content_language);
1036: me->content_language = HTList_new();
1.9 frystyk 1037: }
1.17 frystyk 1038: me->content_length = -1; /* Invalid */
1.48 frystyk 1039: me->transfer = NULL;
1.17 frystyk 1040: me->content_type = WWW_UNKNOWN;
1041: me->charset = NULL;
1.20 frystyk 1042: me->level = NULL;
1.17 frystyk 1043:
1.28 frystyk 1044: me->date = (time_t) -1;
1045: me->expires = (time_t) -1;
1046: me->last_modified = (time_t) -1;
1.17 frystyk 1047:
1.43 frystyk 1048: HT_FREE(me->derived_from);
1049: HT_FREE(me->version);
1.18 frystyk 1050:
1051: if (me->extra_headers) {
1052: HTList *cur = me->extra_headers;
1053: char *pres;
1054: while ((pres = (char *) HTList_nextObject(cur)))
1.43 frystyk 1055: HT_FREE(pres);
1.18 frystyk 1056: HTList_delete(me->extra_headers);
1057: me->extra_headers = NULL;
1058: }
1.17 frystyk 1059: me->header_parsed = NO; /* All cleared */
1.1 timbl 1060: }
Webmaster