Annotation of libwww/Library/src/HTAnchor.c, revision 1.38
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.
544: ** Return YES if OK, else NO
545: */
1.35 frystyk 546: PUBLIC BOOL HTAnchor_deleteAll (HTList * documents)
1.19 frystyk 547: {
548: int cnt;
549: HTList *cur;
1.29 frystyk 550: if (!documents || !adult_table)
1.19 frystyk 551: return NO;
552: for (cnt=0; cnt<HASH_SIZE; cnt++) {
553: if ((cur = adult_table[cnt])) {
554: HTParentAnchor *pres;
555: while ((pres = (HTParentAnchor *) HTList_nextObject(cur)) != NULL){
556: HyperDoc *doc = delete_family((HTAnchor *) pres);
557: if (doc) HTList_addObject(documents, (void *) doc);
558: }
559: }
560: HTList_delete(adult_table[cnt]);
561: }
1.21 frystyk 562: FREE(adult_table);
1.19 frystyk 563: return YES;
564: }
565:
566:
1.35 frystyk 567: PRIVATE void deleteLinks (HTAnchor * me)
1.1 timbl 568: {
1.3 timbl 569: if (! me)
1.1 timbl 570: return;
571:
572: /* Recursively try to delete target anchors */
1.3 timbl 573: if (me->mainLink.dest) {
574: HTParentAnchor *parent = me->mainLink.dest->parent;
575: HTList_removeObject (parent->sources, me);
1.1 timbl 576: if (! parent->document) /* Test here to avoid calling overhead */
577: HTAnchor_delete (parent);
578: }
1.3 timbl 579: if (me->links) { /* Extra destinations */
1.1 timbl 580: HTLink *target;
1.12 frystyk 581: while ((target = (HTLink *) HTList_removeLastObject (me->links))) {
1.1 timbl 582: HTParentAnchor *parent = target->dest->parent;
1.3 timbl 583: HTList_removeObject (parent->sources, me);
1.1 timbl 584: if (! parent->document) /* Test here to avoid calling overhead */
585: HTAnchor_delete (parent);
586: }
587: }
588: }
589:
1.35 frystyk 590: PUBLIC BOOL HTAnchor_delete (HTParentAnchor * me)
1.1 timbl 591: {
592: HTChildAnchor *child;
593:
594: /* Don't delete if document is loaded */
1.3 timbl 595: if (me->document)
1.1 timbl 596: return NO;
597:
598: /* Recursively try to delete target anchors */
1.3 timbl 599: deleteLinks ((HTAnchor *) me);
1.1 timbl 600:
1.3 timbl 601: if (! HTList_isEmpty (me->sources)) { /* There are still incoming links */
1.1 timbl 602: /* Delete all outgoing links from children, if any */
1.3 timbl 603: HTList *kids = me->children;
1.12 frystyk 604: while ((child = (HTChildAnchor *) HTList_nextObject (kids)))
1.1 timbl 605: deleteLinks ((HTAnchor *) child);
606: return NO; /* Parent not deleted */
607: }
608:
609: /* No more incoming links : kill everything */
610: /* First, recursively delete children */
1.12 frystyk 611: while ((child = (HTChildAnchor *) HTList_removeLastObject (me->children))) {
1.1 timbl 612: deleteLinks ((HTAnchor *) child);
613: free (child->tag);
614: free (child);
615: }
616:
617: /* Now kill myself */
1.19 frystyk 618: delete_parent(me);
1.1 timbl 619: return YES; /* Parent deleted */
620: }
621:
1.17 frystyk 622: /* ------------------------------------------------------------------------- */
623: /* Data Access Methods */
624: /* ------------------------------------------------------------------------- */
1.1 timbl 625:
1.35 frystyk 626: PUBLIC HTParentAnchor * HTAnchor_parent (HTAnchor * me)
1.1 timbl 627: {
1.17 frystyk 628: return me ? me->parent : NULL;
1.1 timbl 629: }
630:
1.35 frystyk 631: PUBLIC void HTAnchor_setDocument (HTParentAnchor * me, HyperDoc * doc)
1.1 timbl 632: {
1.17 frystyk 633: if (me)
634: me->document = doc;
1.1 timbl 635: }
636:
1.35 frystyk 637: PUBLIC HyperDoc * HTAnchor_document (HTParentAnchor * me)
1.1 timbl 638: {
1.17 frystyk 639: return me ? me->document : NULL;
1.1 timbl 640: }
641:
642:
1.10 frystyk 643: #if 0
1.17 frystyk 644: /* We might want to use this when we have a link editing application */
1.10 frystyk 645: PUBLIC void HTAnchor_setAddress
1.35 frystyk 646: (HTAnchor * me, char * addr)
1.1 timbl 647: {
1.3 timbl 648: if (me)
649: StrAllocCopy (me->parent->address, addr);
1.1 timbl 650: }
1.10 frystyk 651: #endif
652:
1.35 frystyk 653: PUBLIC char * HTAnchor_address (HTAnchor * me)
1.1 timbl 654: {
1.17 frystyk 655: char *addr = NULL;
656: if (me) {
657: if (((HTParentAnchor *) me == me->parent) ||
658: !((HTChildAnchor *) me)->tag) { /* it's an adult or no tag */
659: StrAllocCopy (addr, me->parent->address);
660: }
661: else { /* it's a named child */
662: addr = (char *) malloc (2 + strlen (me->parent->address)
663: + strlen (((HTChildAnchor *) me)->tag));
664: if (addr == NULL) outofmem(__FILE__, "HTAnchor_address");
665: sprintf (addr, "%s#%s", me->parent->address,
666: ((HTChildAnchor *) me)->tag);
667: }
1.1 timbl 668: }
1.17 frystyk 669: return addr;
1.1 timbl 670: }
671:
1.35 frystyk 672: PUBLIC BOOL HTAnchor_hasChildren (HTParentAnchor * me)
1.17 frystyk 673: {
674: return me ? ! HTList_isEmpty(me->children) : NO;
675: }
1.1 timbl 676:
1.35 frystyk 677: PUBLIC void HTAnchor_clearIndex (HTParentAnchor * me)
1.17 frystyk 678: {
1.36 frystyk 679: if (me) me->isIndex = NO;
1.17 frystyk 680: }
1.1 timbl 681:
1.35 frystyk 682: PUBLIC void HTAnchor_setIndex (HTParentAnchor * me)
1.1 timbl 683: {
1.36 frystyk 684: if (me) me->isIndex = YES;
1.17 frystyk 685: }
686:
1.35 frystyk 687: PUBLIC BOOL HTAnchor_isIndex (HTParentAnchor * me)
1.17 frystyk 688: {
689: return me ? me->isIndex : NO;
1.1 timbl 690: }
691:
1.17 frystyk 692: /* Protocol
693: ** --------
694: */
695:
1.35 frystyk 696: PUBLIC void * HTAnchor_protocol (HTParentAnchor * me)
1.1 timbl 697: {
1.36 frystyk 698: return me ? me->protocol : NULL;
1.1 timbl 699: }
700:
1.35 frystyk 701: PUBLIC void HTAnchor_setProtocol (HTParentAnchor * me,
702: void* protocol)
1.9 frystyk 703: {
1.36 frystyk 704: if (me) me->protocol = protocol;
1.9 frystyk 705: }
1.1 timbl 706:
1.17 frystyk 707: /* Physical Address
708: ** ----------------
709: */
710:
1.35 frystyk 711: PUBLIC char * HTAnchor_physical (HTParentAnchor * me)
1.1 timbl 712: {
1.36 frystyk 713: return me ? me->physical : NULL;
1.1 timbl 714: }
715:
1.35 frystyk 716: PUBLIC void HTAnchor_setPhysical (HTParentAnchor * me,
717: char * physical)
1.1 timbl 718: {
1.17 frystyk 719: if (!me || !physical) {
720: if (ANCH_TRACE)
1.37 frystyk 721: TTYPrint(TDEST, "HTAnchor.... setPhysical, called with null argument\n");
1.17 frystyk 722: return;
723: }
724: StrAllocCopy(me->physical, physical);
1.27 frystyk 725: }
726:
727: /* Cache Information
728: ** -----------------
729: */
1.35 frystyk 730: PUBLIC BOOL HTAnchor_cacheHit (HTParentAnchor * me)
1.27 frystyk 731: {
1.36 frystyk 732: return me ? me->cacheHit : NO;
1.27 frystyk 733: }
734:
1.35 frystyk 735: PUBLIC void HTAnchor_setCacheHit (HTParentAnchor * me, BOOL cacheHit)
1.27 frystyk 736: {
1.36 frystyk 737: if (me) me->cacheHit = cacheHit;
1.1 timbl 738: }
739:
1.17 frystyk 740: /* ------------------------------------------------------------------------- */
741: /* Entity Header Information */
742: /* ------------------------------------------------------------------------- */
743:
744: /*
745: ** Media Types (Content-Type)
746: */
1.35 frystyk 747: PUBLIC HTFormat HTAnchor_format (HTParentAnchor * me)
1.17 frystyk 748: {
749: return me ? me->content_type : NULL;
750: }
1.1 timbl 751:
1.35 frystyk 752: PUBLIC void HTAnchor_setFormat (HTParentAnchor * me, HTFormat form)
1.1 timbl 753: {
1.17 frystyk 754: if (me) me->content_type = form;
1.1 timbl 755: }
756:
1.17 frystyk 757: /*
758: ** Charset parameter to Content-Type
1.1 timbl 759: */
1.35 frystyk 760: PUBLIC HTCharset HTAnchor_charset (HTParentAnchor * me)
1.1 timbl 761: {
1.17 frystyk 762: return me ? me->charset : NULL;
1.1 timbl 763: }
764:
1.35 frystyk 765: PUBLIC void HTAnchor_setCharset (HTParentAnchor * me, HTCharset charset)
1.1 timbl 766: {
1.17 frystyk 767: if (me) me->charset = charset;
1.1 timbl 768: }
769:
1.17 frystyk 770: /*
1.20 frystyk 771: ** Level parameter to Content-Type
772: */
1.35 frystyk 773: PUBLIC HTLevel HTAnchor_level (HTParentAnchor * me)
1.20 frystyk 774: {
775: return me ? me->level : NULL;
776: }
777:
1.35 frystyk 778: PUBLIC void HTAnchor_setLevel (HTParentAnchor * me, HTLevel level)
1.20 frystyk 779: {
780: if (me) me->level = level;
781: }
782:
783: /*
1.17 frystyk 784: ** Content Encoding
785: */
1.35 frystyk 786: PUBLIC HTEncoding HTAnchor_encoding (HTParentAnchor * me)
1.1 timbl 787: {
1.17 frystyk 788: return me ? me->content_encoding : NULL;
1.1 timbl 789: }
790:
1.35 frystyk 791: PUBLIC void HTAnchor_setEncoding (HTParentAnchor * me, HTEncoding encoding)
1.17 frystyk 792: {
793: if (me) me->content_encoding = encoding;
794: }
795:
796: /*
1.21 frystyk 797: ** Content Language
798: ** @@@ SHOULD BE A LIST @@@
799: */
1.35 frystyk 800: PUBLIC HTLanguage HTAnchor_language (HTParentAnchor * me)
1.21 frystyk 801: {
802: return me ? me->content_language : NULL;
803: }
804:
1.35 frystyk 805: PUBLIC void HTAnchor_setLanguage (HTParentAnchor * me, HTLanguage language)
1.21 frystyk 806: {
807: if (me) me->content_language = language;
808: }
809:
810: /*
1.17 frystyk 811: ** Content Transfer Encoding
1.1 timbl 812: */
1.35 frystyk 813: PUBLIC HTCte HTAnchor_cte (HTParentAnchor * me)
1.17 frystyk 814: {
815: return me ? me->cte : NULL;
816: }
1.1 timbl 817:
1.35 frystyk 818: PUBLIC void HTAnchor_setCte (HTParentAnchor * me, HTCte cte)
1.17 frystyk 819: {
820: if (me) me->cte = cte;
821: }
822:
823: /*
824: ** Content Length
825: */
1.35 frystyk 826: PUBLIC long int HTAnchor_length (HTParentAnchor * me)
1.1 timbl 827: {
1.17 frystyk 828: return me ? me->content_length : -1;
1.1 timbl 829: }
830:
1.35 frystyk 831: PUBLIC void HTAnchor_setLength (HTParentAnchor * me, long int length)
1.17 frystyk 832: {
833: if (me) me->content_length = length;
834: }
1.1 timbl 835:
1.17 frystyk 836: /*
837: ** Allowed methods (Allow)
1.1 timbl 838: */
1.35 frystyk 839: PUBLIC int HTAnchor_methods (HTParentAnchor * me)
1.17 frystyk 840: {
1.32 frystyk 841: return me ? me->methods : METHOD_INVALID;
1.17 frystyk 842: }
1.1 timbl 843:
1.35 frystyk 844: PUBLIC void HTAnchor_setMethods (HTParentAnchor * me, int methodset)
1.1 timbl 845: {
1.17 frystyk 846: if (me) me->methods = methodset;
1.1 timbl 847: }
848:
1.35 frystyk 849: PUBLIC void HTAnchor_appendMethods (HTParentAnchor * me, int methodset)
1.1 timbl 850: {
1.32 frystyk 851: if (me) me->methods |= methodset;
1.1 timbl 852: }
853:
1.17 frystyk 854: /*
855: ** Title
1.2 timbl 856: */
1.35 frystyk 857: PUBLIC CONST char * HTAnchor_title (HTParentAnchor * me)
1.1 timbl 858: {
1.17 frystyk 859: return me ? me->title : NULL;
860: }
1.1 timbl 861:
1.35 frystyk 862: PUBLIC void HTAnchor_setTitle (HTParentAnchor * me, CONST char * title)
1.17 frystyk 863: {
864: if (me && title) StrAllocCopy(me->title, title);
1.2 timbl 865: }
866:
1.35 frystyk 867: PUBLIC void HTAnchor_appendTitle (HTParentAnchor * me, CONST char * title)
1.17 frystyk 868: {
869: if (me && title) StrAllocCat(me->title, title);
870: }
1.2 timbl 871:
1.17 frystyk 872: /*
873: ** Version
1.2 timbl 874: */
1.35 frystyk 875: PUBLIC CONST char * HTAnchor_version (HTParentAnchor * me)
1.17 frystyk 876: {
877: return me ? me->version : NULL;
878: }
1.2 timbl 879:
1.35 frystyk 880: PUBLIC void HTAnchor_setVersion (HTParentAnchor * me, CONST char * version)
1.2 timbl 881: {
1.17 frystyk 882: if (me && version) StrAllocCopy(me->version, version);
1.2 timbl 883: }
884:
1.17 frystyk 885: /*
886: ** Derived from
1.2 timbl 887: */
1.35 frystyk 888: PUBLIC CONST char * HTAnchor_derived (HTParentAnchor * me)
1.17 frystyk 889: {
890: return me ? me->derived_from : NULL;
891: }
892:
1.35 frystyk 893: PUBLIC void HTAnchor_setDerived (HTParentAnchor * me, CONST char *derived_from)
1.17 frystyk 894: {
895: if (me && derived_from) StrAllocCopy(me->derived_from, derived_from);
896: }
1.2 timbl 897:
1.17 frystyk 898: /*
1.28 frystyk 899: ** Date
900: */
1.35 frystyk 901: PUBLIC void HTAnchor_setDate (HTParentAnchor * me, CONST time_t * date)
1.28 frystyk 902: {
903: if (me) me->date = *date;
904: }
905:
906: /*
907: ** Expires
908: */
1.35 frystyk 909: PUBLIC void HTAnchor_setExpires (HTParentAnchor * me, CONST time_t * expires)
1.28 frystyk 910: {
911: if (me) me->expires = *expires;
912: }
913:
914: /*
915: ** Last Modified
916: */
1.35 frystyk 917: PUBLIC void HTAnchor_setLastModified (HTParentAnchor * me, CONST time_t * lm)
1.28 frystyk 918: {
919: if (me) me->last_modified = *lm;
920: }
921:
922: /*
1.17 frystyk 923: ** Extra Header List of unknown headers
924: */
1.35 frystyk 925: PUBLIC HTList * HTAnchor_Extra (HTParentAnchor * me)
1.2 timbl 926: {
1.17 frystyk 927: return me ? me->extra_headers : NULL;
1.2 timbl 928: }
929:
1.35 frystyk 930: PUBLIC void HTAnchor_addExtra (HTParentAnchor * me, CONST char * header)
1.2 timbl 931: {
1.17 frystyk 932: if (me) {
1.18 frystyk 933: char *newhead = NULL;
934: StrAllocCopy(newhead, header);
1.17 frystyk 935: if (!me->extra_headers)
936: me->extra_headers = HTList_new();
1.18 frystyk 937: HTList_addObject(me->extra_headers, (void *) newhead);
1.17 frystyk 938: }
1.2 timbl 939: }
940:
1.23 frystyk 941: /*
942: ** Has header been parsed?
1.2 timbl 943: */
1.35 frystyk 944: PUBLIC BOOL HTAnchor_headerParsed (HTParentAnchor * me)
1.2 timbl 945: {
1.17 frystyk 946: return (me ? me->header_parsed : NO);
1.23 frystyk 947: }
948:
1.35 frystyk 949: PUBLIC void HTAnchor_setHeaderParsed (HTParentAnchor * me)
1.23 frystyk 950: {
951: if (me) me->header_parsed = YES;
1.2 timbl 952: }
953:
1.17 frystyk 954: /* Clear Header Information
955: ** ------------------------
956: */
1.35 frystyk 957: PUBLIC void HTAnchor_clearHeader (HTParentAnchor * me)
1.2 timbl 958: {
1.17 frystyk 959: me->methods = METHOD_INVALID;
960: me->content_encoding = NULL;
1.21 frystyk 961: #ifdef NEW_CODE
962: /* WAIT UNTIL WE HANDLE LANGUAGE AS A LIST */
1.17 frystyk 963: if (me->content_language) {
964: HTList_delete(me->content_language);
965: me->content_language = HTList_new();
1.9 frystyk 966: }
1.21 frystyk 967: #else
968: me->content_language = NULL;
969: #endif
1.17 frystyk 970: me->content_length = -1; /* Invalid */
971: me->cte = NULL;
972: me->content_type = WWW_UNKNOWN;
973: me->charset = NULL;
1.20 frystyk 974: me->level = NULL;
1.17 frystyk 975:
1.28 frystyk 976: me->date = (time_t) -1;
977: me->expires = (time_t) -1;
978: me->last_modified = (time_t) -1;
1.17 frystyk 979:
1.18 frystyk 980: FREE(me->derived_from);
981: FREE(me->version);
982:
983: if (me->extra_headers) {
984: HTList *cur = me->extra_headers;
985: char *pres;
986: while ((pres = (char *) HTList_nextObject(cur)))
987: free(pres);
988: HTList_delete(me->extra_headers);
989: me->extra_headers = NULL;
990: }
1.17 frystyk 991: me->header_parsed = NO; /* All cleared */
1.1 timbl 992: }
Webmaster