* anchor.c (reAnchorPos): rewrite (reAnchorWord): delete reseq_anchor() (reAnchorAny): use l->size delete reseq_anchor() * backend.c (internal_get): pass TRUE to saveBuffer * buffer.c (newBuffer): delete n->linelen (reshapeBuffer): rewrite * display.c (displayBuffer): FoldLine (redrawLine): l->bpos (cursorUp0): added (cursorUp): rewrite (cursorDown0): added (cursowDown): rewrite (cursorRight): check l->next l->bwidth (cursorLeft): l->prev && l->bpos l->bwidth (arrangeCursor): buf->currentLine->bwidth buf->cursorX * etc.c (checkType): **oporp rewrite (calcPosition): realColumn allocated by New_reuse * file.c (addnewline): add nlines arg (propBuffer): deleted (colorBuffer): deleted (readHeader): propBuffer FOLD_BUFFER_WIDTH (HTMLlineproc2body): rewrite (addnewline2): added (addnewline): rewrite (loadBuffer): propBuffer, colorBuffer (saveBuffer): cont arg (getNextPage): rewrite * fm.h (LINELEN): 256 (FNLEN): deleted (Line): add size, bpos, bwidth (Buffer): delete linelen (INIT_BUFFER_WIDTH): check showLineNum (FOLD_BUFFER_WIDTH): added (FoldLine): added * funcname.tab (RESHAPE): added * main.c (do_dump): pass FALSE to saveBuffer (nscroll): rewrite (clear_mark): l->size (shiftvisualpos): rewrite (pipeBuf): pass TRUE to saveBuffer (linebeg): check line->prev && line->bpos (linend): check line->next, line->next->bpos (editScr): pass TRUE to saveBuffer (svBuf): pass TRUE to saveBuffer (vmSrc): pass TRUE to saveBuffer (reshape): added (curlno): rewrite * mimehead.c (LINELEN): deleted * proto.h (reshape): added (saveBuffer): add cont arg (cursorUp0): added (cursorDown0): added (checkType): change type oprop, ocolor, delete check_color, len * rc.c (CMT_FOLD_LINE): added (params1): add fold_line (sync_with_option): check PagerMax * search.c (set_mark): l->size (forwardSearch): rewrite (backwardSearch): rewrite * doc/README.func (RESHAPE): added * doc-jp/README.func (RESHAPE): added * scripts/w3mhelp.cgi.in (Buffer operation): add reshape From: Hironori SAKAMOTO <hsaka@mth.biglobe.ne.jp>
		
			
				
	
	
		
			779 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			779 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Id: anchor.c,v 1.21 2003/01/23 18:37:20 ukai Exp $ */
 | 
						|
#include "fm.h"
 | 
						|
#include "myctype.h"
 | 
						|
#include "regex.h"
 | 
						|
 | 
						|
#define FIRST_ANCHOR_SIZE 30
 | 
						|
 | 
						|
AnchorList *
 | 
						|
