Files
w3m/anchor.c
Fumitoshi UKAI 9efbc08856 w3m-img merge (w3m-0.2.4+cvs-1.278-img-2.2.patch.gz)
* NEWS: w3m-img merge
* .cvsignore: add w3mimgdisplay, w3mimgsize
* XMakefile: add image.c to SRCS
	     add image.o to OBJS
             add IMGDISPLAY, IMGSIZE
* config.h.dist: USE_IMAGE, IMGSIZE, IMGDISPLAY
* configure: add find_imlib
		ask use_image
	(config.h) add $imgtarget to EXT_TARGETS
		   $def_use_image
		   IMGSIZE, IMGDISPLAY
* fm.h (MAX_IMAGE): added
* fm.h (DEFAULT_PIXEL_PER_CHAR): fix for USE_IMAGE
* fm.h (DEFAULT_PIXEL_PER_LINE): added
* fm.h (B_REDRAW_IMAGE): added
* fm.h (IMG_FLAG_SKIP): added
* fm.h (IMG_FLAG_AUTO): added
* fm.h (IMG_FLAG_START): added
* fm.h (IMG_FLAG_STOP): added
* fm.h (IMG_FLAG_NEXT): added
* fm.h (IMG_FLAG_UNLOADED): added
* fm.h (IMG_FLAG_LOADED): added
* fm.h (IMG_FLAG_ERROR): added
* fm.h (MapArea): added
* fm.h (MapList): s/urls/alts/, add area
* fm.h (ImageCache): added
* fm.h (Image): added
* fm.h (Anchor): add image
* fm.h (Buffer): add imarklist, image_flag, need_reshape
* fm.h (RG_FRAME_SRC): added
* fm.h (ALIGN_MIDDLE): added
* fm.h (ALIGN_TOP): added
* fm.h (ALIGN_BOTTOM): added
* fm.h (QuietMessage): added
* fm.h (Imgdisplay): added
* fm.h (Imgsize): added
* fm.h (activeImage): added
* fm.h (displayImage): added
* fm.h (autoImage): added
* fm.h (useExtImageViewer): added
* fm.h (image_source): added
* fm.h (view_unseenobject): change default if USE_IMAGE
* fm.h (set_pixel_per_char): added
* fm.h (pixel_per_line): added
* fm.h (set_pixel_per_line): added
* fm.h (image_scale): added
* proto.h (dispI): added
* proto.h (stopI): added
* proto.h (deleteImage): added
* proto.h (getAllImage): added
* proto.h (loadImage): added
* proto.h (getImage): added
* proto.h (getImageSize): added
* proto.h (process_img): add width arg
* proto.h (loadImageBuffer): added
* proto.h (follow_map_menu): add a_img arg
* proto.h (getMapXY): added
* proto.h (newMapArea): added
* proto.h (touch_cursor): added
* proto.h (cURLcode): added
* proto.h (initImage): added
* proto.h (termImage): added
* proto.h (addImage): added
* proto.h (drawImage): added
* proto.h (clearImage): added
* anchor.c (addMultirowsImg): added
* buffer.c (discardBuffer): deleteImage if USE_IMAGE
* buffer.c (reshapeBuffer): buf->need_reshape check
* display.c (fmTerm): if activeImage, stop load image
* display.c (fmInit): if displayImage, initImage
* display.c (image_touch): added
* display.c (draw_image_flag): added
* display.c (redrawLineImage): added
* display.c (displayBuffer): buf->need_reshape = TRUE
			mode == B_REDRAW_IMAGE
			image flag checks
			force redraw image in mode == B_REDRAW_IMAGE
			displayBuffer if need reshape
			drawImage
* display.c (redrawNLine): redrawLineImage
* display.c (redrawLineImage): added
* display.c (disp_message_nsec): return immediately if QuietMessage
* etc.c (reset_signals): ignore SIGUSR1
* file.c (frame_source): added
* file.c (_MoveFile): added
* file.c (cur_baseURL): added
* file.c (cur_document_code): added
* file.c (cur_iseq): added
* file.c (loadGeneralFile): fix fmInitialized and prevtrap checks
			save cur_baseURL
			image_source load
			loadImageBuffer for "image/*"
			frame_source flag
			fix b->type when proc is loadImageBuffer
* file.c (process_img): add width arg
		parse height and width attr, align
		fix for inline-image
* file.c (process_input): fix for form <input type="image">
* file.c (HTMLtagproc1): pass h_env->limit to process_img()
		fix <img_alt> for inline-image
		save cur_baseURL
* file.c (HTMLlineproc2body): fix <img_alt> for inline-image
* file.c (loadHTMLstream): fix for inline-image
		fix fmInitialized and prevtrap checks
		save cur_document_code
		save image_flag
