Initial revision
This commit is contained in:
420
anchor.c
Normal file
420
anchor.c
Normal file
@@ -0,0 +1,420 @@
|
||||
/* $Id: anchor.c,v 1.1 2001/11/08 05:14:10 a-ito Exp $ */
|
||||
#ifdef __EMX__
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#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, 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->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, int line, int pos)
|
||||
{
|
||||
Anchor *a;
|
||||
buf->href = putAnchor(buf->href, url, target, &a, referer, 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, line, pos);
|
||||
return a;
|
||||
}
|
||||
|
||||
Anchor *
|
||||
registerImg(Buffer * buf, char *url, int line, int pos)
|
||||
{
|
||||
Anchor *a;
|
||||
buf->img = putAnchor(buf->img, url, NULL, &a, NULL, 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,
|
||||
line, pos);
|
||||
fi->anchor_num = buf->formitem->nanchor - 1;
|
||||
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 = Strnew_charp("news:");
|
||||
|
||||
p1++;
|
||||
if (*(p2 - 1) == '>')
|
||||
p2--;
|
||||
while (p1 < p2) {
|
||||
Strcat_char(tmp, *(p1++));
|
||||
}
|
||||
return registerHref(buf, tmp->ptr, NULL, NO_REFERER, line, pos);
|
||||
}
|
||||
#endif /* USE_NNTP */
|
||||
|
||||
static Anchor *
|
||||
_put_anchor_all(Buffer * buf, char *p1, char *p2, int line, int pos)
|
||||
{
|
||||
return registerHref(buf, allocStr(p1, p2 - p1), NULL, NO_REFERER, 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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
Anchor *a;
|
||||
int i;
|
||||
int spos, epos;
|
||||
|
||||
if (re == NULL || *re == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
if ((re = regexCompile(re, 1)) != NULL) {
|
||||
return re;
|
||||
}
|
||||
for (l = buf->firstLine; l != NULL; l = l->next) {
|
||||
p = l->lineBuf;
|
||||
for (;;) {
|
||||
if (regexMatch(p, &l->lineBuf[l->len] - p, p == l->lineBuf) == 1) {
|
||||
matchedPosition(&p1, &p2);
|
||||
spos = p1 - l->lineBuf;
|
||||
epos = p2 - l->lineBuf;
|
||||
for (i = spos; i < epos; i++) {
|
||||
if (l->propBuf[i] & (PE_ANCHOR | PE_FORM))
|
||||
goto _next;
|
||||
}
|
||||
a = anchorproc(buf, p1, p2, l->linenumber, p1 - l->lineBuf);
|
||||
a->end.line = l->linenumber;
|
||||
a->end.pos = epos;
|
||||
a->hseq = -2;
|
||||
for (i = a->start.pos; i < a->end.pos; i++)
|
||||
l->propBuf[i] |= PE_ANCHOR;
|
||||
_next:
|
||||
p = p2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
reseq_anchor(buf);
|
||||
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);
|
||||
}
|
||||
#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 = New_N(BufferPoint, ml->markmax);
|
||||
#ifdef __CYGWIN__
|
||||
bzero((char *) ml->marks, sizeof(BufferPoint) * ml->markmax);
|
||||
#else /* not __CYGWIN__ */
|
||||
bzero(ml->marks, sizeof(BufferPoint) * ml->markmax);
|
||||
#endif /* not __CYGWIN__ */
|
||||
}
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user