putAnchor(AnchorList *al, char *url, char *target, Anchor **anchor_return,
 | 
						|
	  char *referer, char *title, unsigned char key, int line, int pos)
 | 
						|
{
 | 
						|
    int n, i, j;
 | 
						|
    Anchor *a;
 | 
						|
    BufferPoint bp;
 | 
						|
    if (al == NULL) {
 | 
						|
	al = New(AnchorList);
 | 
						|
	al->anchors = NULL;
 | 
						|
	al->nanchor = al->anchormax = 0;
 | 
						|
	al->acache = -1;
 | 
						|
    }
 | 
						|
    if (al->anchormax == 0) {
 | 
						|
	/* first time; allocate anchor buffer */
 | 
						|
	al->anchors = New_N(Anchor, FIRST_ANCHOR_SIZE);
 | 
						|
	al->anchormax = FIRST_ANCHOR_SIZE;
 | 
						|
    }
 | 
						|
    if (al->nanchor == al->anchormax) {	/* need realloc */
 | 
						|
	al->anchormax *= 2;
 | 
						|
	al->anchors = New_Reuse(Anchor, al->anchors, al->anchormax);
 | 
						|
    }
 | 
						|
    bp.line = line;
 | 
						|
    bp.pos = pos;
 | 
						|
    n = al->nanchor;
 | 
						|
    if (!n || bpcmp(al->anchors[n - 1].start, bp) < 0)
 | 
						|
	i = n;
 | 
						|
    else
 | 
						|
	for (i = 0; i < n; i++) {
 | 
						|
	    if (bpcmp(al->anchors[i].start, bp) >= 0) {
 | 
						|
		for (j = n; j > i; j--)
 | 
						|
		    al->anchors[j] = al->anchors[j - 1];
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    a = &al->anchors[i];
 | 
						|
    a->url = url;
 | 
						|
    a->target = target;
 | 
						|
    a->referer = referer;
 | 
						|
    a->title = title;
 | 
						|
    a->accesskey = key;
 | 
						|
    a->slave = FALSE;
 | 
						|
    a->start = bp;
 | 
						|
    a->end = bp;
 | 
						|
    al->nanchor++;
 | 
						|
    if (anchor_return)
 | 
						|
	*anchor_return = a;
 | 
						|
    return al;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Anchor *
 | 
						|
registerHref(Buffer *buf, char *url, char *target, char *referer, char *title,
 | 
						|
	     unsigned char key, int line, int pos)
 | 
						|
{
 | 
						|
    Anchor *a;
 | 
						|
    buf->href = putAnchor(buf->href, url, target, &a, referer, title, key,
 | 
						|
			  line, pos);
 | 
						|
    return a;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
registerName(Buffer *buf, char *url, int line, int pos)
 | 
						|
{
 | 
						|
    Anchor *a;
 | 
						|
    buf->name = putAnchor(buf->name, url, NULL, &a, NULL, NULL, '\0', line,
 | 
						|
			  pos);
 | 
						|
    return a;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
registerImg(Buffer *buf, char *url, char *title, int line, int pos)
 | 
						|
{
 | 
						|
    Anchor *a;
 | 
						|
    buf->img = putAnchor(buf->img, url, NULL, &a, NULL, title, '\0', line,
 | 
						|
			 pos);
 | 
						|
    return a;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
registerForm(Buffer *buf, FormList *flist, struct parsed_tag *tag, int line,
 | 
						|
	     int pos)
 | 
						|
{
 | 
						|
    Anchor *a;
 | 
						|
    FormItemList *fi;
 | 
						|
 | 
						|
    fi = formList_addInput(flist, tag);
 | 
						|
    if (fi == NULL)
 | 
						|
	return NULL;
 | 
						|
    buf->formitem = putAnchor(buf->formitem, (char *)fi, flist->target, &a,
 | 
						|
			      NULL, NULL, '\0', line, pos);
 | 
						|
    return a;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
onAnchor(Anchor *a, int line, int pos)
 | 
						|
{
 | 
						|
    BufferPoint bp;
 | 
						|
    bp.line = line;
 | 
						|
    bp.pos = pos;
 | 
						|
 | 
						|
    if (bpcmp(bp, a->start) < 0)
 | 
						|
	return -1;
 | 
						|
    if (bpcmp(a->end, bp) <= 0)
 | 
						|
	return 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
retrieveAnchor(AnchorList *al, int line, int pos)
 | 
						|
{
 | 
						|
    Anchor *a;
 | 
						|
    size_t b, e;
 | 
						|
    int cmp;
 | 
						|
 | 
						|
    if (al == NULL || al->nanchor == 0)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if (al->acache < 0 || al->acache >= al->nanchor)
 | 
						|
	al->acache = 0;
 | 
						|
 | 
						|
    for (b = 0, e = al->nanchor - 1; b <= e; al->acache = (b + e) / 2) {
 | 
						|
	a = &al->anchors[al->acache];
 | 
						|
	cmp = onAnchor(a, line, pos);
 | 
						|
	if (cmp == 0)
 | 
						|
	    return a;
 | 
						|
	else if (cmp > 0)
 | 
						|
	    b = al->acache + 1;
 | 
						|
	else if (al->acache == 0)
 | 
						|
	    return NULL;
 | 
						|
	else
 | 
						|
	    e = al->acache - 1;
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
retrieveCurrentAnchor(Buffer *buf)
 | 
						|
{
 | 
						|
    if (buf->currentLine == NULL)
 | 
						|
	return NULL;
 | 
						|
    return retrieveAnchor(buf->href, buf->currentLine->linenumber, buf->pos);
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
retrieveCurrentImg(Buffer *buf)
 | 
						|
{
 | 
						|
    if (buf->currentLine == NULL)
 | 
						|
	return NULL;
 | 
						|
    return retrieveAnchor(buf->img, buf->currentLine->linenumber, buf->pos);
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
retrieveCurrentForm(Buffer *buf)
 | 
						|
{
 | 
						|
    if (buf->currentLine == NULL)
 | 
						|
	return NULL;
 | 
						|
    return retrieveAnchor(buf->formitem,
 | 
						|
			  buf->currentLine->linenumber, buf->pos);
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
searchAnchor(AnchorList *al, char *str)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    Anchor *a;
 | 
						|
    if (al == NULL)
 | 
						|
	return NULL;
 | 
						|
    for (i = 0; i < al->nanchor; i++) {
 | 
						|
	a = &al->anchors[i];
 | 
						|
	if (!strcmp(a->url, str))
 | 
						|
	    return a;
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
searchURLLabel(Buffer *buf, char *url)
 | 
						|
{
 | 
						|
    return searchAnchor(buf->name, url);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef USE_NNTP
 | 
						|
static Anchor *
 | 
						|
_put_anchor_news(Buffer *buf, char *p1, char *p2, int line, int pos)
 | 
						|
{
 | 
						|
    Str tmp;
 | 
						|
 | 
						|
    if (*p1 == '<') {
 | 
						|
	p1++;
 | 
						|
	if (*(p2 - 1) == '>')
 | 
						|
	    p2--;
 | 
						|
    }
 | 
						|
    tmp = conv_str(Strnew_charp_n(p1, p2 - p1), InnerCode, buf->document_code);
 | 
						|
    tmp = Sprintf("news:%s", file_quote(tmp->ptr));
 | 
						|
    return registerHref(buf, tmp->ptr, NULL, NO_REFERER, NULL, '\0', line,
 | 
						|
			pos);
 | 
						|
}
 | 
						|
#endif				/* USE_NNTP */
 | 
						|
 | 
						|
static Anchor *
 | 
						|
_put_anchor_all(Buffer *buf, char *p1, char *p2, int line, int pos)
 | 
						|
{
 | 
						|
    Str tmp;
 | 
						|
 | 
						|
    tmp = conv_str(Strnew_charp_n(p1, p2 - p1), InnerCode, buf->document_code);
 | 
						|
    return registerHref(buf, url_quote(tmp->ptr), NULL, NO_REFERER, NULL,
 | 
						|
			'\0', line, pos);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
reseq_anchor0(AnchorList *al, short *seqmap)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    Anchor *a;
 | 
						|
 | 
						|
    if (!al)
 | 
						|
	return;
 | 
						|
 | 
						|
    for (i = 0; i < al->nanchor; i++) {
 | 
						|
	a = &al->anchors[i];
 | 
						|
	if (a->hseq >= 0) {
 | 
						|
	    a->hseq = seqmap[a->hseq];
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* renumber anchor */
 | 
						|
static void
 | 
						|
reseq_anchor(Buffer *buf)
 | 
						|
{
 | 
						|
    int i, j, n, nmark = (buf->hmarklist) ? buf->hmarklist->nmark : 0;
 | 
						|
    short *seqmap;
 | 
						|
    Anchor *a, *a1;
 | 
						|
    HmarkerList *ml = NULL;
 | 
						|
 | 
						|
    if (!buf->href)
 | 
						|
	return;
 | 
						|
 | 
						|
    n = nmark;
 | 
						|
    for (i = 0; i < buf->href->nanchor; i++) {
 | 
						|
	a = &buf->href->anchors[i];
 | 
						|
	if (a->hseq == -2)
 | 
						|
	    n++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (n == nmark)
 | 
						|
	return;
 | 
						|
 | 
						|
    seqmap = NewAtom_N(short, n);
 | 
						|
 | 
						|
    for (i = 0; i < n; i++)
 | 
						|
	seqmap[i] = i;
 | 
						|
 | 
						|
    n = nmark;
 | 
						|
    for (i = 0; i < buf->href->nanchor; i++) {
 | 
						|
	a = &buf->href->anchors[i];
 | 
						|
	if (a->hseq == -2) {
 | 
						|
	    a->hseq = n;
 | 
						|
	    a1 = closest_next_anchor(buf->href, NULL, a->start.pos,
 | 
						|
				     a->start.line);
 | 
						|
	    a1 = closest_next_anchor(buf->formitem, a1, a->start.pos,
 | 
						|
				     a->start.line);
 | 
						|
	    if (a1 && a1->hseq >= 0) {
 | 
						|
		seqmap[n] = seqmap[a1->hseq];
 | 
						|
		for (j = a1->hseq; j < nmark; j++)
 | 
						|
		    seqmap[j]++;
 | 
						|
	    }
 | 
						|
	    ml = putHmarker(ml, a->start.line, a->start.pos, seqmap[n]);
 | 
						|
	    n++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < nmark; i++) {
 | 
						|
	ml = putHmarker(ml, buf->hmarklist->marks[i].line,
 | 
						|
			buf->hmarklist->marks[i].pos, seqmap[i]);
 | 
						|
    }
 | 
						|
    buf->hmarklist = ml;
 | 
						|
 | 
						|
    reseq_anchor0(buf->href, seqmap);
 | 
						|
    reseq_anchor0(buf->formitem, seqmap);
 | 
						|
}
 | 
						|
 | 
						|
static char *
 | 
						|
reAnchorPos(Buffer *buf, Line *l, char *p1, char *p2,
 | 
						|
	    Anchor *(*anchorproc) (Buffer *, char *, char *, int, int))
 | 
						|
{
 | 
						|
    Anchor *a;
 | 
						|
    int spos, epos;
 | 
						|
    int i, hseq = -2;
 | 
						|
 | 
						|
    spos = p1 - l->lineBuf;
 | 
						|
    epos = p2 - l->lineBuf;
 | 
						|
    for (i = spos; i < epos; i++) {
 | 
						|
	if (l->propBuf[i] & (PE_ANCHOR | PE_FORM))
 | 
						|
	    return p2;
 | 
						|
    }
 | 
						|
    for (i = spos; i < epos; i++)
 | 
						|
	l->propBuf[i] |= PE_ANCHOR;
 | 
						|
    while (1) {
 | 
						|
	a = anchorproc(buf, p1, p2, l->linenumber, spos);
 | 
						|
	a->hseq = hseq;
 | 
						|
	if (hseq == -2) {
 | 
						|
	    reseq_anchor(buf);
 | 
						|
	    hseq = a->hseq;
 | 
						|
	}
 | 
						|
	a->end.line = l->linenumber;
 | 
						|
	if (epos > l->len) {
 | 
						|
	    a->end.pos = l->len;
 | 
						|
	    spos = 0;
 | 
						|
	    epos -= l->len;
 | 
						|
	    l = l->next;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    a->end.pos = epos;
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return p2;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
reAnchorWord(Buffer *buf, Line *l, int spos, int epos)
 | 
						|
{
 | 
						|
    reAnchorPos(buf, l, &l->lineBuf[spos], &l->lineBuf[epos], _put_anchor_all);
 | 
						|
}
 | 
						|
 | 
						|
/* search regexp and register them as anchors */
 | 
						|
/* returns error message if any               */
 | 
						|
static char *
 | 
						|
reAnchorAny(Buffer *buf, char *re,
 | 
						|
	    Anchor *(*anchorproc) (Buffer *, char *, char *, int, int))
 | 
						|
{
 | 
						|
    Line *l;
 | 
						|
    char *p, *p1, *p2;
 | 
						|
 | 
						|
    if (re == NULL || *re == '\0') {
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    if ((re = regexCompile(re, 1)) != NULL) {
 | 
						|
	return re;
 | 
						|
    }
 | 
						|
    for (l = MarkAllPages ? buf->firstLine : buf->topLine; l != NULL &&
 | 
						|
	 (MarkAllPages || l->linenumber < buf->topLine->linenumber + LASTLINE);
 | 
						|
	 l = l->next) {
 | 
						|
	p = l->lineBuf;
 | 
						|
	for (;;) {
 | 
						|
	    if (regexMatch(p, &l->lineBuf[l->size] - p, p == l->lineBuf) == 1) {
 | 
						|
		matchedPosition(&p1, &p2);
 | 
						|
		p = reAnchorPos(buf, l, p1, p2, anchorproc);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
reAnchor(Buffer *buf, char *re)
 | 
						|
{
 | 
						|
    return reAnchorAny(buf, re, _put_anchor_all);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef USE_NNTP
 | 
						|
char *
 | 
						|
reAnchorNews(Buffer *buf, char *re)
 | 
						|
{
 | 
						|
    return reAnchorAny(buf, re, _put_anchor_news);
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
reAnchorNewsheader(Buffer *buf)
 | 
						|
{
 | 
						|
    Line *l;
 | 
						|
    char *p, *p1, *p2;
 | 
						|
    static char *header_mid[] = {
 | 
						|
	"Message-Id:", "References:", "In-Reply-To:", NULL
 | 
						|
    };
 | 
						|
    static char *header_group[] = {
 | 
						|
	"Newsgroups:", NULL
 | 
						|
    };
 | 
						|
    char **header, **q;
 | 
						|
    int i, search = FALSE;
 | 
						|
 | 
						|
    if (!buf || !buf->firstLine)
 | 
						|
	return NULL;
 | 
						|
    for (i = 0; i <= 1; i++) {
 | 
						|
	if (i == 0) {
 | 
						|
	    regexCompile("<[!-;=?-~]+@[a-zA-Z0-9\\.\\-_]+>", 1);
 | 
						|
	    header = header_mid;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    regexCompile("[a-zA-Z0-9\\.\\-_]+", 1);
 | 
						|
	    header = header_group;
 | 
						|
	}
 | 
						|
	for (l = buf->firstLine; l != NULL && l->real_linenumber == 0;
 | 
						|
	     l = l->next) {
 | 
						|
	    p = l->lineBuf;
 | 
						|
	    if (!IS_SPACE(*p)) {
 | 
						|
		search = FALSE;
 | 
						|
		for (q = header; *q; q++) {
 | 
						|
		    if (!strncasecmp(p, *q, sizeof(*q) - 1)) {
 | 
						|
			search = TRUE;
 | 
						|
			p = strchr(p, ':') + 1;
 | 
						|
			break;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    if (!search)
 | 
						|
		continue;
 | 
						|
	    for (;;) {
 | 
						|
		if (regexMatch(p, &l->lineBuf[l->len] - p, p == l->lineBuf)
 | 
						|
		    == 1) {
 | 
						|
		    matchedPosition(&p1, &p2);
 | 
						|
		    p = reAnchorPos(buf, l, p1, p2, _put_anchor_news);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		    break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    reseq_anchor(buf);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
#endif				/* USE_NNTP */
 | 
						|
 | 
						|
#define FIRST_MARKER_SIZE 30
 | 
						|
HmarkerList *
 | 
						|
putHmarker(HmarkerList *ml, int line, int pos, int seq)
 | 
						|
{
 | 
						|
    if (ml == NULL) {
 | 
						|
	ml = New(HmarkerList);
 | 
						|
	ml->marks = NULL;
 | 
						|
	ml->nmark = 0;
 | 
						|
	ml->markmax = 0;
 | 
						|
	ml->prevhseq = -1;
 | 
						|
    }
 | 
						|
    if (ml->markmax == 0) {
 | 
						|
	ml->markmax = FIRST_MARKER_SIZE;
 | 
						|
	ml->marks = NewAtom_N(BufferPoint, ml->markmax);
 | 
						|
	bzero(ml->marks, sizeof(BufferPoint) * ml->markmax);
 | 
						|
    }
 | 
						|
    if (seq + 1 > ml->nmark)
 | 
						|
	ml->nmark = seq + 1;
 | 
						|
    if (ml->nmark >= ml->markmax) {
 | 
						|
	ml->markmax = ml->nmark * 2;
 | 
						|
	ml->marks = New_Reuse(BufferPoint, ml->marks, ml->markmax);
 | 
						|
    }
 | 
						|
    ml->marks[seq].line = line;
 | 
						|
    ml->marks[seq].pos = pos;
 | 
						|
    return ml;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
closest_next_anchor(AnchorList *a, Anchor *an, int x, int y)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (a == NULL || a->nanchor == 0)
 | 
						|
	return an;
 | 
						|
    for (i = 0; i < a->nanchor; i++) {
 | 
						|
	if (a->anchors[i].hseq < 0)
 | 
						|
	    continue;
 | 
						|
	if (a->anchors[i].start.line > y ||
 | 
						|
	    (a->anchors[i].start.line == y && a->anchors[i].start.pos > x)) {
 | 
						|
	    if (an == NULL || an->start.line > a->anchors[i].start.line ||
 | 
						|
		(an->start.line == a->anchors[i].start.line &&
 | 
						|
		 an->start.pos > a->anchors[i].start.pos))
 | 
						|
		an = &a->anchors[i];
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return an;
 | 
						|
}
 | 
						|
 | 
						|
Anchor *
 | 
						|
closest_prev_anchor(AnchorList *a, Anchor *an, int x, int y)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (a == NULL || a->nanchor == 0)
 | 
						|
	return an;
 | 
						|
    for (i = 0; i < a->nanchor; i++) {
 | 
						|
	if (a->anchors[i].hseq < 0)
 | 
						|
	    continue;
 | 
						|
	if (a->anchors[i].end.line < y ||
 | 
						|
	    (a->anchors[i].end.line == y && a->anchors[i].end.pos <= x)) {
 | 
						|
	    if (an == NULL || an->end.line < a->anchors[i].end.line ||
 | 
						|
		(an->end.line == a->anchors[i].end.line &&
 | 
						|
		 an->end.pos < a->anchors[i].end.pos))
 | 
						|
		an = &a->anchors[i];
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return an;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef USE_IMAGE
 | 
						|
void
 | 
						|
addMultirowsImg(Buffer *buf, AnchorList *al)
 | 
						|
{
 | 
						|
    int i, j, k, col, ecol, pos;
 | 
						|
    Image *img;
 | 
						|
    Anchor a_img, a_href, a_form, *a;
 | 
						|
    Line *l, *ls;
 | 
						|
 | 
						|
    if (al == NULL || al->nanchor == 0)
 | 
						|
	return;
 | 
						|
    for (i = 0; i < al->nanchor; i++) {
 | 
						|
	a_img = al->anchors[i];
 | 
						|
	img = a_img.image;
 | 
						|
	if (a_img.hseq < 0 || !img || img->rows <= 1)
 | 
						|
	    continue;
 | 
						|
	for (l = buf->firstLine; l != NULL; l = l->next) {
 | 
						|
	    if (l->linenumber == img->y)
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (!l)
 | 
						|
	    continue;
 | 
						|
	if (a_img.y == a_img.start.line)
 | 
						|
	    ls = l;
 | 
						|
	else {
 | 
						|
	    for (ls = l; ls != NULL;
 | 
						|
		 ls = (a_img.y < a_img.start.line) ? ls->next : ls->prev) {
 | 
						|
		if (ls->linenumber == a_img.start.line)
 | 
						|
		    break;
 | 
						|
	    }
 | 
						|
	    if (!ls)
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
	a = retrieveAnchor(buf->href, a_img.start.line, a_img.start.pos);
 | 
						|
	if (a)
 | 
						|
	    a_href = *a;
 | 
						|
	else
 | 
						|
	    a_href.url = NULL;
 | 
						|
	a = retrieveAnchor(buf->formitem, a_img.start.line, a_img.start.pos);
 | 
						|
	if (a)
 | 
						|
	    a_form = *a;
 | 
						|
	else
 | 
						|
	    a_form.url = NULL;
 | 
						|
	col = COLPOS(ls, a_img.start.pos);
 | 
						|
	ecol = COLPOS(ls, a_img.end.pos);
 | 
						|
	for (j = 0; l && j < img->rows; l = l->next, j++) {
 | 
						|
	    if (a_img.start.line == l->linenumber)
 | 
						|
		continue;
 | 
						|
	    pos = columnPos(l, col);
 | 
						|
	    a = registerImg(buf, a_img.url, a_img.title, l->linenumber, pos);
 | 
						|
	    a->hseq = -a_img.hseq;
 | 
						|
	    a->slave = TRUE;
 | 
						|
	    a->image = img;
 | 
						|
	    a->end.pos = pos + ecol - col;
 | 
						|
	    for (k = pos; k < a->end.pos; k++)
 | 
						|
		l->propBuf[k] |= PE_IMAGE;
 | 
						|
	    if (a_href.url) {
 | 
						|
		a = registerHref(buf, a_href.url, a_href.target,
 | 
						|
				 a_href.referer, a_href.title,
 | 
						|
				 a_href.accesskey, l->linenumber, pos);
 | 
						|
		a->hseq = a_href.hseq;
 | 
						|
		a->slave = TRUE;
 | 
						|
		a->end.pos = pos + ecol - col;
 | 
						|
		for (k = pos; k < a->end.pos; k++)
 | 
						|
		    l->propBuf[k] |= PE_ANCHOR;
 | 
						|
	    }
 | 
						|
	    if (a_form.url) {
 | 
						|
		buf->formitem = putAnchor(buf->formitem, a_form.url,
 | 
						|
					  a_form.target, &a, NULL, NULL, '\0',
 | 
						|
					  l->linenumber, pos);
 | 
						|
		a->hseq = a_form.hseq;
 | 
						|
		a->end.pos = pos + ecol - col;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	img->rows = 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
addMultirowsForm(Buffer *buf, AnchorList *al)
 | 
						|
{
 | 
						|
    int i, j, k, col, ecol, pos;
 | 
						|
    Anchor a_form, *a;
 | 
						|
    FormItemList *fi;
 | 
						|
    Line *l, *ls;
 | 
						|
 | 
						|
    if (al == NULL || al->nanchor == 0)
 | 
						|
	return;
 | 
						|
    for (i = 0; i < al->nanchor; i++) {
 | 
						|
	a_form = al->anchors[i];
 | 
						|
	al->anchors[i].rows = 1;
 | 
						|
	if (a_form.hseq < 0 || a_form.rows <= 1)
 | 
						|
	    continue;
 | 
						|
	for (l = buf->firstLine; l != NULL; l = l->next) {
 | 
						|
	    if (l->linenumber == a_form.y)
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (!l)
 | 
						|
	    continue;
 | 
						|
	if (a_form.y == a_form.start.line)
 | 
						|
	    ls = l;
 | 
						|
	else {
 | 
						|
	    for (ls = l; ls != NULL;
 | 
						|
		 ls = (a_form.y < a_form.start.line) ? ls->next : ls->prev) {
 | 
						|
		if (ls->linenumber == a_form.start.line)
 | 
						|
		    break;
 | 
						|
	    }
 | 
						|
	    if (!ls)
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
	fi = (FormItemList *)a_form.url;
 | 
						|
	col = COLPOS(ls, a_form.start.pos);
 | 
						|
	ecol = COLPOS(ls, a_form.end.pos);
 | 
						|
	for (j = 0; l && j < a_form.rows; l = l->next, j++) {
 | 
						|
	    pos = columnPos(l, col);
 | 
						|
	    if (j == 0) {
 | 
						|
		buf->hmarklist->marks[a_form.hseq].line = l->linenumber;
 | 
						|
		buf->hmarklist->marks[a_form.hseq].pos = pos;
 | 
						|
	    }
 | 
						|
	    if (a_form.start.line == l->linenumber)
 | 
						|
		continue;
 | 
						|
	    buf->formitem = putAnchor(buf->formitem, a_form.url,
 | 
						|
				      a_form.target, &a, NULL, NULL, '\0',
 | 
						|
				      l->linenumber, pos);
 | 
						|
	    a->hseq = a_form.hseq;
 | 
						|
	    a->y = a_form.y;
 | 
						|
	    a->end.pos = pos + ecol - col;
 | 
						|
	    l->lineBuf[pos - 1] = '[';
 | 
						|
	    l->lineBuf[a->end.pos] = ']';
 | 
						|
	    for (k = pos; k < a->end.pos; k++)
 | 
						|
		l->propBuf[k] |= PE_FORM;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
getAnchorText(Buffer *buf, AnchorList *al, Anchor *a)
 | 
						|
{
 | 
						|
    int hseq, i;
 | 
						|
    Line *l;
 | 
						|
    Str tmp = NULL;
 | 
						|
    char *p, *ep;
 | 
						|
 | 
						|
    if (!a || a->hseq < 0)
 | 
						|
	return NULL;
 | 
						|
    hseq = a->hseq;
 | 
						|
    l = buf->firstLine;
 | 
						|
    for (i = 0; i < al->nanchor; i++) {
 | 
						|
	a = &al->anchors[i];
 | 
						|
	if (a->hseq != hseq)
 | 
						|
	    continue;
 | 
						|
	for (; l; l = l->next) {
 | 
						|
	    if (l->linenumber == a->start.line)
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (!l)
 | 
						|
	    break;
 | 
						|
	p = l->lineBuf + a->start.pos;
 | 
						|
	ep = l->lineBuf + a->end.pos;
 | 
						|
	for (; p < ep && IS_SPACE(*p); p++) ;
 | 
						|
	if (p == ep)
 | 
						|
	    continue;
 | 
						|
	if (!tmp)
 | 
						|
	    tmp = Strnew_size(ep - p);
 | 
						|
	else
 | 
						|
	    Strcat_char(tmp, ' ');
 | 
						|
	Strcat_charp_n(tmp, p, ep - p);
 | 
						|
    }
 | 
						|
    return tmp ? tmp->ptr : NULL;
 | 
						|
}
 | 
						|
 | 
						|
Buffer *
 | 
						|
link_list_panel(Buffer *buf)
 | 
						|
{
 | 
						|
    LinkList *l;
 | 
						|
    AnchorList *al;
 | 
						|
    Anchor *a;
 | 
						|
    FormItemList *fi;
 | 
						|
    int i;
 | 
						|
    char *t, *u;
 | 
						|
    ParsedURL pu;
 | 
						|
    Str tmp = Strnew_charp("<title>Link List</title>\
 | 
						|
<h1 align=center>Link List</h1>\n");
 | 
						|
 | 
						|
    if (buf->bufferprop & BP_INTERNAL ||
 | 
						|
	(buf->linklist == NULL && buf->href == NULL && buf->img == NULL)) {
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (buf->linklist) {
 | 
						|
	Strcat_charp(tmp, "<hr><h2>Links</h2>\n<ol>\n");
 | 
						|
	for (l = buf->linklist; l; l = l->next) {
 | 
						|
	    if (l->url) {
 | 
						|
		parseURL2(l->url, &pu, baseURL(buf));
 | 
						|
		u = html_quote(parsedURL2Str(&pu)->ptr);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		u = "";
 | 
						|
	    if (l->type == LINK_TYPE_REL)
 | 
						|
		t = " [Rel]";
 | 
						|
	    else if (l->type == LINK_TYPE_REV)
 | 
						|
		t = " [Rev]";
 | 
						|
	    else
 | 
						|
		t = "";
 | 
						|
	    t = Sprintf("%s%s\n", l->title ? l->title : "", t)->ptr;
 | 
						|
	    t = html_quote(t);
 | 
						|
	    Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t, "</a><br>", u,
 | 
						|
			   "\n", NULL);
 | 
						|
	}
 | 
						|
	Strcat_charp(tmp, "</ol>\n");
 | 
						|
    }
 | 
						|
 | 
						|
    if (buf->href) {
 | 
						|
	Strcat_charp(tmp, "<hr><h2>Anchors</h2>\n<ol>\n");
 | 
						|
	al = buf->href;
 | 
						|
	for (i = 0; i < al->nanchor; i++) {
 | 
						|
	    a = &al->anchors[i];
 | 
						|
	    if (a->slave)
 | 
						|
		continue;
 | 
						|
	    parseURL2(a->url, &pu, baseURL(buf));
 | 
						|
	    u = html_quote(parsedURL2Str(&pu)->ptr);
 | 
						|
	    t = getAnchorText(buf, al, a);
 | 
						|
	    t = t ? html_quote(t) : "";
 | 
						|
	    Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t, "</a><br>", u,
 | 
						|
			   "\n", NULL);
 | 
						|
	}
 | 
						|
	Strcat_charp(tmp, "</ol>\n");
 | 
						|
    }
 | 
						|
 | 
						|
    if (buf->img) {
 | 
						|
	Strcat_charp(tmp, "<hr><h2>Images</h2>\n<ol>\n");
 | 
						|
	al = buf->img;
 | 
						|
	for (i = 0; i < al->nanchor; i++) {
 | 
						|
	    a = &al->anchors[i];
 | 
						|
	    if (a->slave)
 | 
						|
		continue;
 | 
						|
	    parseURL2(a->url, &pu, baseURL(buf));
 | 
						|
	    u = html_quote(parsedURL2Str(&pu)->ptr);
 | 
						|
	    t = (a->title && *a->title) ? html_quote(a->title) :
 | 
						|
		html_quote(a->url);
 | 
						|
	    Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t, "</a><br>", u,
 | 
						|
			   "\n", NULL);
 | 
						|
	    a = retrieveAnchor(buf->formitem, a->start.line, a->start.pos);
 | 
						|
	    if (!a)
 | 
						|
		continue;
 | 
						|
	    fi = (FormItemList *)a->url;
 | 
						|
	    fi = fi->parent->item;
 | 
						|
	    if (fi->parent->method == FORM_METHOD_INTERNAL &&
 | 
						|
		!Strcmp_charp(fi->parent->action, "map") && fi->value) {
 | 
						|
		MapList *ml = searchMapList(buf, fi->value->ptr);
 | 
						|
		ListItem *mi;
 | 
						|
		MapArea *m;
 | 
						|
		if (!ml)
 | 
						|
		    continue;
 | 
						|
		Strcat_charp(tmp, "<br>\n<b>Image map</b>\n<ol>\n");
 | 
						|
		for (mi = ml->area->first; mi != NULL; mi = mi->next) {
 | 
						|
		    m = (MapArea *) mi->ptr;
 | 
						|
		    if (!m)
 | 
						|
			continue;
 | 
						|
		    parseURL2(m->url, &pu, baseURL(buf));
 | 
						|
		    u = html_quote(parsedURL2Str(&pu)->ptr);
 | 
						|
		    t = (m->alt && *m->alt) ? html_quote(m->alt) :
 | 
						|
			html_quote(m->url);
 | 
						|
		    Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t,
 | 
						|
				   "</a><br>", u, "\n", NULL);
 | 
						|
		}
 | 
						|
		Strcat_charp(tmp, "</ol>\n");
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	Strcat_charp(tmp, "</ol>\n");
 | 
						|
    }
 | 
						|
 | 
						|
    return loadHTMLString(tmp);
 | 
						|
}
 |