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