1
/* Hypertext "Anchor" Object HTAnchor.c
2
** ==========================
4
** An anchor represents a region of a hypertext document which is linked to
5
** another anchor in the same or a different document.
9
** Nov 1990 Written in Objective-C for the NeXT browser (TBL)
10
** 24-Oct-1991 (JFG), written in C, browser-independent
11
** 21-Nov-1991 (JFG), first complete version
13
** (c) Copyright CERN 1991 - See Copyright.html
16
#define HASH_SIZE 101 /* Arbitrary prime. Memory/speed tradeoff */
27
#include <LYCharSets.h>
32
* This is the hashing function used to determine which list in the
33
* adult_table a parent anchor should be put in. This is a
34
* much simpler function than the original used.
36
#define HASH_FUNCTION(cp_address) ((unsigned short int)strlen(cp_address) *\
37
(unsigned short int)TOUPPER(*cp_address) % HASH_SIZE)
38
#endif /* NOT_DEFINED */
40
* This is the original function. We'll use it again. - FM
42
PRIVATE int HASH_FUNCTION ARGS1(
43
CONST char *, cp_address)
46
CONST unsigned char *p;
48
for (p = (CONST unsigned char *)cp_address, hash = 0; *p; p++)
49
hash = (int) (hash * 3 + (*(CONST unsigned char *)p)) % HASH_SIZE;
54
typedef struct _HyperDoc Hyperdoc;
57
int junk; /* VMS cannot handle pointers to undefined structs */
61
/* Table of lists of all parents */
62
PRIVATE HTList adult_table[HASH_SIZE] = { {NULL, NULL} };
68
** Do not use "new" by itself outside this module. In order to enforce
69
** consistency, we insist that you furnish more information about the
70
** anchor you are creating : use newWithParent or newWithAddress.
72
PRIVATE HTParentAnchor0 * HTParentAnchor0_new ARGS2(
73
CONST char *, address,
76
HTParentAnchor0 *newAnchor = typecalloc(HTParentAnchor0);
77
if (newAnchor == NULL)
78
outofmem(__FILE__, "HTParentAnchor0_new");
80
newAnchor->parent = newAnchor; /* self */
81
StrAllocCopy(newAnchor->address, address);
82
newAnchor->adult_hash = hash;
87
PRIVATE HTParentAnchor * HTParentAnchor_new ARGS1(
88
HTParentAnchor0 *, parent)
90
HTParentAnchor *newAnchor = typecalloc(HTParentAnchor);
91
if (newAnchor == NULL)
92
outofmem(__FILE__, "HTParentAnchor_new");
94
newAnchor->parent = parent; /* cross reference */
95
parent->info = newAnchor; /* cross reference */
96
newAnchor->address = parent->address; /* copy pointer */
98
newAnchor->isISMAPScript = FALSE; /* Lynx appends ?0,0 if TRUE. - FM */
99
newAnchor->isHEAD = FALSE; /* HEAD request if TRUE. - FM */
100
newAnchor->safe = FALSE; /* Safe. - FM */
101
newAnchor->no_cache = FALSE; /* no-cache? - FM */
102
newAnchor->inBASE = FALSE; /* duplicated from HTML.c/h */
103
newAnchor->content_length = 0; /* Content-Length. - FM */
107
PRIVATE HTChildAnchor * HTChildAnchor_new ARGS1(
108
HTParentAnchor0 *, parent)
110
HTChildAnchor *p = typecalloc(HTChildAnchor);
112
outofmem(__FILE__, "HTChildAnchor_new");
114
p->parent = parent; /* parent reference */
118
PRIVATE HTChildAnchor * HText_pool_ChildAnchor_new ARGS1(
119
HTParentAnchor *, parent)
121
HTChildAnchor *p = (HTChildAnchor *)HText_pool_calloc((HText*)(parent->document),
122
sizeof(HTChildAnchor));
124
outofmem(__FILE__, "HText_pool_ChildAnchor_new");
126
p->parent = parent->parent; /* parent reference */
130
#ifdef CASE_INSENSITIVE_ANCHORS
131
/* Case insensitive string comparison */
132
#define HT_EQUIV(a,b) (TOUPPER(a) == TOUPPER(b))
134
/* Case sensitive string comparison */
135
#define HT_EQUIV(a,b) ((a) == (b))
138
/* Null-terminated string comparison
139
** ---------------------------------
141
** s Points to one string, null terminated
142
** t points to the other.
144
** returns YES if the strings are equivalent
145
** NO if they differ.
147
PRIVATE BOOL HTSEquivalent ARGS2(
151
if (s && t) { /* Make sure they point to something */
152
for (; *s && *t; s++, t++) {
153
if (!HT_EQUIV(*s, *t)) {
157
return(HT_EQUIV(*s, *t));
159
return(s == t); /* Two NULLs are equivalent, aren't they ? */
163
/* Binary string comparison
164
** ------------------------
166
** s Points to one bstring
167
** t points to the other.
169
** returns YES if the strings are equivalent
170
** NO if they differ.
172
PRIVATE BOOL HTBEquivalent ARGS2(
176
if (s && t && BStrLen(s) == BStrLen(t)) {
178
int len = BStrLen(s);
179
for (j = 0; j < len; ++j) {
180
if (!HT_EQUIV(BStrData(s)[j], BStrData(t)[j])) {
186
return(s == t); /* Two NULLs are equivalent, aren't they ? */
191
* Three-way compare function
193
PRIVATE int compare_anchors ARGS2(
197
CONST char* a = ((HTChildAnchor *)l)->tag;
198
CONST char* b = ((HTChildAnchor *)r)->tag;
199
/* both tags are not NULL */
201
#ifdef CASE_INSENSITIVE_ANCHORS
202
return strcasecomp(a, b); /* Case insensitive */
204
return strcmp(a, b); /* Case sensitive - FM */
205
#endif /* CASE_INSENSITIVE_ANCHORS */
209
/* Create new or find old sub-anchor
210
** ---------------------------------
212
** This one is for a named child.
213
** The parent anchor must already exist.
215
PRIVATE HTChildAnchor * HTAnchor_findNamedChild ARGS2(
216
HTParentAnchor0 *, parent,
219
HTChildAnchor *child;
221
if (parent && tag && *tag) { /* TBL */
222
if (parent->children) {
224
** Parent has children. Search them.
226
HTChildAnchor sample;
227
sample.tag = (char*)tag; /* for compare_anchors() only */
229
child = (HTChildAnchor *)HTBTree_search(parent->children, &sample);
231
CTRACE((tfp, "Child anchor %p of parent %p with name `%s' already exists.\n",
232
(void *)child, (void *)parent, tag));
235
} else { /* parent doesn't have any children yet : create family */
236
parent->children = HTBTree_new(compare_anchors);
239
child = HTChildAnchor_new(parent);
240
CTRACE((tfp, "HTAnchor: New Anchor %p named `%s' is child of %p\n",
243
(void *)child->parent));
245
StrAllocCopy(child->tag, tag); /* should be set before HTBTree_add */
246
HTBTree_add(parent->children, child);
250
CTRACE((tfp, "HTAnchor_findNamedChild called with NULL parent.\n"));
257
** This one is for a new unnamed child being edited into an existing
258
** document. The parent anchor and the document must already exist.
259
** (Just add new unnamed child).
261
PRIVATE HTChildAnchor * HTAnchor_addChild ARGS1(
262
HTParentAnchor *, parent)
264
HTChildAnchor *child;
267
CTRACE((tfp, "HTAnchor_addChild called with NULL parent.\n"));
271
child = HText_pool_ChildAnchor_new(parent);
272
CTRACE((tfp, "HTAnchor: New unnamed Anchor %p is child of %p\n",
274
(void *)child->parent));
277
HTList_linkObject(&parent->children_notag, child, &child->_add_children_notag);
283
PRIVATE HTParentAnchor0 * HTAnchor_findAddress_in_adult_table PARAMS((
284
CONST DocAddress * newdoc));
286
PRIVATE BOOL HTAnchor_link PARAMS((
287
HTChildAnchor * child,
288
HTAnchor * destination,
292
/* Create or find a child anchor with a possible link
293
** --------------------------------------------------
295
** Create new anchor with a given parent and possibly
296
** a name, and possibly a link to a _relatively_ named anchor.
297
** (Code originally in ParseHTML.h)
299
PUBLIC HTChildAnchor * HTAnchor_findChildAndLink ARGS4(
300
HTParentAnchor *, parent, /* May not be 0 */
301
CONST char *, tag, /* May be "" or 0 */
302
CONST char *, href, /* May be "" or 0 */
303
HTLinkType *, ltype) /* May be 0 */
305
HTChildAnchor * child;
306
CTRACE((tfp,"Entered HTAnchor_findChildAndLink: tag=`%s',%s href=`%s'\n",
308
(ltype == HTInternalLink) ? " (internal link)" : "",
312
child = HTAnchor_findNamedChild(parent->parent, tag);
314
child = HTAnchor_addChild(parent);
318
CONST char *fragment = NULL;
319
HTParentAnchor0 * dest;
321
if (ltype == HTInternalLink && *href == '#') {
322
dest = parent->parent;
324
CONST char *relative_to = (parent->inBASE && *href != '#') ?
325
parent->content_base : parent->address;
326
DocAddress parsed_doc;
327
parsed_doc.address = HTParse(href, relative_to,
328
PARSE_ALL_WITHOUT_ANCHOR);
330
parsed_doc.post_data = NULL;
331
parsed_doc.post_content_type = NULL;
332
if (ltype && parent->post_data && ltype == HTInternalLink) {
333
/* for internal links, find a destination with the same
334
post data if the source of the link has post data. - kw
335
Example: LYNXIMGMAP: */
336
parsed_doc.post_data = parent->post_data;
337
parsed_doc.post_content_type = parent->post_content_type;
339
parsed_doc.bookmark = NULL;
340
parsed_doc.isHEAD = FALSE;
341
parsed_doc.safe = FALSE;
343
dest = HTAnchor_findAddress_in_adult_table(&parsed_doc);
344
FREE(parsed_doc.address);
348
** [from HTAnchor_findAddress()]
349
** If the address represents a sub-anchor, we load its parent (above),
350
** then we create a named child anchor within that parent.
352
fragment = (*href == '#') ? href+1 : HTParseAnchor(href);
355
dest = (HTParentAnchor0 *)HTAnchor_findNamedChild(dest, fragment);
359
if (child->dest) { /* DUPLICATE_ANCHOR_NAME_WORKAROUND - kw */
361
"*** Duplicate ChildAnchor %p named `%s'",
363
if ((HTAnchor *)dest != child->dest || ltype != child->type) {
365
", different dest %p or type, creating unnamed child\n",
367
child = HTAnchor_addChild(parent);
371
HTAnchor_link(child, (HTAnchor *)dest, ltype);
377
/* Create new or find old parent anchor
378
** ------------------------------------
380
** Me one is for a reference which is found in a document, and might
381
** not be already loaded.
382
** Note: You are not guaranteed a new anchor -- you might get an old one,
385
PUBLIC HTParentAnchor * HTAnchor_findAddress ARGS1(
386
CONST DocAddress *, newdoc)
388
/* Anchor tag specified ? */
389
CONST char *tag = HTParseAnchor(newdoc->address);
391
CTRACE((tfp,"Entered HTAnchor_findAddress\n"));
394
** If the address represents a sub-anchor, we load its parent,
395
** then we create a named child anchor within that parent.
398
DocAddress parsed_doc;
399
HTParentAnchor0 * foundParent;
400
HTChildAnchor * foundAnchor;
402
parsed_doc.address = HTParse(newdoc->address, "",
403
PARSE_ALL_WITHOUT_ANCHOR);
404
parsed_doc.post_data = newdoc->post_data;
405
parsed_doc.post_content_type = newdoc->post_content_type;
406
parsed_doc.bookmark = newdoc->bookmark;
407
parsed_doc.isHEAD = newdoc->isHEAD;
408
parsed_doc.safe = newdoc->safe;
410
foundParent = HTAnchor_findAddress_in_adult_table(&parsed_doc);
411
foundAnchor = HTAnchor_findNamedChild (foundParent, tag);
412
FREE(parsed_doc.address);
413
return HTAnchor_parent((HTAnchor *)foundParent);
415
return HTAnchor_parent((HTAnchor *)HTAnchor_findAddress_in_adult_table(newdoc));
419
/* The address has no anchor tag, for sure.
421
PRIVATE HTParentAnchor0 * HTAnchor_findAddress_in_adult_table ARGS1(
422
CONST DocAddress *, newdoc)
425
** Check whether we have this node.
430
HTParentAnchor0 * foundAnchor;
431
BOOL need_extra_info = (newdoc->post_data || newdoc->post_content_type ||
432
newdoc->bookmark || newdoc->isHEAD || newdoc->safe);
435
* We need not free adult_table[] atexit -
436
* it should be perfectly empty after free'ing all HText's.
437
* (There is an error if it is not empty at exit). -LP
441
** Select list from hash table,
443
hash = HASH_FUNCTION(newdoc->address);
444
adults = &(adult_table[hash]);
447
** Search list for anchor.
450
while (NULL != (foundAnchor =
451
(HTParentAnchor0 *)HTList_nextObject(grownups))) {
452
if (HTSEquivalent(foundAnchor->address, newdoc->address) &&
454
((!foundAnchor->info && !need_extra_info) ||
455
(foundAnchor->info &&
456
HTBEquivalent(foundAnchor->info->post_data, newdoc->post_data) &&
457
foundAnchor->info->isHEAD == newdoc->isHEAD)))
459
CTRACE((tfp, "Anchor %p with address `%s' already exists.\n",
460
(void *)foundAnchor, newdoc->address));
466
** Node not found: create new anchor.
468
foundAnchor = HTParentAnchor0_new(newdoc->address, hash);
469
CTRACE((tfp, "New anchor %p has hash %d and address `%s'\n",
470
(void *)foundAnchor, hash, newdoc->address));
472
if (need_extra_info) {
473
/* rare case, create a big structure */
474
HTParentAnchor *p = HTParentAnchor_new(foundAnchor);
476
if (newdoc->post_data)
477
BStrCopy(p->post_data, newdoc->post_data);
478
if (newdoc->post_content_type)
479
StrAllocCopy(p->post_content_type,
480
newdoc->post_content_type);
481
if (newdoc->bookmark)
482
StrAllocCopy(p->bookmark, newdoc->bookmark);
483
p->isHEAD = newdoc->isHEAD;
484
p->safe = newdoc->safe;
486
HTList_linkObject(adults, foundAnchor, &foundAnchor->_add_adult);
491
/* Create new or find old named anchor - simple form
492
** -------------------------------------------------
494
** Like HTAnchor_findAddress, but simpler to use for simple cases.
495
** No post data etc. can be supplied. - kw
497
PUBLIC HTParentAnchor * HTAnchor_findSimpleAddress ARGS1(
502
urldoc.address = (char *)url; /* ignore warning, it IS treated like const - kw */
503
urldoc.post_data = NULL;
504
urldoc.post_content_type = NULL;
505
urldoc.bookmark = NULL;
506
urldoc.isHEAD = FALSE;
508
return HTAnchor_findAddress(&urldoc);
512
/* Link me Anchor to another given one
513
** -------------------------------------
515
PRIVATE BOOL HTAnchor_link ARGS3(
516
HTChildAnchor *, child,
517
HTAnchor *, destination,
520
if (!(child && destination))
521
return(NO); /* Can't link to/from non-existing anchor */
523
CTRACE((tfp, "Linking child %p to anchor %p\n", child, destination));
525
CTRACE((tfp, "*** child anchor already has destination, exiting!\n"));
529
child->dest = destination;
532
if (child->parent != destination->parent)
533
/* link only foreign children */
534
HTList_linkObject(&destination->parent->sources, child, &child->_add_sources);
536
return(YES); /* Success */
540
/* Delete an anchor and possibly related things (auto garbage collection)
541
** --------------------------------------------
543
** The anchor is only deleted if the corresponding document is not loaded.
544
** All outgoing links from children are deleted, and children are
545
** removed from the sources lists of theirs targets.
546
** We also try to delete the targets whose documents are not loaded.
547
** If this anchor's sources list is empty, we delete it and its children.
551
* Recursively try to delete destination anchor of this child.
552
* In any event, this will tell destination anchor that we
553
* no longer consider it a destination.
555
PRIVATE void deleteLinks ARGS1(
559
* Unregister me with our destination anchor's parent.
562
HTParentAnchor0 *parent = me->dest->parent;
565
* Start. Set the dest pointer to zero.
570
* Remove me from the parent's sources so that the
571
* parent knows one less anchor is its dest.
573
if ((me->parent != parent) && !HTList_isEmpty(&parent->sources)) {
575
* Really should only need to deregister once.
577
HTList_unlinkObject(&parent->sources, (void *)me);
582
* Test here to avoid calling overhead.
583
* Don't delete if document is loaded or being loaded.
585
if ((me->parent != parent) && !parent->underway &&
586
(!parent->info || !parent->info->document)) {
587
HTAnchor_delete(parent);
591
* At this point, we haven't a destination. Set it to be
593
* Leave the HTAtom pointed to by type up to other code to
594
* handle (reusable, near static).
601
PRIVATE void HTParentAnchor_free PARAMS((
602
HTParentAnchor * me));
604
PUBLIC BOOL HTAnchor_delete ARGS1(
605
HTParentAnchor0 *, me)
608
* Memory leaks fixed.
609
* 05-27-94 Lynx 2-3-1 Garrett Arch Blythe
612
HTChildAnchor *child;
615
* Do nothing if nothing to do.
622
* Don't delete if document is loaded or being loaded.
624
if (me->underway || (me->info && me->info->document)) {
629
* Mark ourselves busy, so that recursive calls of this function
630
* on this HTParentAnchor0 will not free it from under our feet. - kw
636
* Delete all outgoing links from named children.
637
* Do not delete named children itself (may have incoming links).
640
ele = HTBTree_next(me->children, NULL);
641
while (ele != NULL) {
642
child = (HTChildAnchor *)HTBTree_object(ele);
645
ele = HTBTree_next(me->children, ele);
649
me->underway = FALSE;
653
* There are still incoming links to this one (we are the
654
* destination of another anchor).
656
if (!HTList_isEmpty(&me->sources)) {
658
* Can't delete parent, still have sources.
664
* No more incoming and outgoing links : kill everything
665
* First, delete named children.
668
ele = HTBTree_next(me->children, NULL);
669
while (ele != NULL) {
670
child = (HTChildAnchor *)HTBTree_object(ele);
673
ele = HTBTree_next(me->children, ele);
675
HTBTree_free(me->children);
679
* Delete the ParentAnchor, if any. (Document was already deleted).
682
HTParentAnchor_free(me->info);
687
* Remove ourselves from the hash table's list.
689
HTList_unlinkObject(&(adult_table[me->adult_hash]), (void *)me);
697
* Finally, kill the parent anchor passed in.
705
* Unnamed children (children_notag) have no sence without HText -
706
* delete them and their links if we are about to free HText.
707
* Document currently exists. Called within HText_free().
709
PUBLIC void HTAnchor_delete_links ARGS1(
710
HTParentAnchor *, me)
713
HTChildAnchor *child;
716
* Do nothing if nothing to do.
718
if (!me || !me->document) {
723
* Mark ourselves busy, so that recursive calls
724
* on this HTParentAnchor0 will not free it from under our feet. - kw
726
me->parent->underway = TRUE;
729
* Delete all outgoing links from unnamed children.
731
if (!HTList_isEmpty(&me->children_notag)) {
732
cur = &me->children_notag;
734
(HTChildAnchor *)HTList_unlinkLastObject(cur)) != 0) {
736
/* child allocated in HText pool, HText_free() will free it later*/
739
me->parent->underway = FALSE;
743
PRIVATE void HTParentAnchor_free ARGS1(
744
HTParentAnchor *, me)
747
* Delete the methods list.
751
* Leave what the methods point to up in memory for
752
* other code (near static stuff).
754
HTList_delete(me->methods);
759
* Free up all allocated members.
762
FREE(me->isIndexAction);
763
FREE(me->isIndexPrompt);
766
BStrFree(me->post_data);
767
FREE(me->post_content_type);
772
#ifdef USE_SOURCE_CACHE
773
HTAnchor_clearSourceCache(me);
777
if ((fd = fopen(me->FileCache, "r")) != NULL) {
779
remove(me->FileCache);
784
FREE(me->cache_control);
785
FREE(me->content_type);
786
FREE(me->content_language);
787
FREE(me->content_encoding);
788
FREE(me->content_base);
789
FREE(me->content_disposition);
790
FREE(me->content_location);
791
FREE(me->content_md5);
792
FREE(me->message_id);
797
FREE(me->last_modified);
800
#ifdef USE_COLOR_STYLE
805
* Original code wanted a way to clean out the HTFormat if no
806
* longer needed (ref count?). I'll leave it alone since
807
* those HTAtom objects are a little harder to know where
808
* they are being referenced all at one time. (near static)
812
ImageMapList_free(me->imaps);
815
#ifdef USE_SOURCE_CACHE
816
PUBLIC void HTAnchor_clearSourceCache ARGS1(
817
HTParentAnchor *, me)
820
* Clean up the source cache, if any.
822
if (me->source_cache_file) {
823
CTRACE((tfp, "SourceCache: Removing file %s\n",
824
me->source_cache_file));
825
LYRemoveTemp(me->source_cache_file);
826
FREE(me->source_cache_file);
828
if (me->source_cache_chunk) {
829
CTRACE((tfp, "SourceCache: Removing memory chunk %p\n",
830
(void *)me->source_cache_chunk));
831
HTChunkFree(me->source_cache_chunk);
832
me->source_cache_chunk = NULL;
835
#endif /* USE_SOURCE_CACHE */
837
/* Data access functions
838
** ---------------------
840
PUBLIC HTParentAnchor * HTAnchor_parent ARGS1(
846
if (me->parent->info)
847
return me->parent->info;
849
/* else: create a new structure */
850
return HTParentAnchor_new(me->parent);
853
PUBLIC void HTAnchor_setDocument ARGS2(
854
HTParentAnchor *, me,
861
PUBLIC HyperDoc * HTAnchor_document ARGS1(
862
HTParentAnchor *, me)
864
return( me ? me->document : NULL);
868
PUBLIC char * HTAnchor_address ARGS1(
874
if (((HTParentAnchor0 *)me == me->parent) ||
875
((HTParentAnchor *)me == me->parent->info) ||
876
!((HTChildAnchor *)me)->tag) { /* it's an adult or no tag */
877
StrAllocCopy(addr, me->parent->address);
878
} else { /* it's a named child */
879
HTSprintf0(&addr, "%s#%s",
880
me->parent->address, ((HTChildAnchor *)me)->tag);
886
PUBLIC void HTAnchor_setFormat ARGS2(
887
HTParentAnchor *, me,
894
PUBLIC HTFormat HTAnchor_format ARGS1(
895
HTParentAnchor *, me)
897
return( me ? me->format : NULL);
900
PUBLIC void HTAnchor_setIndex ARGS2(
901
HTParentAnchor *, me,
902
CONST char *, address)
906
StrAllocCopy(me->isIndexAction, address);
910
PUBLIC void HTAnchor_setPrompt ARGS2(
911
HTParentAnchor *, me,
912
CONST char *, prompt)
915
StrAllocCopy(me->isIndexPrompt, prompt);
919
PUBLIC BOOL HTAnchor_isIndex ARGS1(
920
HTParentAnchor *, me)
922
return( me ? me->isIndex : NO);
925
/* Whether Anchor has been designated as an ISMAP link
926
** (normally by presence of an ISMAP attribute on A or IMG) - KW
928
PUBLIC BOOL HTAnchor_isISMAPScript ARGS1(
931
return( (me && me->parent->info) ? me->parent->info->isISMAPScript : NO);
934
#if defined(USE_COLOR_STYLE)
937
PUBLIC CONST char * HTAnchor_style ARGS1(
938
HTParentAnchor *, me)
940
return( me ? me->style : NULL);
943
PUBLIC void HTAnchor_setStyle ARGS2(
944
HTParentAnchor *, me,
948
StrAllocCopy(me->style, style);
956
PUBLIC CONST char * HTAnchor_title ARGS1(
957
HTParentAnchor *, me)
959
return( me ? me->title : NULL);
962
PUBLIC void HTAnchor_setTitle ARGS2(
963
HTParentAnchor *, me,
970
StrAllocCopy(me->title, title);
971
for (i = 0; me->title[i]; i++) {
972
if (UCH(me->title[i]) == 1 ||
973
UCH(me->title[i]) == 2) {
978
CTRACE((tfp,"HTAnchor_setTitle: New title is NULL! "));
980
CTRACE((tfp,"Old title was \"%s\".\n", me->title));
983
CTRACE((tfp,"Old title was NULL.\n"));
989
PUBLIC void HTAnchor_appendTitle ARGS2(
990
HTParentAnchor *, me,
996
StrAllocCat(me->title, title);
997
for (i = 0; me->title[i]; i++) {
998
if (UCH(me->title[i]) == 1 ||
999
UCH(me->title[i]) == 2) {
1006
/* Bookmark handling.
1008
PUBLIC CONST char * HTAnchor_bookmark ARGS1(
1009
HTParentAnchor *, me)
1011
return( me ? me->bookmark : NULL);
1014
PUBLIC void HTAnchor_setBookmark ARGS2(
1015
HTParentAnchor *, me,
1016
CONST char *, bookmark)
1019
StrAllocCopy(me->bookmark, bookmark);
1024
PUBLIC CONST char * HTAnchor_owner ARGS1(
1025
HTParentAnchor *, me)
1027
return( me ? me->owner : NULL);
1030
PUBLIC void HTAnchor_setOwner ARGS2(
1031
HTParentAnchor *, me,
1032
CONST char *, owner)
1035
StrAllocCopy(me->owner, owner);
1039
/* TITLE handling in LINKs with REV="made" or REV="owner". - FM
1041
PUBLIC CONST char * HTAnchor_RevTitle ARGS1(
1042
HTParentAnchor *, me)
1044
return( me ? me->RevTitle : NULL);
1047
PUBLIC void HTAnchor_setRevTitle ARGS2(
1048
HTParentAnchor *, me,
1049
CONST char *, title)
1054
StrAllocCopy(me->RevTitle, title);
1055
for (i = 0; me->RevTitle[i]; i++) {
1056
if (UCH(me->RevTitle[i]) == 1 ||
1057
UCH(me->RevTitle[i]) == 2) {
1058
me->RevTitle[i] = ' ';
1064
#ifndef DISABLE_BIBP
1065
/* Citehost for bibp links from LINKs with REL="citehost". - RDC
1067
PUBLIC CONST char * HTAnchor_citehost ARGS1(
1068
HTParentAnchor *, me)
1070
return( me ? me->citehost : NULL);
1073
PUBLIC void HTAnchor_setCitehost ARGS2(
1074
HTParentAnchor *, me,
1075
CONST char *, citehost)
1078
StrAllocCopy(me->citehost, citehost);
1081
#endif /* !DISABLE_BIBP */
1083
/* Suggested filename handling. - FM
1084
** (will be loaded if we had a Content-Disposition
1085
** header or META element with filename=name.suffix)
1087
PUBLIC CONST char * HTAnchor_SugFname ARGS1(
1088
HTParentAnchor *, me)
1090
return( me ? me->SugFname : NULL);
1093
/* Content-Encoding handling. - FM
1094
** (will be loaded if we had a Content-Encoding
1097
PUBLIC CONST char * HTAnchor_content_encoding ARGS1(
1098
HTParentAnchor *, me)
1100
return( me ? me->content_encoding : NULL);
1103
/* Content-Type handling. - FM
1105
PUBLIC CONST char * HTAnchor_content_type ARGS1(
1106
HTParentAnchor *, me)
1108
return( me ? me->content_type : NULL);
1111
/* Last-Modified header handling. - FM
1113
PUBLIC CONST char * HTAnchor_last_modified ARGS1(
1114
HTParentAnchor *, me)
1116
return( me ? me->last_modified : NULL);
1119
/* Date header handling. - FM
1121
PUBLIC CONST char * HTAnchor_date ARGS1(
1122
HTParentAnchor *, me)
1124
return( me ? me->date : NULL);
1127
/* Server header handling. - FM
1129
PUBLIC CONST char * HTAnchor_server ARGS1(
1130
HTParentAnchor *, me)
1132
return( me ? me->server : NULL);
1135
/* Safe header handling. - FM
1137
PUBLIC BOOL HTAnchor_safe ARGS1(
1138
HTParentAnchor *, me)
1140
return (BOOL) ( me ? me->safe : FALSE);
1143
/* Content-Base header handling. - FM
1145
PUBLIC CONST char * HTAnchor_content_base ARGS1(
1146
HTParentAnchor *, me)
1148
return( me ? me->content_base : NULL);
1151
/* Content-Location header handling. - FM
1153
PUBLIC CONST char * HTAnchor_content_location ARGS1(
1154
HTParentAnchor *, me)
1156
return( me ? me->content_location : NULL);
1159
/* Message-ID, used for mail replies - kw
1161
PUBLIC CONST char * HTAnchor_messageID ARGS1(
1162
HTParentAnchor *, me)
1164
return( me ? me->message_id : NULL);
1167
PUBLIC BOOL HTAnchor_setMessageID ARGS2(
1168
HTParentAnchor *, me,
1169
CONST char *, messageid)
1171
if (!(me && messageid && *messageid)) {
1174
StrAllocCopy(me->message_id, messageid);
1178
/* Subject, used for mail replies - kw
1180
PUBLIC CONST char * HTAnchor_subject ARGS1(
1181
HTParentAnchor *, me)
1183
return( me ? me->subject : NULL);
1186
PUBLIC BOOL HTAnchor_setSubject ARGS2(
1187
HTParentAnchor *, me,
1188
CONST char *, subject)
1190
if (!(me && subject && *subject)) {
1193
StrAllocCopy(me->subject, subject);
1197
/* Manipulation of links
1198
** ---------------------
1200
PUBLIC HTAnchor * HTAnchor_followLink ARGS1(
1201
HTChildAnchor *, me)
1206
PUBLIC HTAnchor * HTAnchor_followTypedLink ARGS2(
1207
HTChildAnchor *, me,
1210
if (me->type == type)
1212
return(NULL); /* No link of me type */
1219
PUBLIC HTList * HTAnchor_methods ARGS1(
1220
HTParentAnchor *, me)
1223
me->methods = HTList_new();
1225
return( me->methods);
1231
PUBLIC void * HTAnchor_protocol ARGS1(
1232
HTParentAnchor *, me)
1234
return( me->protocol);
1237
PUBLIC void HTAnchor_setProtocol ARGS2(
1238
HTParentAnchor *, me,
1241
me->protocol = protocol;
1247
PUBLIC char * HTAnchor_physical ARGS1(
1248
HTParentAnchor *, me)
1250
return( me->physical);
1253
PUBLIC void HTAnchor_setPhysical ARGS2(
1254
HTParentAnchor *, me,
1258
StrAllocCopy(me->physical, physical);
1263
** We store charset info in the HTParentAnchor object, for several
1264
** "stages". (See UCDefs.h)
1265
** A stream method is supposed to know what stage in the model it is.
1267
** General model MIME -> parser -> structured -> HText
1269
** from HTTP: HTMIME.c -> SGML.c -> HTML.c -> GridText.c
1271
** from file: HTFile.c -> HTPlain.c -> GridText.c
1273
** The lock/set_by is used to lock e.g. a charset set by an explicit
1274
** HTTP MIME header against overriding by a HTML META tag - the MIME
1275
** header has higher priority. Defaults (from -assume_.. options etc.)
1276
** will not override charset explicitly given by server.
1278
** Some advantages of keeping this in the HTAnchor:
1279
** - Global variables are bad.
1280
** - Can remember a charset given by META tag when toggling to SOURCE view.
1281
** - Can remember a charset given by <A CHARSET=...> href in another doc.
1283
** We don't modify the HTParentAnchor's charset element
1284
** here, that one will only be set when explicitly given.
1286
PUBLIC LYUCcharset * HTAnchor_getUCInfoStage ARGS2(
1287
HTParentAnchor *, me,
1290
if (me && !me->UCStages) {
1292
int chndl = UCLYhndl_for_unspec; /* always >= 0 */
1293
UCAnchorInfo * stages = typecalloc(UCAnchorInfo);
1295
outofmem(__FILE__, "HTAnchor_getUCInfoStage");
1296
for (i = 0; i < UCT_STAGEMAX; i++) {
1297
stages->s[i].C.MIMEname = "";
1298
stages->s[i].LYhndl = -1;
1301
chndl = UCGetLYhndl_byMIME(me->charset);
1303
chndl = UCLYhndl_for_unrec;
1306
** UCLYhndl_for_unrec not defined :-(
1307
** fallback to UCLYhndl_for_unspec which always valid.
1309
chndl = UCLYhndl_for_unspec; /* always >= 0 */
1311
memcpy(&stages->s[UCT_STAGE_MIME].C, &LYCharSet_UC[chndl],
1312
sizeof(LYUCcharset));
1313
stages->s[UCT_STAGE_MIME].lock = UCT_SETBY_DEFAULT;
1314
stages->s[UCT_STAGE_MIME].LYhndl = chndl;
1315
me->UCStages = stages;
1318
return( &me->UCStages->s[which_stage].C);
1323
PUBLIC int HTAnchor_getUCLYhndl ARGS2(
1324
HTParentAnchor *, me,
1328
if (!me->UCStages) {
1330
* This will allocate and initialize, if not yet done.
1332
(void) HTAnchor_getUCInfoStage(me, which_stage);
1334
if (me->UCStages->s[which_stage].lock > UCT_SETBY_NONE) {
1335
return( me->UCStages->s[which_stage].LYhndl);
1341
#ifdef CAN_SWITCH_DISPLAY_CHARSET
1342
PRIVATE void setup_switch_display_charset ARGS2(HTParentAnchor *, me, int, h)
1344
if (!Switch_Display_Charset(h,SWITCH_DISPLAY_CHARSET_MAYBE))
1346
HTAnchor_setUCInfoStage(me, current_char_set,
1347
UCT_STAGE_HTEXT, UCT_SETBY_MIME); /* highest priorty! */
1348
HTAnchor_setUCInfoStage(me, current_char_set,
1349
UCT_STAGE_STRUCTURED, UCT_SETBY_MIME); /* highest priorty! */
1350
CTRACE((tfp, "changing UCInfoStage: HTEXT/STRUCTURED stages charset='%s'.\n",
1351
LYCharSet_UC[current_char_set].MIMEname));
1355
PUBLIC LYUCcharset * HTAnchor_setUCInfoStage ARGS4(
1356
HTParentAnchor *, me,
1363
* This will allocate and initialize, if not yet done.
1365
LYUCcharset * p = HTAnchor_getUCInfoStage(me, which_stage);
1369
if (set_by >= me->UCStages->s[which_stage].lock) {
1370
#ifdef CAN_SWITCH_DISPLAY_CHARSET
1371
int ohandle = me->UCStages->s[which_stage].LYhndl;
1373
me->UCStages->s[which_stage].lock = set_by;
1374
me->UCStages->s[which_stage].LYhndl = LYhndl;
1376
memcpy(p, &LYCharSet_UC[LYhndl], sizeof(LYUCcharset));
1377
#ifdef CAN_SWITCH_DISPLAY_CHARSET
1378
/* Allow a switch to a more suitable display charset */
1379
if ( LYhndl != ohandle && which_stage == UCT_STAGE_PARSER )
1380
setup_switch_display_charset(me, LYhndl);
1392
PUBLIC LYUCcharset * HTAnchor_resetUCInfoStage ARGS4(
1393
HTParentAnchor *, me,
1400
if (!me || !me->UCStages)
1402
me->UCStages->s[which_stage].lock = set_by;
1403
ohandle = me->UCStages->s[which_stage].LYhndl;
1404
me->UCStages->s[which_stage].LYhndl = LYhndl;
1405
#ifdef CAN_SWITCH_DISPLAY_CHARSET
1406
/* Allow a switch to a more suitable display charset */
1407
if (LYhndl >= 0 && LYhndl != ohandle && which_stage == UCT_STAGE_PARSER)
1408
setup_switch_display_charset(me, LYhndl);
1410
return( &me->UCStages->s[which_stage].C);
1414
** A set_by of (-1) means use the lock value from the from_stage.
1416
PUBLIC LYUCcharset * HTAnchor_copyUCInfoStage ARGS4(
1417
HTParentAnchor *, me,
1424
* This will allocate and initialize, if not yet done.
1426
LYUCcharset * p_from = HTAnchor_getUCInfoStage(me, from_stage);
1427
LYUCcharset * p_to = HTAnchor_getUCInfoStage(me, to_stage);
1432
set_by = me->UCStages->s[from_stage].lock;
1433
if (set_by == UCT_SETBY_NONE)
1434
set_by = UCT_SETBY_DEFAULT;
1435
if (set_by >= me->UCStages->s[to_stage].lock) {
1436
#ifdef CAN_SWITCH_DISPLAY_CHARSET
1437
int ohandle = me->UCStages->s[to_stage].LYhndl;
1439
me->UCStages->s[to_stage].lock = set_by;
1440
me->UCStages->s[to_stage].LYhndl =
1441
me->UCStages->s[from_stage].LYhndl;
1442
#ifdef CAN_SWITCH_DISPLAY_CHARSET
1443
/* Allow a switch to a more suitable display charset */
1444
if ( me->UCStages->s[to_stage].LYhndl >= 0
1445
&& me->UCStages->s[to_stage].LYhndl != ohandle
1446
&& to_stage == UCT_STAGE_PARSER )
1447
setup_switch_display_charset(me,
1448
me->UCStages->s[to_stage].LYhndl);
1451
memcpy(p_to, p_from, sizeof(LYUCcharset));