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

1.1       timbl       1: /*     Hypertext "Anchor" Object                               HTAnchor.c
                      2: **     ==========================
                      3: **
                      4: ** An anchor represents a region of a hypertext document which is linked to
                      5: ** another anchor in the same or a different document.
                      6: **
                      7: ** History
                      8: **
                      9: **         Nov 1990  Written in Objective-C for the NeXT browser (TBL)
                     10: **     24-Oct-1991 (JFG), written in C, browser-independant 
                     11: **     21-Nov-1991 (JFG), first complete version
                     12: **
                     13: **     (c) Copyright CERN 1991 - See Copyright.html
                     14: */
                     15: 
1.7       luotonen   16: #include "HTFormat.h"
1.1       timbl      17: #include "HTUtils.h"
                     18: #include "HTParse.h"
1.11    ! frystyk    19: #include "HTFWriter.h"                                   /* for cache stuff */
        !            20: #include "HTAnchor.h"                                   /* Implemented here */
        !            21: 
        !            22: #define HASH_SIZE 101          /* Arbitrary prime. Memory/speed tradeoff */
1.1       timbl      23: 
                     24: typedef struct _HyperDoc Hyperdoc;
1.5       duns       25: #ifdef VMS
1.1       timbl      26: struct _HyperDoc {
                     27:        int junk;       /* VMS cannot handle pointers to undefined structs */
                     28: };
                     29: #endif
                     30: 
                     31: PRIVATE HTList **adult_table=0;  /* Point to table of lists of all parents */
                     32: 
                     33: /*                             Creation Methods
                     34: **                             ================
                     35: **
                     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: */
                     40: 
                     41: PRIVATE HTParentAnchor * HTParentAnchor_new
                     42:   NOARGS
                     43: {
                     44:   HTParentAnchor *newAnchor = 
                     45:     (HTParentAnchor *) calloc (1, sizeof (HTParentAnchor));  /* zero-filled */
                     46:   newAnchor->parent = newAnchor;
                     47:   return newAnchor;
                     48: }
                     49: 
                     50: PRIVATE HTChildAnchor * HTChildAnchor_new
                     51:   NOARGS
                     52: {
                     53:   return (HTChildAnchor *) calloc (1, sizeof (HTChildAnchor));  /* zero-filled */
                     54: }
                     55: 
                     56: 
                     57: /*     Case insensitive string comparison
                     58: **     ----------------------------------
                     59: ** On entry,
                     60: **     s       Points to one string, null terminated
                     61: **     t       points to the other.
                     62: ** On exit,
                     63: **     returns YES if the strings are equivalent ignoring case
                     64: **             NO if they differ in more than  their case.
                     65: */
                     66: 
                     67: PRIVATE BOOL equivalent
                     68:   ARGS2 (CONST char *,s, CONST char *,t)
                     69: {
                     70:   if (s && t) {  /* Make sure they point to something */
                     71:     for ( ; *s && *t ; s++, t++) {
                     72:         if (TOUPPER(*s) != TOUPPER(*t))
                     73:          return NO;
                     74:     }
                     75:     return TOUPPER(*s) == TOUPPER(*t);
                     76:   } else
                     77:     return s == t;  /* Two NULLs are equivalent, aren't they ? */
                     78: }
                     79: 
                     80: 
                     81: /*     Create new or find old sub-anchor
                     82: **     ---------------------------------
                     83: **
1.3       timbl      84: **     Me one is for a new anchor being edited into an existing
1.1       timbl      85: **     document. The parent anchor must already exist.
                     86: */
                     87: 
