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