Annotation of libwww/Library/src/HTAnchor.c, revision 1.41
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.
6: **
7: ** An anchor represents a region of a hypertext document which is
8: ** linked to another anchor in the same or a different document.
1.1 timbl 9: **
10: ** History
11: ** Nov 1990 Written in Objective-C for the NeXT browser (TBL)
12: ** 24-Oct-1991 (JFG), written in C, browser-independant
13: ** 21-Nov-1991 (JFG), first complete version
1.41 ! frystyk 14: ** 3-May-1995 (HF), Added a lot of methods and other stuff made an object
1.1 timbl 15: */
16:
1.16 frystyk 17: /* Library include files */
18: #include "tcp.h"
19: #include "HTUtils.h"
20: #include "HTString.h"
1.7 luotonen 21: #include "HTFormat.h"
1.1 timbl 22: #include "HTParse.h"
1.24 frystyk 23: #include "HTMethod.h"
1.16 frystyk 24: #include "HTFWrite.h" /* for cache stuff */
1.41 ! frystyk 25: #include "HTAncMan.h" /* Implemented here */
1.11 frystyk 26:
27: #define HASH_SIZE 101 /* Arbitrary prime. Memory/speed tradeoff */
1.1 timbl 28:
29: PRIVATE HTList **adult_table=0; /* Point to table of lists of all parents */
30:
1.17 frystyk 31: /* ------------------------------------------------------------------------- */
32: /* Creation Methods */
33: /* ------------------------------------------------------------------------- */
34:
35: /*
1.1 timbl 36: ** Do not use "new" by itself outside this module. In order to enforce
37: ** consistency, we insist that you furnish more information about the
38: ** anchor you are creating : use newWithParent or newWithAddress.
39: */
1.35 frystyk 40: PRIVATE HTParentAnchor * HTParentAnchor_new (void)
1.1 timbl 41: {
1.16 frystyk 42: HTParentAnchor *newAnchor =
43: (HTParentAnchor *) calloc(1, sizeof (HTParentAnchor));
1.33 frystyk 44: if (!newAnchor) outofmem(__FILE__, "HTParentAnchor_new");
1.16 frystyk 45: newAnchor->parent = newAnchor;
1.17 frystyk 46: newAnchor->content_type = WWW_UNKNOWN;
1.24 frystyk 47: newAnchor->mainLink.method = METHOD_INVALID;
1.41 ! frystyk 48: newAnchor->content_length = -1; /* howcome 6 dec 95 */
1.28 frystyk 49: newAnchor->date = (time_t) -1;
50: newAnchor->expires = (time_t) -1;
51: newAnchor->last_modified = (time_t) -1;
1.16 frystyk 52: return newAnchor;
1.1 timbl 53: }
54:
1.16 frystyk 55:
1.35 frystyk 56: PRIVATE HTChildAnchor * HTChildAnchor_new (void)
1.1 timbl 57: {
1.33 frystyk 58: HTChildAnchor *child = (HTChildAnchor *) calloc (1, sizeof(HTChildAnchor));
59: if (!child) outofmem(__FILE__, "HTChildAnchor_new");
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,
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.37 frystyk 80: TTYPrint(TDEST, "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.37 frystyk 90: TTYPrint(TDEST,
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.37 frystyk 106: TTYPrint(TDEST,"Find Child.. New Anchor %p named `%s' is child of %p\n",
1.17 frystyk 107: (void *) child, tag ? tag : (CONST char *) "", (void *)parent);
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.35 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);
131: free(addr);
132: free(tag);
133: return (HTAnchor *) child;
1.16 frystyk 134: } else { /* Else check whether we have this node */
135: int hash;
136: CONST char *p;
137: HTList * adults;
138: HTList *grownups;
139: HTParentAnchor * foundAnchor;
1.34 frystyk 140: char *newaddr = NULL;
141: StrAllocCopy(newaddr, address); /* Get our own copy */
142: 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.16 frystyk 149: adult_table = (HTList**) calloc(HASH_SIZE, sizeof(HTList*));
1.33 frystyk 150: if (!adult_table) outofmem(__FILE__, "HTAnchor_findAddress");
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.37 frystyk 160: TTYPrint(TDEST, "Find Parent. %p with address `%s' already exists.\n",
1.16 frystyk 161: (void*) foundAnchor, newaddr);
1.19 frystyk 162: 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.37 frystyk 171: if (ANCH_TRACE) TTYPrint(TDEST, "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,
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);
194: free(parsed_address);
195: free(relative_to);
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.37 frystyk 279: TTYPrint(TDEST, "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 {
286: HTLink * newLink = (HTLink *) calloc(1, sizeof (HTLink));
1.33 frystyk 287: if (!newLink) outofmem(__FILE__, "HTAnchor_link");
1.17 frystyk 288: newLink->dest = destination;
289: newLink->type = type;
1.24 frystyk 290: newLink->method = method;
291: if (!source->links)
292: source->links = HTList_new();
1.17 frystyk 293: HTList_addObject (source->links, newLink);
294: }
295: if (!destination->parent->sources)
296: destination->parent->sources = HTList_new ();
297: HTList_addObject (destination->parent->sources, source);
298: return YES;
299: }
300:
1.24 frystyk 301: /*
1.28 frystyk 302: ** Find the anchor object between a destination and a source ancher.
303: ** Return link object if any, else NULL
304: */
1.41 ! frystyk 305: PUBLIC HTLink * HTAnchor_findLink (HTAnchor * src, HTAnchor * dest)
1.28 frystyk 306: {
307: if (src && dest) {
308: if (src->mainLink.dest == dest)
309: return &(src->mainLink);
310: if (src->links) {
311: HTList *cur = src->links;
312: HTLink *pres;
313: while ((pres = (HTLink *) HTList_nextObject(cur)) != NULL) {
314: if (pres->dest == dest)
315: return pres;
316: }
317: }
318: }
319: return NULL;
320: }
321:
1.41 ! frystyk 322: /*
! 323: ** Upgrade the link to the main destination and and downgrade the
! 324: ** current main link to the list
! 325: */
! 326: PUBLIC HTLink * HTAnchor_mainLink (HTAnchor * me)
! 327: {
! 328: return me ? &(me->mainLink) : NULL;
! 329: }
1.28 frystyk 330:
1.41 ! frystyk 331: PUBLIC BOOL HTAnchor_setMainLink (HTAnchor * me, HTLink * movingLink)
1.28 frystyk 332: {
1.41 ! frystyk 333: if (!(me && me->links && movingLink &&
! 334: HTList_removeObject(me->links, movingLink)))
! 335: return NO;
! 336: else {
! 337: /* First push current main link onto top of links list */
! 338: HTLink *newLink = (HTLink*) malloc (sizeof (HTLink));
! 339: if (newLink == NULL) outofmem(__FILE__, "HTAnchor_makeMainLink");
! 340: memcpy (newLink, & me->mainLink, sizeof (HTLink));
! 341: HTList_addObject (me->links, newLink);
! 342:
! 343: /* Now make movingLink the new main link, and free it */
! 344: memcpy (& me->mainLink, movingLink, sizeof (HTLink));
! 345: free (movingLink);
1.28 frystyk 346: return YES;
347: }
348: }
349:
350: /*
1.41 ! frystyk 351: ** Handling sub links
1.24 frystyk 352: */
1.41 ! frystyk 353: PUBLIC HTList * HTAnchor_subLinks (HTAnchor * anchor)
1.24 frystyk 354: {
1.41 ! frystyk 355: return anchor ? anchor->links : NULL;
1.24 frystyk 356: }
357:
1.41 ! frystyk 358: PUBLIC BOOL HTAnchor_setSubLinks (HTAnchor * anchor, HTList * list)
! 359: {
! 360: if (anchor) {
! 361: anchor->links = list;
! 362: return YES;
! 363: }
! 364: return NO;
! 365: }
1.24 frystyk 366:
367: /*
368: ** Returns the methods registered for the main destination of this
369: ** anchor
1.17 frystyk 370: */
1.35 frystyk 371: PUBLIC HTMethod HTAnchor_mainLinkMethod (HTAnchor * me)
1.24 frystyk 372: {
373: return me ? me->mainLink.method : METHOD_INVALID;
374: }
375:
1.41 ! frystyk 376: /*
! 377: ** Returns the main destination of this anchor
! 378: */
! 379: PUBLIC HTAnchor * HTAnchor_followMainLink (HTAnchor * me)
! 380: {
! 381: return me ? me->mainLink.dest : NULL;
! 382: }
1.17 frystyk 383:
1.24 frystyk 384: /*
385: ** Moves all link information from one anchor to another.
386: ** This is used in redirection etc.
387: ** Returns YES if OK, else NO
388: */
1.35 frystyk 389: PUBLIC BOOL HTAnchor_moveAllLinks (HTAnchor * src, HTAnchor * dest)
1.17 frystyk 390: {
1.24 frystyk 391: if (!src || !dest) return NO;
392: if (ANCH_TRACE)
1.37 frystyk 393: TTYPrint(TDEST, "Move Links.. from anchor %p to anchor %p\n",
1.24 frystyk 394: (void *) src, (void *) dest);
395:
396: /* Move main link information */
397: dest->mainLink.dest = src->mainLink.dest;
398: dest->mainLink.type = src->mainLink.type;
399: dest->mainLink.method = src->mainLink.method;
1.25 frystyk 400: dest->mainLink.result = src->mainLink.result;
1.24 frystyk 401:
402: src->mainLink.dest = NULL;
403: src->mainLink.type = NULL;
1.25 frystyk 404: src->mainLink.method = METHOD_INVALID;
1.28 frystyk 405: src->mainLink.result = HT_LINK_INVALID;
1.24 frystyk 406:
407: /* Move link information for other links */
1.26 frystyk 408: if (dest->links) {
409: HTList *cur = dest->links;
410: HTLink *pres;
411: while ((pres = (HTLink *) HTList_nextObject(cur)))
412: free(pres);
1.24 frystyk 413: HTList_delete(dest->links);
1.26 frystyk 414: }
1.24 frystyk 415: dest->links = src->links;
416: src->links = NULL;
417: return YES;
1.17 frystyk 418: }
419:
1.24 frystyk 420:
421: /*
1.28 frystyk 422: ** Removes all link information from one anchor to another.
423: ** Returns YES if OK, else NO
424: */
1.35 frystyk 425: PUBLIC BOOL HTAnchor_removeLink (HTAnchor * src, HTAnchor * dest)
1.28 frystyk 426: {
427: if (!src || !dest) return NO;
428: if (ANCH_TRACE)
1.37 frystyk 429: TTYPrint(TDEST, "Remove Link. from anchor %p to anchor %p\n",
1.28 frystyk 430: (void *) src, (void *) dest);
431:
432: /* Remove if dest is the main link */
433: if (src->mainLink.dest == dest) {
434: src->mainLink.dest = NULL;
435: src->mainLink.type = NULL;
436: src->mainLink.method = METHOD_INVALID;
437: src->mainLink.result = HT_LINK_INVALID;
438: return YES;
439: }
440:
441: /* Remove link information for other links */
442: if (dest->links) {
443: HTList *cur = dest->links;
444: HTLink *pres;
445: while ((pres = (HTLink *) HTList_nextObject(cur))) {
446: if (pres->dest == dest) {
447: HTList_removeObject(dest->links, pres);
448: free(pres);
449: return YES;
450: }
451: }
452: }
453: return NO;
454: }
455:
456: /*
457: ** Removes all link information
458: ** Returns YES if OK, else NO
459: */
1.35 frystyk 460: PUBLIC BOOL HTAnchor_removeAllLinks (HTAnchor * me)
1.28 frystyk 461: {
462: if (!me) return NO;
463: if (ANCH_TRACE)
1.37 frystyk 464: TTYPrint(TDEST, "Remove Link. from anchor %p\n", (void *) me);
1.28 frystyk 465:
466: /* Remove if dest is the main link */
467: me->mainLink.dest = NULL;
468: me->mainLink.type = NULL;
469: me->mainLink.method = METHOD_INVALID;
470: me->mainLink.result = HT_LINK_INVALID;
471:
472: /* Remove link information for other links */
473: if (me->links) {
474: HTList *cur = me->links;
475: HTLink *pres;
476: while ((pres = (HTLink *) HTList_nextObject(cur)))
477: free(pres);
478: HTList_delete(me->links);
479: me->links = NULL;
480: }
481: return YES;
482: }
483:
484: /*
1.24 frystyk 485: ** Returns a link with a given link type or NULL if nothing found
486: */
1.41 ! frystyk 487: PUBLIC HTAnchor * HTAnchor_followTypedLink (HTAnchor * me, HTLinkType type)
1.17 frystyk 488: {
1.24 frystyk 489: if (me->mainLink.type == type)
490: return me->mainLink.dest;
491: if (me->links) {
492: HTList *links = me->links;
493: HTLink *link;
494: while ((link = (HTLink *) HTList_nextObject (links)))
495: if (link->type == type)
496: return link->dest;
497: }
498: return NULL; /* No link of me type */
1.17 frystyk 499: }
500:
501:
502: /* Move an anchor to the head of the list of its siblings
503: ** ------------------------------------------------------
504: **
505: ** This is to ensure that an anchor which might have already existed
506: ** is put in the correct order as we load the document.
507: */
1.35 frystyk 508: PUBLIC void HTAnchor_makeLastChild (HTChildAnchor * me)
1.17 frystyk 509: {
1.35 frystyk 510: if (me->parent != (HTParentAnchor *) me) { /* Make sure it's a child */
511: HTList * siblings = me->parent->children;
512: HTList_removeObject (siblings, me);
513: HTList_addObject (siblings, me);
514: }
1.17 frystyk 515: }
516:
517: /* ------------------------------------------------------------------------- */
518: /* Deletion Methods */
519: /* ------------------------------------------------------------------------- */
1.1 timbl 520:
521: /* Delete an anchor and possibly related things (auto garbage collection)
522: ** --------------------------------------------
523: **
524: ** The anchor is only deleted if the corresponding document is not loaded.
1.10 frystyk 525: ** All outgoing links from parent and children are deleted, and this
526: ** anchor is removed from the sources list of all its targets.
1.1 timbl 527: ** We also try to delete the targets whose documents are not loaded.
528: ** If this anchor's source list is empty, we delete it and its children.
529: */
530:
1.41 ! frystyk 531: /* Deletes all the memory allocated in a parent anchor and returns any
! 532: ** hyperdoc object hanging of this anchor
1.19 frystyk 533: */
1.41 ! frystyk 534: PRIVATE void * delete_parent (HTParentAnchor * me)
1.19 frystyk 535: {
1.41 ! frystyk 536: void * doc = me->document;
1.19 frystyk 537:
538: /* Remove link and address information */
1.26 frystyk 539: if (me->links) {
540: HTList *cur = me->links;
541: HTLink *pres;
542: while ((pres = (HTLink *) HTList_nextObject(cur)))
543: free(pres);
544: HTList_delete(me->links);
545: }
1.19 frystyk 546: HTList_delete (me->children);
547: HTList_delete (me->sources);
548: FREE(me->physical);
549: FREE(me->address);
550:
551: /* Then remove entity header information (metainformation) */
552: FREE(me->title);
553: FREE(me->derived_from);
554: FREE(me->version);
555: if (me->extra_headers) {
556: HTList *cur = me->extra_headers;
557: char *pres;
558: while ((pres = (char *) HTList_nextObject(cur)))
559: free(pres);
560: HTList_delete(me->extra_headers);
561: }
562: free(me);
563: return doc;
564: }
565:
566:
1.41 ! frystyk 567: /* Delete a parent anchor and all its children. If a hyperdoc object
! 568: ** is found hanging off the parent anchor then this is returned
1.19 frystyk 569: */
1.41 ! frystyk 570: PRIVATE void * delete_family (HTAnchor * me)
1.19 frystyk 571: {
572: HTParentAnchor *parent = me->parent;
573: if (ANCH_TRACE)
1.37 frystyk 574: TTYPrint(TDEST, "AnchorDelete Remove parent %p and children\n", parent);
1.19 frystyk 575: if (!me) {
576: if (ANCH_TRACE)
1.37 frystyk 577: TTYPrint(TDEST, "AnchorDelete No anchor found\n");
1.19 frystyk 578: return NULL;
579: }
580:
581: /* Delete children */
582: if (parent->children) {
583: HTChildAnchor *child;
584: while ((child = (HTChildAnchor *)
585: HTList_removeLastObject(parent->children))) {
586: FREE(child->tag);
1.26 frystyk 587: if (child->links) {
588: HTList *cur = child->links;
589: HTLink *pres;
590: while ((pres = (HTLink *) HTList_nextObject(cur)))
591: free(pres);
592: HTList_delete(child->links);
593: }
1.19 frystyk 594: free(child);
595: }
596: }
597: return delete_parent(parent);
598: }
599:
600:
601: /* DELETE ALL ANCHORS
602: ** ------------------
603: ** Deletes all anchors and return a list of all the HyperDocs found.
604: ** It is for the application to delete any HyperDocs.
1.39 frystyk 605: ** If NULL then no hyperdocs are returned
1.19 frystyk 606: ** Return YES if OK, else NO
607: */
1.35 frystyk 608: PUBLIC BOOL HTAnchor_deleteAll (HTList * documents)
1.19 frystyk 609: {
610: int cnt;
611: HTList *cur;
1.39 frystyk 612: if (!adult_table)
1.19 frystyk 613: return NO;
614: for (cnt=0; cnt<HASH_SIZE; cnt++) {
615: if ((cur = adult_table[cnt])) {
616: HTParentAnchor *pres;
617: while ((pres = (HTParentAnchor *) HTList_nextObject(cur)) != NULL){
1.41 ! frystyk 618: void * doc = delete_family((HTAnchor *) pres);
! 619: if (doc && documents) HTList_addObject(documents, doc);
1.19 frystyk 620: }
621: }
622: HTList_delete(adult_table[cnt]);
623: }
1.21 frystyk 624: FREE(adult_table);
1.19 frystyk 625: return YES;
626: }
627:
628:
1.35 frystyk 629: PRIVATE void deleteLinks (HTAnchor * me)
1.1 timbl 630: {
1.3 timbl 631: if (! me)
1.1 timbl 632: return;
633:
634: /* Recursively try to delete target anchors */
1.3 timbl 635: if (me->mainLink.dest) {
636: HTParentAnchor *parent = me->mainLink.dest->parent;
637: HTList_removeObject (parent->sources, me);
1.1 timbl 638: if (! parent->document) /* Test here to avoid calling overhead */
639: HTAnchor_delete (parent);
640: }
1.3 timbl 641: if (me->links) { /* Extra destinations */
1.1 timbl 642: HTLink *target;
1.12 frystyk 643: while ((target = (HTLink *) HTList_removeLastObject (me->links))) {
1.1 timbl 644: HTParentAnchor *parent = target->dest->parent;
1.3 timbl 645: HTList_removeObject (parent->sources, me);
1.1 timbl 646: if (! parent->document) /* Test here to avoid calling overhead */
647: HTAnchor_delete (parent);
648: }
649: }
650: }
651:
1.35 frystyk 652: PUBLIC BOOL HTAnchor_delete (HTParentAnchor * me)
1.1 timbl 653: {
654: HTChildAnchor *child;
655:
656: /* Don't delete if document is loaded */
1.3 timbl 657: if (me->document)
1.1 timbl 658: return NO;
659:
660: /* Recursively try to delete target anchors */
1.3 timbl 661: deleteLinks ((HTAnchor *) me);
1.1 timbl 662:
1.3 timbl 663: if (! HTList_isEmpty (me->sources)) { /* There are still incoming links */
1.1 timbl 664: /* Delete all outgoing links from children, if any */
1.3 timbl 665: HTList *kids = me->children;
1.12 frystyk 666: while ((child = (HTChildAnchor *) HTList_nextObject (kids)))
1.1 timbl 667: deleteLinks ((HTAnchor *) child);
668: return NO; /* Parent not deleted */
669: }
670:
671: /* No more incoming links : kill everything */
672: /* First, recursively delete children */
1.12 frystyk 673: while ((child = (HTChildAnchor *) HTList_removeLastObject (me->children))) {
1.1 timbl 674: deleteLinks ((HTAnchor *) child);
675: free (child->tag);
676: free (child);
677: }
678:
679: /* Now kill myself */
1.19 frystyk 680: delete_parent(me);
1.1 timbl 681: return YES; /* Parent deleted */
682: }
683:
1.17 frystyk 684: /* ------------------------------------------------------------------------- */
685: /* Data Access Methods */
686: /* ------------------------------------------------------------------------- */
1.1 timbl 687:
1.35 frystyk 688: PUBLIC HTParentAnchor * HTAnchor_parent (HTAnchor * me)
1.1 timbl 689: {
1.17 frystyk 690: return me ? me->parent : NULL;
1.1 timbl 691: }
692:
1.41 ! frystyk 693: PUBLIC void HTAnchor_setDocument (HTParentAnchor * me, void * doc)
1.1 timbl 694: {
1.41 ! frystyk 695: if (me) me->document = doc;
1.1 timbl 696: }
697:
1.41 ! frystyk 698: PUBLIC void * HTAnchor_document (HTParentAnchor * me)
1.1 timbl 699: {
1.17 frystyk 700: return me ? me->document : NULL;
1.1 timbl 701: }
702:
1.35 frystyk 703: PUBLIC char * HTAnchor_address (HTAnchor * me)
1.1 timbl 704: {
1.17 frystyk 705: char *addr = NULL;
706: if (me) {
707: if (((HTParentAnchor *) me == me->parent) ||
708: !((HTChildAnchor *) me)->tag) { /* it's an adult or no tag */
709: StrAllocCopy (addr, me->parent->address);
710: }
711: else { /* it's a named child */
712: addr = (char *) malloc (2 + strlen (me->parent->address)
713: + strlen (((HTChildAnchor *) me)->tag));
714: if (addr == NULL) outofmem(__FILE__, "HTAnchor_address");
715: sprintf (addr, "%s#%s", me->parent->address,
716: ((HTChildAnchor *) me)->tag);
717: }
1.1 timbl 718: }
1.17 frystyk 719: return addr;
1.1 timbl 720: }
721:
1.35 frystyk 722: PUBLIC BOOL HTAnchor_hasChildren (HTParentAnchor * me)
1.17 frystyk 723: {
724: return me ? ! HTList_isEmpty(me->children) : NO;
725: }
1.1 timbl 726:
1.35 frystyk 727: PUBLIC void HTAnchor_clearIndex (HTParentAnchor * me)
1.17 frystyk 728: {
1.36 frystyk 729: if (me) me->isIndex = NO;
1.17 frystyk 730: }
1.1 timbl 731:
1.35 frystyk 732: PUBLIC void HTAnchor_setIndex (HTParentAnchor * me)
1.1 timbl 733: {
1.36 frystyk 734: if (me) me->isIndex = YES;
1.17 frystyk 735: }
736:
1.35 frystyk 737: PUBLIC BOOL HTAnchor_isIndex (HTParentAnchor * me)
1.17 frystyk 738: {
739: return me ? me->isIndex : NO;
1.9 frystyk 740: }
1.1 timbl 741:
1.17 frystyk 742: /* Physical Address
743: ** ----------------
744: */
745:
1.35 frystyk 746: PUBLIC char * HTAnchor_physical (HTParentAnchor * me)
1.1 timbl 747: {
1.36 frystyk 748: return me ? me->physical : NULL;
1.1 timbl 749: }
750:
1.35 frystyk 751: PUBLIC void HTAnchor_setPhysical (HTParentAnchor * me,
752: char * physical)
1.1 timbl 753: {
1.17 frystyk 754: if (!me || !physical) {
755: if (ANCH_TRACE)
1.37 frystyk 756: TTYPrint(TDEST, "HTAnchor.... setPhysical, called with null argument\n");
1.17 frystyk 757: return;
758: }
759: StrAllocCopy(me->physical, physical);
1.27 frystyk 760: }
761:
762: /* Cache Information
763: ** -----------------
764: */
1.35 frystyk 765: PUBLIC BOOL HTAnchor_cacheHit (HTParentAnchor * me)
1.27 frystyk 766: {
1.36 frystyk 767: return me ? me->cacheHit : NO;
1.27 frystyk 768: }
769:
1.35 frystyk 770: PUBLIC void HTAnchor_setCacheHit (HTParentAnchor * me, BOOL cacheHit)
1.27 frystyk 771: {
1.36 frystyk 772: if (me) me->cacheHit = cacheHit;
1.1 timbl 773: }
774:
1.17 frystyk 775: /* ------------------------------------------------------------------------- */
776: /* Entity Header Information */
777: /* ------------------------------------------------------------------------- */
778:
779: /*
780: ** Media Types (Content-Type)
781: */
1.35 frystyk 782: PUBLIC HTFormat HTAnchor_format (HTParentAnchor * me)
1.17 frystyk 783: {
784: return me ? me->content_type : NULL;
785: }
1.1 timbl 786:
1.35 frystyk 787: PUBLIC void HTAnchor_setFormat (HTParentAnchor * me, HTFormat form)
1.1 timbl 788: {
1.17 frystyk 789: if (me) me->content_type = form;
1.1 timbl 790: }
791:
1.17 frystyk 792: /*
793: ** Charset parameter to Content-Type
1.1 timbl 794: */
1.35 frystyk 795: PUBLIC HTCharset HTAnchor_charset (HTParentAnchor * me)
1.1 timbl 796: {
1.17 frystyk 797: return me ? me->charset : NULL;
1.1 timbl 798: }
799:
1.35 frystyk 800: PUBLIC void HTAnchor_setCharset (HTParentAnchor * me, HTCharset charset)
1.1 timbl 801: {
1.17 frystyk 802: if (me) me->charset = charset;
1.1 timbl 803: }
804:
1.17 frystyk 805: /*
1.20 frystyk 806: ** Level parameter to Content-Type
807: */
1.35 frystyk 808: PUBLIC HTLevel HTAnchor_level (HTParentAnchor * me)
1.20 frystyk 809: {
810: return me ? me->level : NULL;
811: }
812:
1.35 frystyk 813: PUBLIC void HTAnchor_setLevel (HTParentAnchor * me, HTLevel level)
1.20 frystyk 814: {
815: if (me) me->level = level;
816: }
817:
818: /*
1.17 frystyk 819: ** Content Encoding
820: */
1.35 frystyk 821: PUBLIC HTEncoding HTAnchor_encoding (HTParentAnchor * me)
1.1 timbl 822: {
1.17 frystyk 823: return me ? me->content_encoding : NULL;
1.1 timbl 824: }
825:
1.35 frystyk 826: PUBLIC void HTAnchor_setEncoding (HTParentAnchor * me, HTEncoding encoding)
1.17 frystyk 827: {
828: if (me) me->content_encoding = encoding;
829: }
830:
831: /*
1.21 frystyk 832: ** Content Language
833: ** @@@ SHOULD BE A LIST @@@
834: */
1.35 frystyk 835: PUBLIC HTLanguage HTAnchor_language (HTParentAnchor * me)
1.21 frystyk 836: {
837: return me ? me->content_language : NULL;
838: }
839:
1.35 frystyk 840: PUBLIC void HTAnchor_setLanguage (HTParentAnchor * me, HTLanguage language)
1.21 frystyk 841: {
842: if (me) me->content_language = language;
843: }
844:
845: /*
1.17 frystyk 846: ** Content Transfer Encoding
1.1 timbl 847: */
1.35 frystyk 848: PUBLIC HTCte HTAnchor_cte (HTParentAnchor * me)
1.17 frystyk 849: {
850: return me ? me->cte : NULL;
851: }
1.1 timbl 852:
1.35 frystyk 853: PUBLIC void HTAnchor_setCte (HTParentAnchor * me, HTCte cte)
1.17 frystyk 854: {
855: if (me) me->cte = cte;
856: }
857:
858: /*
859: ** Content Length
860: */
1.35 frystyk 861: PUBLIC long int HTAnchor_length (HTParentAnchor * me)
1.1 timbl 862: {
1.17 frystyk 863: return me ? me->content_length : -1;
1.1 timbl 864: }
865:
1.35 frystyk 866: PUBLIC void HTAnchor_setLength (HTParentAnchor * me, long int length)
1.17 frystyk 867: {
868: if (me) me->content_length = length;
869: }
1.1 timbl 870:
1.17 frystyk 871: /*
872: ** Allowed methods (Allow)
1.1 timbl 873: */
1.35 frystyk 874: PUBLIC int HTAnchor_methods (HTParentAnchor * me)
1.17 frystyk 875: {
1.32 frystyk 876: return me ? me->methods : METHOD_INVALID;
1.17 frystyk 877: }
1.1 timbl 878:
1.35 frystyk 879: PUBLIC void HTAnchor_setMethods (HTParentAnchor * me, int methodset)
1.1 timbl 880: {
1.17 frystyk 881: if (me) me->methods = methodset;
1.1 timbl 882: }
883:
1.35 frystyk 884: PUBLIC void HTAnchor_appendMethods (HTParentAnchor * me, int methodset)
1.1 timbl 885: {
1.32 frystyk 886: if (me) me->methods |= methodset;
1.1 timbl 887: }
888:
1.17 frystyk 889: /*
890: ** Title
1.2 timbl 891: */
1.35 frystyk 892: PUBLIC CONST char * HTAnchor_title (HTParentAnchor * me)
1.1 timbl 893: {
1.17 frystyk 894: return me ? me->title : NULL;
895: }
1.1 timbl 896:
1.35 frystyk 897: PUBLIC void HTAnchor_setTitle (HTParentAnchor * me, CONST char * title)
1.17 frystyk 898: {
899: if (me && title) StrAllocCopy(me->title, title);
1.2 timbl 900: }
901:
1.35 frystyk 902: PUBLIC void HTAnchor_appendTitle (HTParentAnchor * me, CONST char * title)
1.17 frystyk 903: {
904: if (me && title) StrAllocCat(me->title, title);
905: }
1.2 timbl 906:
1.17 frystyk 907: /*
908: ** Version
1.2 timbl 909: */
1.41 ! frystyk 910: PUBLIC char * HTAnchor_version (HTParentAnchor * me)
1.17 frystyk 911: {
912: return me ? me->version : NULL;
913: }
1.2 timbl 914:
1.35 frystyk 915: PUBLIC void HTAnchor_setVersion (HTParentAnchor * me, CONST char * version)
1.2 timbl 916: {
1.17 frystyk 917: if (me && version) StrAllocCopy(me->version, version);
1.2 timbl 918: }
919:
1.17 frystyk 920: /*
921: ** Derived from
1.2 timbl 922: */
1.41 ! frystyk 923: PUBLIC char * HTAnchor_derived (HTParentAnchor * me)
1.17 frystyk 924: {
925: return me ? me->derived_from : NULL;
926: }
927:
1.35 frystyk 928: PUBLIC void HTAnchor_setDerived (HTParentAnchor * me, CONST char *derived_from)
1.17 frystyk 929: {
930: if (me && derived_from) StrAllocCopy(me->derived_from, derived_from);
931: }
1.2 timbl 932:
1.17 frystyk 933: /*
1.28 frystyk 934: ** Date
935: */
1.41 ! frystyk 936: PUBLIC time_t HTAnchor_date (HTParentAnchor * me)
! 937: {
! 938: return me ? me->date : -1;
! 939: }
! 940:
! 941: PUBLIC void HTAnchor_setDate (HTParentAnchor * me, CONST time_t date)
1.28 frystyk 942: {
1.41 ! frystyk 943: if (me) me->date = date;
1.28 frystyk 944: }
945:
946: /*
947: ** Expires
948: */
1.41 ! frystyk 949: PUBLIC time_t HTAnchor_expires (HTParentAnchor * me)
! 950: {
! 951: return me ? me->expires : -1;
! 952: }
! 953:
! 954: PUBLIC void HTAnchor_setExpires (HTParentAnchor * me, CONST time_t expires)
1.28 frystyk 955: {
1.41 ! frystyk 956: if (me) me->expires = expires;
1.28 frystyk 957: }
958:
959: /*
960: ** Last Modified
961: */
1.41 ! frystyk 962: PUBLIC time_t HTAnchor_lastModified (HTParentAnchor * me)
! 963: {
! 964: return me ? me->last_modified : -1;
! 965: }
! 966:
! 967: PUBLIC void HTAnchor_setLastModified (HTParentAnchor * me, CONST time_t lm)
1.28 frystyk 968: {
1.41 ! frystyk 969: if (me) me->last_modified = lm;
1.28 frystyk 970: }
971:
972: /*
1.17 frystyk 973: ** Extra Header List of unknown headers
974: */
1.35 frystyk 975: PUBLIC HTList * HTAnchor_Extra (HTParentAnchor * me)
1.2 timbl 976: {
1.17 frystyk 977: return me ? me->extra_headers : NULL;
1.2 timbl 978: }
979:
1.35 frystyk 980: PUBLIC void HTAnchor_addExtra (HTParentAnchor * me, CONST char * header)
1.2 timbl 981: {
1.17 frystyk 982: if (me) {
1.18 frystyk 983: char *newhead = NULL;
984: StrAllocCopy(newhead, header);
1.17 frystyk 985: if (!me->extra_headers)
986: me->extra_headers = HTList_new();
1.18 frystyk 987: HTList_addObject(me->extra_headers, (void *) newhead);
1.17 frystyk 988: }
1.2 timbl 989: }
990:
1.23 frystyk 991: /*
992: ** Has header been parsed?
1.2 timbl 993: */
1.35 frystyk 994: PUBLIC BOOL HTAnchor_headerParsed (HTParentAnchor * me)
1.2 timbl 995: {
1.17 frystyk 996: return (me ? me->header_parsed : NO);
1.23 frystyk 997: }
998:
1.35 frystyk 999: PUBLIC void HTAnchor_setHeaderParsed (HTParentAnchor * me)
1.23 frystyk 1000: {
1001: if (me) me->header_parsed = YES;
1.2 timbl 1002: }
1003:
1.17 frystyk 1004: /* Clear Header Information
1005: ** ------------------------
1006: */
1.35 frystyk 1007: PUBLIC void HTAnchor_clearHeader (HTParentAnchor * me)
1.2 timbl 1008: {
1.17 frystyk 1009: me->methods = METHOD_INVALID;
1010: me->content_encoding = NULL;
1.21 frystyk 1011: #ifdef NEW_CODE
1012: /* WAIT UNTIL WE HANDLE LANGUAGE AS A LIST */
1.17 frystyk 1013: if (me->content_language) {
1014: HTList_delete(me->content_language);
1015: me->content_language = HTList_new();
1.9 frystyk 1016: }
1.21 frystyk 1017: #else
1018: me->content_language = NULL;
1019: #endif
1.17 frystyk 1020: me->content_length = -1; /* Invalid */
1021: me->cte = NULL;
1022: me->content_type = WWW_UNKNOWN;
1023: me->charset = NULL;
1.20 frystyk 1024: me->level = NULL;
1.17 frystyk 1025:
1.28 frystyk 1026: me->date = (time_t) -1;
1027: me->expires = (time_t) -1;
1028: me->last_modified = (time_t) -1;
1.17 frystyk 1029:
1.18 frystyk 1030: FREE(me->derived_from);
1031: FREE(me->version);
1032:
1033: if (me->extra_headers) {
1034: HTList *cur = me->extra_headers;
1035: char *pres;
1036: while ((pres = (char *) HTList_nextObject(cur)))
1037: free(pres);
1038: HTList_delete(me->extra_headers);
1039: me->extra_headers = NULL;
1040: }
1.17 frystyk 1041: me->header_parsed = NO; /* All cleared */
1.1 timbl 1042: }
Webmaster