diff options
Diffstat (limited to 'buffer.c')
-rw-r--r-- | buffer.c | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/buffer.c b/buffer.c new file mode 100644 index 0000000..f258dd6 --- /dev/null +++ b/buffer.c @@ -0,0 +1,769 @@ +/* $Id: buffer.c,v 1.29 2003/09/26 17:59:51 ukai Exp $ */ +#include "fm.h" + +#ifdef USE_MOUSE +#ifdef USE_GPM +#include <gpm.h> +#endif +#if defined(USE_GPM) || defined(USE_SYSMOUSE) +extern int do_getch(); +#define getch() do_getch() +#endif /* USE_GPM */ +#endif /* USE_MOUSE */ + +#ifdef __EMX__ +#include <sys/kbdscan.h> +#include <strings.h> +#endif +char *NullLine = ""; +Lineprop NullProp[] = { 0 }; + +/* + * Buffer creation + */ +Buffer * +newBuffer(int width) +{ + Buffer *n; + + n = New(Buffer); + if (n == NULL) + return NULL; + bzero((void *)n, sizeof(Buffer)); + n->width = width; + n->COLS = COLS; + n->LINES = LASTLINE; + n->currentURL.scheme = SCM_UNKNOWN; + n->baseURL = NULL; + n->baseTarget = NULL; + n->buffername = ""; + n->bufferprop = BP_NORMAL; + n->clone = New(int); + *n->clone = 1; + n->trbyte = 0; +#ifdef USE_SSL + n->ssl_certificate = NULL; +#endif +#ifdef USE_M17N + n->auto_detect = WcOption.auto_detect; +#endif + return n; +} + +/* + * Create null buffer + */ +Buffer * +nullBuffer(void) +{ + Buffer *b; + + b = newBuffer(COLS); + b->buffername = "*Null*"; + return b; +} + +/* + * clearBuffer: clear buffer content + */ +void +clearBuffer(Buffer *buf) +{ + buf->firstLine = buf->topLine = buf->currentLine = buf->lastLine = NULL; + buf->allLine = 0; +} + +/* + * discardBuffer: free buffer structure + */ + +void +discardBuffer(Buffer *buf) +{ + int i; + Buffer *b; + +#ifdef USE_IMAGE + deleteImage(buf); +#endif + clearBuffer(buf); + for (i = 0; i < MAX_LB; i++) { + b = buf->linkBuffer[i]; + if (b == NULL) + continue; + b->linkBuffer[REV_LB[i]] = NULL; + } + if (buf->savecache) + unlink(buf->savecache); + if (--(*buf->clone)) + return; + if (buf->pagerSource) + ISclose(buf->pagerSource); + if (buf->sourcefile && + (!buf->real_type || strncasecmp(buf->real_type, "image/", 6))) { + if (buf->real_scheme != SCM_LOCAL || buf->bufferprop & BP_FRAME) + unlink(buf->sourcefile); + } + if (buf->header_source) + unlink(buf->header_source); + if (buf->mailcap_source) + unlink(buf->mailcap_source); + while (buf->frameset) { + deleteFrameSet(buf->frameset); + buf->frameset = popFrameTree(&(buf->frameQ)); + } +} + +/* + * namedBuffer: Select buffer which have specified name + */ +Buffer * +namedBuffer(Buffer *first, char *name) +{ + Buffer *buf; + + if (!strcmp(first->buffername, name)) { + return first; + } + for (buf = first; buf->nextBuffer != NULL; buf = buf->nextBuffer) { + if (!strcmp(buf->nextBuffer->buffername, name)) { + return buf->nextBuffer; + } + } + return NULL; +} + +/* + * deleteBuffer: delete buffer + */ +Buffer * +deleteBuffer(Buffer *first, Buffer *delbuf) +{ + Buffer *buf, *b; + + if (first == delbuf && first->nextBuffer != NULL) { + buf = first->nextBuffer; + discardBuffer(first); + return buf; + } + if ((buf = prevBuffer(first, delbuf)) != NULL) { + b = buf->nextBuffer; + buf->nextBuffer = b->nextBuffer; + discardBuffer(b); + } + return first; +} + +/* + * replaceBuffer: replace buffer + */ +Buffer * +replaceBuffer(Buffer *first, Buffer *delbuf, Buffer *newbuf) +{ + Buffer *buf; + + if (delbuf == NULL) { + newbuf->nextBuffer = first; + return newbuf; + } + if (first == delbuf) { + newbuf->nextBuffer = delbuf->nextBuffer; + discardBuffer(delbuf); + return newbuf; + } + if (delbuf && (buf = prevBuffer(first, delbuf))) { + buf->nextBuffer = newbuf; + newbuf->nextBuffer = delbuf->nextBuffer; + discardBuffer(delbuf); + return first; + } + newbuf->nextBuffer = first; + return newbuf; +} + +Buffer * +nthBuffer(Buffer *firstbuf, int n) +{ + int i; + Buffer *buf = firstbuf; + + if (n < 0) + return firstbuf; + for (i = 0; i < n; i++) { + if (buf == NULL) + return NULL; + buf = buf->nextBuffer; + } + return buf; +} + +static void +writeBufferName(Buffer *buf, int n) +{ + Str msg; + int all; + + all = buf->allLine; + if (all == 0 && buf->lastLine != NULL) + all = buf->lastLine->linenumber; + move(n, 0); + /* FIXME: gettextize? */ + msg = Sprintf("<%s> [%d lines]", buf->buffername, all); + if (buf->filename != NULL) { + switch (buf->currentURL.scheme) { + case SCM_LOCAL: + case SCM_LOCAL_CGI: + if (strcmp(buf->currentURL.file, "-")) { + Strcat_char(msg, ' '); + Strcat_charp(msg, conv_from_system(buf->currentURL.real_file)); + } + break; + case SCM_UNKNOWN: + case SCM_MISSING: + break; + default: + Strcat_char(msg, ' '); + Strcat(msg, parsedURL2Str(&buf->currentURL)); + break; + } + } + addnstr_sup(msg->ptr, COLS - 1); +} + + +/* + * gotoLine: go to line number + */ +void +gotoLine(Buffer *buf, int n) +{ + char msg[32]; + Line *l = buf->firstLine; + + if (l == NULL) + return; + if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) { + if (buf->lastLine->linenumber < n) + getNextPage(buf, n - buf->lastLine->linenumber); + while ((buf->lastLine->linenumber < n) && + (getNextPage(buf, 1) != NULL)) ; + } + if (l->linenumber > n) { + /* FIXME: gettextize? */ + sprintf(msg, "First line is #%ld", l->linenumber); + set_delayed_message(msg); + buf->topLine = buf->currentLine = l; + return; + } + if (buf->lastLine->linenumber < n) { + l = buf->lastLine; + /* FIXME: gettextize? */ + sprintf(msg, "Last line is #%ld", buf->lastLine->linenumber); + set_delayed_message(msg); + buf->currentLine = l; + buf->topLine = lineSkip(buf, buf->currentLine, -(buf->LINES - 1), + FALSE); + return; + } + for (; l != NULL; l = l->next) { + if (l->linenumber >= n) { + buf->currentLine = l; + if (n < buf->topLine->linenumber || + buf->topLine->linenumber + buf->LINES <= n) + buf->topLine = lineSkip(buf, l, -(buf->LINES + 1) / 2, FALSE); + break; + } + } +} + +/* + * gotoRealLine: go to real line number + */ +void +gotoRealLine(Buffer *buf, int n) +{ + char msg[32]; + Line *l = buf->firstLine; + + if (l == NULL) + return; + if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) { + if (buf->lastLine->real_linenumber < n) + getNextPage(buf, n - buf->lastLine->real_linenumber); + while ((buf->lastLine->real_linenumber < n) && + (getNextPage(buf, 1) != NULL)) ; + } + if (l->real_linenumber > n) { + /* FIXME: gettextize? */ + sprintf(msg, "First line is #%ld", l->real_linenumber); + set_delayed_message(msg); + buf->topLine = buf->currentLine = l; + return; + } + if (buf->lastLine->real_linenumber < n) { + l = buf->lastLine; + /* FIXME: gettextize? */ + sprintf(msg, "Last line is #%ld", buf->lastLine->real_linenumber); + set_delayed_message(msg); + buf->currentLine = l; + buf->topLine = lineSkip(buf, buf->currentLine, -(buf->LINES - 1), + FALSE); + return; + } + for (; l != NULL; l = l->next) { + if (l->real_linenumber >= n) { + buf->currentLine = l; + if (n < buf->topLine->real_linenumber || + buf->topLine->real_linenumber + buf->LINES <= n) + buf->topLine = lineSkip(buf, l, -(buf->LINES + 1) / 2, FALSE); + break; + } + } +} + + +static Buffer * +listBuffer(Buffer *top, Buffer *current) +{ + int i, c = 0; + Buffer *buf = top; + + move(0, 0); +#ifdef USE_COLOR + if (useColor) { + setfcolor(basic_color); +#ifdef USE_BG_COLOR + setbcolor(bg_color); +#endif /* USE_BG_COLOR */ + } +#endif /* USE_COLOR */ + clrtobotx(); + for (i = 0; i < LASTLINE; i++) { + if (buf == current) { + c = i; + standout(); + } + writeBufferName(buf, i); + if (buf == current) { + standend(); + clrtoeolx(); + move(i, 0); + toggle_stand(); + } + else + clrtoeolx(); + if (buf->nextBuffer == NULL) { + move(i + 1, 0); + clrtobotx(); + break; + } + buf = buf->nextBuffer; + } + standout(); + /* FIXME: gettextize? */ + message("Buffer selection mode: SPC for select / D for delete buffer", 0, + 0); + standend(); + /* + * move(LASTLINE, COLS - 1); */ + move(c, 0); + refresh(); + return buf->nextBuffer; +} + + +/* + * Select buffer visually + */ +Buffer * +selectBuffer(Buffer *firstbuf, Buffer *currentbuf, char *selectchar) +{ + int i, cpoint, /* Current Buffer Number */ + spoint, /* Current Line on Screen */ + maxbuf, sclimit = LASTLINE; /* Upper limit of line * number in + * the * screen */ + Buffer *buf, *topbuf; + char c; + + i = cpoint = 0; + for (buf = firstbuf; buf != NULL; buf = buf->nextBuffer) { + if (buf == currentbuf) + cpoint = i; + i++; + } + maxbuf = i; + + if (cpoint >= sclimit) { + spoint = sclimit / 2; + topbuf = nthBuffer(firstbuf, cpoint - spoint); + } + else { + topbuf = firstbuf; + spoint = cpoint; + } + listBuffer(topbuf, currentbuf); + + for (;;) { + if ((c = getch()) == ESC_CODE) { + if ((c = getch()) == '[' || c == 'O') { + switch (c = getch()) { + case 'A': + c = 'k'; + break; + case 'B': + c = 'j'; + break; + case 'C': + c = ' '; + break; + case 'D': + c = 'B'; + break; + } + } + } +#ifdef __EMX__ + else if (!c) + switch (getch()) { + case K_UP: + c = 'k'; + break; + case K_DOWN: + c = 'j'; + break; + case K_RIGHT: + c = ' '; + break; + case K_LEFT: + c = 'B'; + } +#endif + switch (c) { + case CTRL_N: + case 'j': + if (spoint < sclimit - 1) { + if (currentbuf->nextBuffer == NULL) + continue; + writeBufferName(currentbuf, spoint); + currentbuf = currentbuf->nextBuffer; + cpoint++; + spoint++; + standout(); + writeBufferName(currentbuf, spoint); + standend(); + move(spoint, 0); + toggle_stand(); + } + else if (cpoint < maxbuf - 1) { + topbuf = currentbuf; + currentbuf = currentbuf->nextBuffer; + cpoint++; + spoint = 1; + listBuffer(topbuf, currentbuf); + } + break; + case CTRL_P: + case 'k': + if (spoint > 0) { + writeBufferName(currentbuf, spoint); + currentbuf = nthBuffer(topbuf, --spoint); + cpoint--; + standout(); + writeBufferName(currentbuf, spoint); + standend(); + move(spoint, 0); + toggle_stand(); + } + else if (cpoint > 0) { + i = cpoint - sclimit; + if (i < 0) + i = 0; + cpoint--; + spoint = cpoint - i; + currentbuf = nthBuffer(firstbuf, cpoint); + topbuf = nthBuffer(firstbuf, i); + listBuffer(topbuf, currentbuf); + } + break; + default: + *selectchar = c; + return currentbuf; + } + /* + * move(LASTLINE, COLS - 1); + */ + move(spoint, 0); + refresh(); + } +} + +/* + * Reshape HTML buffer + */ +void +reshapeBuffer(Buffer *buf) +{ + URLFile f; + Buffer sbuf; +#ifdef USE_M17N + wc_uint8 old_auto_detect = WcOption.auto_detect; +#endif + + if (!buf->need_reshape) + return; + buf->need_reshape = FALSE; + buf->width = INIT_BUFFER_WIDTH; + if (buf->sourcefile == NULL) + return; + init_stream(&f, SCM_LOCAL, NULL); + examineFile(buf->mailcap_source ? buf->mailcap_source : buf->sourcefile, + &f); + if (f.stream == NULL) + return; + copyBuffer(&sbuf, buf); + clearBuffer(buf); + while (buf->frameset) { + deleteFrameSet(buf->frameset); + buf->frameset = popFrameTree(&(buf->frameQ)); + } + + buf->href = NULL; + buf->name = NULL; + buf->img = NULL; + buf->formitem = NULL; + buf->formlist = NULL; + buf->linklist = NULL; + buf->maplist = NULL; + if (buf->hmarklist) + buf->hmarklist->nmark = 0; + if (buf->imarklist) + buf->imarklist->nmark = 0; + + if (buf->header_source) { + if (buf->currentURL.scheme != SCM_LOCAL || + buf->mailcap_source || !strcmp(buf->currentURL.file, "-")) { + URLFile h; + init_stream(&h, SCM_LOCAL, NULL); + examineFile(buf->header_source, &h); + if (h.stream) { + readHeader(&h, buf, TRUE, NULL); + UFclose(&h); + } + } + else if (buf->search_header) /* -m option */ + readHeader(&f, buf, TRUE, NULL); + } + +#ifdef USE_M17N + WcOption.auto_detect = WC_OPT_DETECT_OFF; + UseContentCharset = FALSE; +#endif + if (!strcasecmp(buf->type, "text/html")) + loadHTMLBuffer(&f, buf); + else + loadBuffer(&f, buf); + UFclose(&f); +#ifdef USE_M17N + WcOption.auto_detect = old_auto_detect; + UseContentCharset = TRUE; +#endif + + buf->height = LASTLINE + 1; + if (buf->firstLine && sbuf.firstLine) { + Line *cur = sbuf.currentLine; + int n; + + buf->pos = sbuf.pos + cur->bpos; + while (cur->bpos && cur->prev) + cur = cur->prev; + if (cur->real_linenumber > 0) + gotoRealLine(buf, cur->real_linenumber); + else + gotoLine(buf, cur->linenumber); + n = (buf->currentLine->linenumber - buf->topLine->linenumber) + - (cur->linenumber - sbuf.topLine->linenumber); + if (n) { + buf->topLine = lineSkip(buf, buf->topLine, n, FALSE); + if (cur->real_linenumber > 0) + gotoRealLine(buf, cur->real_linenumber); + else + gotoLine(buf, cur->linenumber); + } + buf->pos -= buf->currentLine->bpos; + if (FoldLine && strcasecmp(buf->type, "text/html")) + buf->currentColumn = 0; + else + buf->currentColumn = sbuf.currentColumn; + arrangeCursor(buf); + } + if (buf->check_url & CHK_URL) + chkURLBuffer(buf); +#ifdef USE_NNTP + if (buf->check_url & CHK_NMID) + chkNMIDBuffer(buf); + if (buf->real_scheme == SCM_NNTP || buf->real_scheme == SCM_NEWS) + reAnchorNewsheader(buf); +#endif + formResetBuffer(buf, sbuf.formitem); +} + +/* shallow copy */ +void +copyBuffer(Buffer *a, Buffer *b) +{ + readBufferCache(b); + bcopy((void *)b, (void *)a, sizeof(Buffer)); +} + +Buffer * +prevBuffer(Buffer *first, Buffer *buf) +{ + Buffer *b; + + for (b = first; b != NULL && b->nextBuffer != buf; b = b->nextBuffer) ; + return b; +} + +#define fwrite1(d, f) (fwrite(&d, sizeof(d), 1, f)==0) +#define fread1(d, f) (fread(&d, sizeof(d), 1, f)==0) + +int +writeBufferCache(Buffer *buf) +{ + Str tmp; + FILE *cache = NULL; + Line *l; +#ifdef USE_ANSI_COLOR + int colorflag; +#endif + + if (buf->savecache) + return -1; + + if (buf->firstLine == NULL) + goto _error1; + + tmp = tmpfname(TMPF_CACHE, NULL); + buf->savecache = tmp->ptr; + cache = fopen(buf->savecache, "w"); + if (!cache) + goto _error1; + + if (fwrite1(buf->currentLine->linenumber, cache) || + fwrite1(buf->topLine->linenumber, cache)) + goto _error; + + for (l = buf->firstLine; l; l = l->next) { + if (fwrite1(l->real_linenumber, cache) || + fwrite1(l->usrflags, cache) || + fwrite1(l->width, cache) || + fwrite1(l->len, cache) || + fwrite1(l->size, cache) || + fwrite1(l->bpos, cache) || fwrite1(l->bwidth, cache)) + goto _error; + if (l->bpos == 0) { + if (fwrite(l->lineBuf, 1, l->size, cache) < l->size || + fwrite(l->propBuf, sizeof(Lineprop), l->size, cache) < l->size) + goto _error; + } +#ifdef USE_ANSI_COLOR + colorflag = l->colorBuf ? 1 : 0; + if (fwrite1(colorflag, cache)) + goto _error; + if (colorflag) { + if (l->bpos == 0) { + if (fwrite(l->colorBuf, sizeof(Linecolor), l->size, cache) < + l->size) + goto _error; + } + } +#endif + } + + fclose(cache); + return 0; + _error: + fclose(cache); + unlink(buf->savecache); + _error1: + buf->savecache = NULL; + return -1; +} + +int +readBufferCache(Buffer *buf) +{ + FILE *cache; + Line *l = NULL, *prevl = NULL, *basel = NULL; + long lnum = 0, clnum, tlnum; +#ifdef USE_ANSI_COLOR + int colorflag; +#endif + + if (buf->savecache == NULL) + return -1; + + cache = fopen(buf->savecache, "r"); + if (cache == NULL || fread1(clnum, cache) || fread1(tlnum, cache)) { + buf->savecache = NULL; + return -1; + } + + while (!feof(cache)) { + lnum++; + prevl = l; + l = New(Line); + l->prev = prevl; + if (prevl) + prevl->next = l; + else + buf->firstLine = l; + l->linenumber = lnum; + if (lnum == clnum) + buf->currentLine = l; + if (lnum == tlnum) + buf->topLine = l; + if (fread1(l->real_linenumber, cache) || + fread1(l->usrflags, cache) || + fread1(l->width, cache) || + fread1(l->len, cache) || + fread1(l->size, cache) || + fread1(l->bpos, cache) || fread1(l->bwidth, cache)) + break; + if (l->bpos == 0) { + basel = l; + l->lineBuf = NewAtom_N(char, l->size + 1); + fread(l->lineBuf, 1, l->size, cache); + l->lineBuf[l->size] = '\0'; + l->propBuf = NewAtom_N(Lineprop, l->size); + fread(l->propBuf, sizeof(Lineprop), l->size, cache); + } + else if (basel) { + l->lineBuf = basel->lineBuf + l->bpos; + l->propBuf = basel->propBuf + l->bpos; + } + else + break; +#ifdef USE_ANSI_COLOR + if (fread1(colorflag, cache)) + break; + if (colorflag) { + if (l->bpos == 0) { + l->colorBuf = NewAtom_N(Linecolor, l->size); + fread(l->colorBuf, sizeof(Linecolor), l->size, cache); + } + else + l->colorBuf = basel->colorBuf + l->bpos; + } + else { + l->colorBuf = NULL; + } +#endif + } + buf->lastLine = prevl; + buf->lastLine->next = NULL; + fclose(cache); + unlink(buf->savecache); + buf->savecache = NULL; + return 0; +} |