1.2       timbl      88: PUBLIC HTChildAnchor * HTAnchor_findChild
1.1       timbl      89:   ARGS2 (HTParentAnchor *,parent, CONST char *,tag)
                     90: {
                     91:   HTChildAnchor *child;
                     92:   HTList *kids;
                     93: 
                     94:   if (! parent) {
1.11    ! frystyk    95:     if (ANCH_TRACE)
1.8       frystyk    96:        fprintf(stderr, "HTAnchor_findChild called with NULL parent.\n");
1.1       timbl      97:     return NULL;
                     98:   }
1.7       luotonen   99:   if ((kids = parent->children)) {  /* parent has children : search them */
1.1       timbl     100:     if (tag && *tag) {         /* TBL */
1.7       luotonen  101:        while ((child = HTList_nextObject (kids))) {
1.1       timbl     102:            if (equivalent(child->tag, tag)) { /* Case sensitive 920226 */
1.11    ! frystyk   103:                if (ANCH_TRACE) fprintf (stderr,
        !           104:               "AnchorChild. %p of parent %p with name `%s' already exists.\n",
1.4       timbl     105:                    (void*)child, (void*)parent, tag);
1.1       timbl     106:                return child;
                    107:            }
                    108:        }
                    109:      }  /*  end if tag is void */
                    110:   } else  /* parent doesn't have any children yet : create family */
                    111:     parent->children = HTList_new ();
                    112: 
                    113:   child = HTChildAnchor_new ();
1.11    ! frystyk   114:   if (ANCH_TRACE) fprintf(stderr, "AnchorChild. New Anchor %p named `%s' is child of %p\n",
1.4       timbl     115:        (void*)child, (int)tag ? tag : (CONST char *)"" , (void*)parent); /* int for apollo */
1.1       timbl     116:   HTList_addObject (parent->children, child);
                    117:   child->parent = parent;
                    118:   StrAllocCopy(child->tag, tag);
                    119:   return child;
                    120: }
                    121: 
                    122: 
                    123: /*     Create or find a child anchor with a possible link
                    124: **     --------------------------------------------------
                    125: **
                    126: **     Create new anchor with a given parent and possibly
                    127: **     a name, and possibly a link to a _relatively_ named anchor.
                    128: **     (Code originally in ParseHTML.h)
                    129: */
                    130: PUBLIC HTChildAnchor * HTAnchor_findChildAndLink
                    131:   ARGS4(
                    132:        HTParentAnchor *,parent,        /* May not be 0 */
                    133:        CONST char *,tag,       /* May be "" or 0 */
                    134:        CONST char *,href,      /* May be "" or 0 */
                    135:        HTLinkType *,ltype      /* May be 0 */
                    136:        )
                    137: {
                    138:   HTChildAnchor * child = HTAnchor_findChild(parent, tag);
                    139:   if (href && *href) {
1.2       timbl     140:     char * relative_to = HTAnchor_address((HTAnchor *) parent);
                    141:     char * parsed_address = HTParse(href, relative_to, PARSE_ALL);
                    142:     HTAnchor * dest = HTAnchor_findAddress(parsed_address);
1.1       timbl     143:     HTAnchor_link((HTAnchor *) child, dest, ltype);
                    144:     free(parsed_address);
1.2       timbl     145:     free(relative_to);
1.1       timbl     146:   }
                    147:   return child;
                    148: }
                    149: 
                    150: 
                    151: /*     Create new or find old named anchor
                    152: **     -----------------------------------
                    153: **
1.3       timbl     154: **     Me one is for a reference which is found in a document, and might
1.1       timbl     155: **     not be already loaded.
                    156: **     Note: You are not guaranteed a new anchor -- you might get an old one,
                    157: **     like with fonts.
                    158: */
                    159: 