* file.c (loadGopherDir): save cur_document_code
		fix fmInitialized and prevtrap checks
* file.c (loadImageBuffer): added for inline-image
* file.c (save2tmp): fix fmInitialized and prevtrap checks
* frame.c (frame_download_source): set RG_FRAME_SRC flag
		image check
* funcname.tab (DISPLAY_IMAGE): added
* funcname.tab (STOP_IMAGE): added
* html.c (ALST_IMG): add align, ismap
* html.c (ALST_AREA): add shape, coords
* html.c (ALST_IMG_ALT): add width, height, usemap, ismap, hseq,
			xoffset, yoffset, top_margin, bottom_margin
* html.c (AttrMap): add shape, coords, ismap, xoffset, yoffset
* html.h (ATTR_SHAPE): added
* html.h (ATTR_COORDS): added
* html.h (ATTR_ISMAP): added
* html.h (ATTR_XOFFSET): added
* html.h (ATTR_YOFFSET): added
* html.h (ATTR_TOP_MARGIN): added
* html.h (ATTR_BOTTOM_MARGIN): added
* html.h (SHAPE_UNKNOWN): added
* html.h (SHAPE_DEFAULT): added
* html.h (SHAPE_RECT): added
* html.h (SHAPE_CIRCLE): added
* html.h (SHAPE_POLY): added
* image.c: added
* main.c (fversion): add USE_IMAGE
* main.c (fusage): -ppl option
* main.c (MAIN): set_pixel_per_char if ppc specified
		-ppl option
		loadImage
* main.c (pushBuffer): deleteImage
* main.c (quitfm): termImage
* main.c (selBuf): deleteImage
* main.c (followA): fix for inline-image and map area
* main.c (query_from_followform): getMapXY()
* main.c (setOpt): displayBuffer B_REDRAW_IMAGE
* main.c (follow_map): fix calculate x, y
* main.c (dispI): added
* main.c (stopI): added
* map.c: include <math.h>
* map.c (inMapArea): added
* map.c (follow_map_menu): add a_img arg to handle inline-image
* map.c (follow_map_panel): use MapArea
* map.c (getMapXY): added
* map.c (newMapArea): added
* menu.c (smChBuf): deleteImage
* parsetagx.c (toAlign): align top, bottom, middle
* rc.c (P_SCALE): added
* rc.c (CMT_PIXEL_PER_LINE): added
* rc.c (CMT_DISP_IMAGE): added
* rc.c (CMT_AUTO_IMAGE): added
* rc.c (CMT_EXT_IMAGE_VIEWER): added
* rc.c (CMT_IMAGE_SCALE): added
* rc.c (CMT_IMGDISPLAY): added
* rc.c (CMT_IMGSIZE): added
* rc.c (show_param): P_PIXELS
* rc.c (set_param): P_PIXELS
* rc.c (sync_with_option): initImage
* rc.c (to_str): P_PIXELS
* table.c (feed_table_tag): fix <img> for inline-image
* tagtable.tab (image): added
* terms.c (wgetch): retry read when EINTR or EAGAIN
* terms.c (touch_cursor): added
* w3mimgdisplay.c: added
* w3mimgsize.c: added
* doc/README.func (DISPLAY_IMAGE): added
* doc/README.func (STOP_IMAGE): added
* doc/README.img: added
* doc-jp/README.func (DISPLAY_IMAGE): added
* doc-jp/README.func (STOP_IMAGE): added
* doc-jp/README.img: added
* scripts/w3mhelp.cgi.in: show dispI, stopI
* scripts/multipart/multipart.cgi.in: inline image support
From: Fumitoshi UKAI  <ukai@debian.or.jp>
2002-01-31 17:54:47 +00:00

542 lines
12 KiB
C

/* $Id: anchor.c,v 1.8 2002/01/31 17:54:48 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, 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);
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;
p1++;
if (*(p2 - 1) == '>')
p2--;
tmp = Strnew_size(sizeof("news:") - 1 + (p2 - p1));
Strcat_charp_n(tmp, "news:", sizeof("news:") - 1);
Strcat_charp_n(tmp, p1, p2 - 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 = 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, l->linenumber, pos);
a->hseq = -a_img.hseq;
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, l->linenumber, pos);
a->hseq = a_href.hseq;
a->end.pos = pos + ecol - col;
for (k = pos; k < a->end.pos; k++)
l->propBuf[k] |= PE_ANCHOR;
}
if (a_form.url) {
FormItemList *fi = (FormItemList *)a_form.url;
buf->formitem = putAnchor(buf->formitem, a_form.url,
a_form.target, &a, NULL,
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, 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;
}
}
}