Annotation of libwww/Library/src/HTAnchor.c, revision 1.41

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

Webmaster