1.10      frystyk   160: PUBLIC HTAnchor * HTAnchor_findAddress
1.1       timbl     161:   ARGS1 (CONST char *,address)
                    162: {
                    163:   char *tag = HTParse (address, "", PARSE_ANCHOR);  /* Anchor tag specified ? */
                    164: 
                    165:   /* If the address represents a sub-anchor, we recursively load its parent,
                    166:      then we create a child anchor within that document. */
                    167:   if (*tag) {
                    168:     char *docAddress = HTParse(address, "", PARSE_ACCESS | PARSE_HOST |
                    169:                                            PARSE_PATH | PARSE_PUNCTUATION);
                    170:     HTParentAnchor * foundParent =
                    171:       (HTParentAnchor *) HTAnchor_findAddress (docAddress);
                    172:     HTChildAnchor * foundAnchor = HTAnchor_findChild (foundParent, tag);
                    173:     free (docAddress);
                    174:     free (tag);
                    175:     return (HTAnchor *) foundAnchor;
                    176:   }
                    177:   
1.3       timbl     178:   else { /* If the address has no anchor tag, 
                    179:            check whether we have this node */
1.1       timbl     180:     int hash;
                    181:     CONST char *p;
                    182:     HTList * adults;
                    183:     HTList *grownups;
                    184:     HTParentAnchor * foundAnchor;
                    185: 
                    186:     free (tag);
                    187:     
                    188:     /* Select list from hash table */
1.2       timbl     189:     for(p=address, hash=0; *p; p++)
1.11    ! frystyk   190:        hash = (int) ((hash * 3 + (*(unsigned char*)p)) % HASH_SIZE);
1.1       timbl     191:     if (!adult_table)
                    192:         adult_table = (HTList**) calloc(HASH_SIZE, sizeof(HTList*));
                    193:     if (!adult_table[hash]) adult_table[hash] = HTList_new();
                    194:     adults = adult_table[hash];
                    195: 
                    196:     /* Search list for anchor */
                    197:     grownups = adults;
1.7       luotonen  198:     while ((foundAnchor = HTList_nextObject (grownups))) {
1.2       timbl     199:        if (equivalent(foundAnchor->address, address)) {
1.11    ! frystyk   200:        if (ANCH_TRACE)
        !           201:            fprintf(stderr, "FindAnchor.. %p with address `%s' already exists.\n",
1.8       frystyk   202:                    (void*) foundAnchor, address);
1.1       timbl     203:        return (HTAnchor *) foundAnchor;
                    204:       }
                    205:     }
                    206:     
1.11    ! frystyk   207:     /* Node not found : create new anchor. */
1.1       timbl     208:     foundAnchor = HTParentAnchor_new ();
1.11    ! frystyk   209:     if (ANCH_TRACE) fprintf(stderr, "FindAnchor.. %p with hash %d and address `%s' created\n", (void*)foundAnchor, hash, address);
        !           210: 
        !           211:     /* This is done earlier in the Proxy server */
        !           212:     if (HTImProxy) {
        !           213:        StrAllocCopy(foundAnchor->address, address);
        !           214:     } else {
        !           215:        StrAllocCopy(foundAnchor->address, address);
        !           216:        foundAnchor->address = HTSimplify(foundAnchor->address);
        !           217:     }
1.1       timbl     218:     HTList_addObject (adults, foundAnchor);
                    219:     return (HTAnchor *) foundAnchor;
                    220:   }
                    221: }
                    222: 
                    223: 
                    224: /*     Delete an anchor and possibly related things (auto garbage collection)
                    225: **     --------------------------------------------
                    226: **
                    227: **     The anchor is only deleted if the corresponding document is not loaded.
1.10      frystyk   228: **     All outgoing links from parent and children are deleted, and this
                    229: **     anchor is removed from the sources list of all its targets.
1.1       timbl     230: **     We also try to delete the targets whose documents are not loaded.
                    231: **     If this anchor's source list is empty, we delete it and its children.
                    232: */
                    233: 
                    234: PRIVATE void deleteLinks
1.3       timbl     235:   ARGS1 (HTAnchor *,me)
1.1       timbl     236: {
1.3       timbl     237:   if (! me)
1.1       timbl     238:     return;
                    239: 
                    240:   /* Recursively try to delete target anchors */
1.3       timbl     241:   if (me->mainLink.dest) {
                    242:     HTParentAnchor *parent = me->mainLink.dest->parent;
                    243:     HTList_removeObject (parent->sources, me);
1.1       timbl     244:     if (! parent->document)  /* Test here to avoid calling overhead */
                    245:       HTAnchor_delete (parent);
                    246:   }
1.3       timbl     247:   if (me->links) {  /* Extra destinations */
1.1       timbl     248:     HTLink *target;
1.7       luotonen  249:     while ((target = HTList_removeLastObject (me->links))) {
1.1       timbl     250:       HTParentAnchor *parent = target->dest->parent;
1.3       timbl     251:       HTList_removeObject (parent->sources, me);
1.1       timbl     252:       if (! parent->document)  /* Test here to avoid calling overhead */
                    253:        HTAnchor_delete (parent);
                    254:     }
                    255:   }
                    256: }
                    257: 
                    258: PUBLIC BOOL HTAnchor_delete
