diff options
Diffstat (limited to '')
-rw-r--r-- | anchor.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/anchor.c b/anchor.c new file mode 100644 index 0000000..6005899 --- /dev/null +++ b/anchor.c @@ -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; +} |