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