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