1.3       timbl     259:   ARGS1 (HTParentAnchor *,me)
1.1       timbl     260: {
                    261:   HTChildAnchor *child;
                    262: 
                    263:   /* Don't delete if document is loaded */
1.3       timbl     264:   if (me->document)
1.1       timbl     265:     return NO;
                    266: 
                    267:   /* Recursively try to delete target anchors */
1.3       timbl     268:   deleteLinks ((HTAnchor *) me);
1.1       timbl     269: 
1.3       timbl     270:   if (! HTList_isEmpty (me->sources)) {  /* There are still incoming links */
1.1       timbl     271:     /* Delete all outgoing links from children, if any */
1.3       timbl     272:     HTList *kids = me->children;
1.7       luotonen  273:     while ((child = HTList_nextObject (kids)))
1.1       timbl     274:       deleteLinks ((HTAnchor *) child);
                    275:     return NO;  /* Parent not deleted */
                    276:   }
                    277: 
                    278:   /* No more incoming links : kill everything */
                    279:   /* First, recursively delete children */
1.7       luotonen  280:   while ((child = HTList_removeLastObject (me->children))) {
1.1       timbl     281:     deleteLinks ((HTAnchor *) child);
                    282:     free (child->tag);
                    283:     free (child);
                    284:   }
                    285: 
                    286:   /* Now kill myself */
1.3       timbl     287:   HTList_delete (me->children);
                    288:   HTList_delete (me->sources);
                    289:   free (me->address);
1.1       timbl     290:   /* Devise a way to clean out the HTFormat if no longer needed (ref count?) */
1.3       timbl     291:   free (me);
1.6       timbl     292:   if (me->cacheItems) {
                    293:       HTCacheClear(me->cacheItems);
                    294:   }
1.1       timbl     295:   return YES;  /* Parent deleted */
                    296: }
                    297: 
                    298: 
                    299: /*             Move an anchor to the head of the list of its siblings
                    300: **             ------------------------------------------------------
                    301: **
                    302: **     This is to ensure that an anchor which might have already existed
                    303: **     is put in the correct order as we load the document.
                    304: */
                    305: 
1.10      frystyk   306: PUBLIC void HTAnchor_makeLastChild
1.3       timbl     307:   ARGS1(HTChildAnchor *,me)
1.1       timbl     308: {
1.3       timbl     309:   if (me->parent != (HTParentAnchor *) me) {  /* Make sure it's a child */
                    310:     HTList * siblings = me->parent->children;
                    311:     HTList_removeObject (siblings, me);
                    312:     HTList_addObject (siblings, me);
1.1       timbl     313:   }
                    314: }
                    315: 
                    316: /*     Data access functions
                    317: **     ---------------------
                    318: */
                    319: 
                    320: PUBLIC HTParentAnchor * HTAnchor_parent
1.3       timbl     321:   ARGS1 (HTAnchor *,me)
1.1       timbl     322: {
1.3       timbl     323:   return me ? me->parent : NULL;
1.1       timbl     324: }
                    325: 
1.10      frystyk   326: PUBLIC void HTAnchor_setDocument
1.3       timbl     327:   ARGS2 (HTParentAnchor *,me, HyperDoc *,doc)
1.1       timbl     328: {
1.3       timbl     329:   if (me)
                    330:     me->document = doc;
1.1       timbl     331: }
                    332: 
1.10      frystyk   333: PUBLIC HyperDoc * HTAnchor_document
1.3       timbl     334:   ARGS1 (HTParentAnchor *,me)
1.1       timbl     335: {
1.3       timbl     336:   return me ? me->document : NULL;
1.1       timbl     337: }
                    338: 
                    339: 
1.10      frystyk   340: #if 0
                    341: PUBLIC void HTAnchor_setAddress
1.3       timbl     342:   ARGS2 (HTAnchor *,me, char *,addr)
1.1       timbl     343: {
1.3       timbl     344:   if (me)
                    345:     StrAllocCopy (me->parent->address, addr);
1.1       timbl     346: }
1.10      frystyk   347: #endif
                    348: 
1.1       timbl     349: 
1.10      frystyk   350: PUBLIC char * HTAnchor_address
1.3       timbl     351:   ARGS1 (HTAnchor *,me)
1.1       timbl     352: {
                    353:   char *addr = NULL;
1.3       timbl     354:   if (me) {
                    355:     if (((HTParentAnchor *) me == me->parent) ||
                    356:        !((HTChildAnchor *) me)->tag) {  /* it's an adult or no tag */
                    357:       StrAllocCopy (addr, me->parent->address);
1.1       timbl     358:     }
                    359:     else {  /* it's a named child */
1.3       timbl     360:       addr = malloc (2 + strlen (me->parent->address)
                    361:                     + strlen (((HTChildAnchor *) me)->tag));
1.1       timbl     362:       if (addr == NULL) outofmem(__FILE__, "HTAnchor_address");
1.3       timbl     363:       sprintf (addr, "%s#%s", me->parent->address,
                    364:               ((HTChildAnchor *) me)->tag);
1.1       timbl     365:     }
                    366:   }
                    367:   return addr;
                    368: }
                    369: 
                    370: 
                    371: 
