Logo Search packages:      
Sourcecode: w3m version File versions  Download package

buffer.c

/* $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;
}

Generated by  Doxygen 1.6.0   Back to index