1.10      frystyk   372: PUBLIC void HTAnchor_setFormat
1.3       timbl     373:   ARGS2 (HTParentAnchor *,me, HTFormat ,form)
1.1       timbl     374: {
1.3       timbl     375:   if (me)
                    376:     me->format = form;
1.1       timbl     377: }
                    378: 
1.10      frystyk   379: PUBLIC HTFormat HTAnchor_format
1.3       timbl     380:   ARGS1 (HTParentAnchor *,me)
1.1       timbl     381: {
1.3       timbl     382:   return me ? me->format : NULL;
1.1       timbl     383: }
                    384: 
1.10      frystyk   385: PUBLIC void HTAnchor_clearIndex
1.9       frystyk   386:   ARGS1 (HTParentAnchor *,me)
                    387: {
                    388:   if (me)
                    389:     me->isIndex = NO;
                    390: }
1.1       timbl     391: 
1.10      frystyk   392: PUBLIC void HTAnchor_setIndex
1.3       timbl     393:   ARGS1 (HTParentAnchor *,me)
1.1       timbl     394: {
1.3       timbl     395:   if (me)
                    396:     me->isIndex = YES;
1.1       timbl     397: }
                    398: 
1.10      frystyk   399: PUBLIC BOOL HTAnchor_isIndex
1.3       timbl     400:   ARGS1 (HTParentAnchor *,me)
1.1       timbl     401: {
1.3       timbl     402:   return me ? me->isIndex : NO;
1.1       timbl     403: }
                    404: 
                    405: 
1.10      frystyk   406: PUBLIC BOOL HTAnchor_hasChildren
1.3       timbl     407:   ARGS1 (HTParentAnchor *,me)
1.1       timbl     408: {
1.3       timbl     409:   return me ? ! HTList_isEmpty(me->children) : NO;
1.1       timbl     410: }
                    411: 
                    412: /*     Title handling
                    413: */
1.10      frystyk   414: PUBLIC CONST char * HTAnchor_title
1.3       timbl     415:   ARGS1 (HTParentAnchor *,me)
1.1       timbl     416: {
1.3       timbl     417:   return me ? me->title : 0;
1.1       timbl     418: }
                    419: 
1.10      frystyk   420: PUBLIC void HTAnchor_setTitle
1.3       timbl     421:   ARGS2(HTParentAnchor *,me, CONST char *,title)
1.1       timbl     422: {
1.3       timbl     423:   StrAllocCopy(me->title, title);
1.1       timbl     424: }
                    425: 
1.10      frystyk   426: PUBLIC void HTAnchor_appendTitle
1.3       timbl     427:   ARGS2(HTParentAnchor *,me, CONST char *,title)
1.1       timbl     428: {
1.3       timbl     429:   StrAllocCat(me->title, title);
1.1       timbl     430: }
                    431: 
1.3       timbl     432: /*     Link me Anchor to another given one
1.1       timbl     433: **     -------------------------------------
                    434: */
                    435: 
1.10      frystyk   436: PUBLIC BOOL HTAnchor_link
1.1       timbl     437:   ARGS3(HTAnchor *,source, HTAnchor *,destination, HTLinkType *,type)
                    438: {
                    439:   if (! (source && destination))
                    440:     return NO;  /* Can't link to/from non-existing anchor */
1.11    ! frystyk   441:   if (ANCH_TRACE)
        !           442:       fprintf(stderr, "LinkAnchor.. Linking anchor %p to anchor %p\n",
1.8       frystyk   443:              (void *) source, (void *) destination);
1.1       timbl     444:   if (! source->mainLink.dest) {
                    445:     source->mainLink.dest = destination;
                    446:     source->mainLink.type = type;
                    447:   } else {
                    448:     HTLink * newLink = (HTLink *) malloc (sizeof (HTLink));
                    449:     if (newLink == NULL) outofmem(__FILE__, "HTAnchor_link");
                    450:     newLink->dest = destination;
                    451:     newLink->type = type;
                    452:     if (! source->links)
                    453:       source->links = HTList_new ();
                    454:     HTList_addObject (source->links, newLink);
                    455:   }
                    456:   if (!destination->parent->sources)
                    457:     destination->parent->sources = HTList_new ();
                    458:   HTList_addObject (destination->parent->sources, source);
                    459:   return YES;  /* Success */
                    460: }
                    461: 
                    462: 
                    463: /*     Manipulation of links
                    464: **     ---------------------
                    465: */
                    466: 
1.10      frystyk   467: PUBLIC HTAnchor * HTAnchor_followMainLink
1.3       timbl     468:   ARGS1 (HTAnchor *,me)
1.1       timbl     469: {
1.3       timbl     470:   return me->mainLink.dest;
1.1       timbl     471: }
                    472: 
1.10      frystyk   473: PUBLIC HTAnchor * HTAnchor_followTypedLink
1.3       timbl     474:   ARGS2 (HTAnchor *,me, HTLinkType *,type)
1.1       timbl     475: {
1.3       timbl     476:   if (me->mainLink.type == type)
                    477:     return me->mainLink.dest;
                    478:   if (me->links) {
                    479:     HTList *links = me->links;
1.1       timbl     480:     HTLink *link;
1.7       luotonen  481:     while ((link = HTList_nextObject (links)))
1.1       timbl     482:       if (link->type == type)
                    483:        return link->dest;
                    484:   }
1.3       timbl     485:   return NULL;  /* No link of me type */
1.1       timbl     486: }
                    487: 
1.2       timbl     488: 
                    489: /*     Make main link
                    490: */
1.10      frystyk   491: PUBLIC BOOL HTAnchor_makeMainLink
1.3       timbl     492:   ARGS2 (HTAnchor *,me, HTLink *,movingLink)
1.1       timbl     493: {
                    494:   /* Check that everything's OK */
1.3       timbl     495:   if (! (me && HTList_removeObject (me->links, movingLink)))
1.1       timbl     496:     return NO;  /* link not found or NULL anchor */
                    497:   else {
                    498:     /* First push current main link onto top of links list */
                    499:     HTLink *newLink = (HTLink*) malloc (sizeof (HTLink));
                    500:     if (newLink == NULL) outofmem(__FILE__, "HTAnchor_makeMainLink");
1.3       timbl     501:     memcpy (newLink, & me->mainLink, sizeof (HTLink));
                    502:     HTList_addObject (me->links, newLink);
1.1       timbl     503: 
                    504:     /* Now make movingLink the new main link, and free it */
1.3       timbl     505:     memcpy (& me->mainLink, movingLink, sizeof (HTLink));
1.1       timbl     506:     free (movingLink);
                    507:     return YES;
                    508:   }
1.2       timbl     509: }
                    510: 
                    511: 
                    512: /*     Methods List
                    513: **     ------------
                    514: */
                    515: 
1.3       timbl     516: PUBLIC HTList * HTAnchor_methods ARGS1(HTParentAnchor *, me)
1.2       timbl     517: {
1.3       timbl     518:     if (!me->methods) {
                    519:         me->methods = HTList_new();
1.2       timbl     520:     }
1.3       timbl     521:     return me->methods;
1.2       timbl     522: }
                    523: 
                    524: /*     Protocol
                    525: **     --------
                    526: */
                    527: 
1.3       timbl     528: PUBLIC void * HTAnchor_protocol ARGS1(HTParentAnchor *, me)
1.2       timbl     529: {
1.3       timbl     530:     return me->protocol;
1.2       timbl     531: }
                    532: 
1.3       timbl     533: PUBLIC void HTAnchor_setProtocol ARGS2(HTParentAnchor *, me,
1.2       timbl     534:        void*,  protocol)
                    535: {
1.3       timbl     536:     me->protocol = protocol;
1.2       timbl     537: }
                    538: 
                    539: /*     Physical Address
                    540: **     ----------------
                    541: */
                    542: 
1.3       timbl     543: PUBLIC char * HTAnchor_physical ARGS1(HTParentAnchor *, me)
1.2       timbl     544: {
1.3       timbl     545:     return me->physical;
1.2       timbl     546: }
                    547: 
1.3       timbl     548: PUBLIC void HTAnchor_setPhysical ARGS2(HTParentAnchor *, me,
1.2       timbl     549:        char *, physical)
                    550: {
1.9       frystyk   551:     if (!me || !physical) {
1.11    ! frystyk   552:        if (ANCH_TRACE)
1.9       frystyk   553:            fprintf(stderr, "HTAnchor.... setPhysical, called with null argument\n");
                    554:        return;
                    555:     }
1.3       timbl     556:     StrAllocCopy(me->physical, physical);
1.1       timbl     557: }
1.10      frystyk   558: 

Webmaster