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

vfile.c

/*
 *    Software virtual memory system
 *    Copyright
 *          (C) 1992 Joseph H. Allen
 *
 *    This file is part of JOE (Joe's Own Editor)
 */
#include "config.h"
#include "types.h"

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include <fcntl.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <unistd.h>

#include "blocks.h"
#include "queue.h"
#include "path.h"
#include "utils.h"
#include "vfile.h"
#include "vs.h"

static VFILE vfiles = { {&vfiles, &vfiles} };   /* Known vfiles */
static VPAGE *freepages = NULL;     /* Linked list of free pages */
static VPAGE *htab[HTSIZE];   /* Hash table of page headers */
static long curvalloc = 0;    /* Amount of memory in use */
static long maxvalloc = ILIMIT;     /* Maximum allowed */
unsigned char *vbase;               /* Data first entry in vheader refers to */
VPAGE **vheaders = NULL;      /* Array of header addresses */
static int vheadsz = 0;       /* No. entries allocated to vheaders */

void vflsh(void)
{
      VPAGE *vp;
      VPAGE *vlowest;
      long addr;
      long last;
      VFILE *vfile;
      int x;

      for (vfile = vfiles.link.next; vfile != &vfiles; vfile = vfile->link.next) {
            last = -1;
            loop:
            addr = MAXLONG;
            vlowest = NULL;
            for (x = 0; x != HTSIZE; x++)
                  for (vp = htab[x]; vp; vp = vp->next)
                        if (vp->addr < addr && vp->addr > last && vp->vfile == vfile && (vp->addr >= vfile->size || (vp->dirty && !vp->count))) {
                              addr = vp->addr;
                              vlowest = vp;
                        }
            if (vlowest) {
                  if (!vfile->name)
                        vfile->name = mktmp(NULL);
                  if (!vfile->fd)
                        vfile->fd = open((char *)(vfile->name), O_RDWR);
                  lseek(vfile->fd, addr, 0);
                  if (addr + PGSIZE > vsize(vfile)) {
                        joe_write(vfile->fd, vlowest->data, (int) (vsize(vfile) - addr));
                        vfile->size = vsize(vfile);
                  } else {
                        joe_write(vfile->fd, vlowest->data, PGSIZE);
                        if (addr + PGSIZE > vfile->size)
                              vfile->size = addr + PGSIZE;
                  }
                  vlowest->dirty = 0;
                  last = addr;
                  goto loop;
            }
      }
}

void vflshf(VFILE *vfile)
{
      VPAGE *vp;
      VPAGE *vlowest;
      long addr;
      int x;

      loop:
      addr = MAXLONG;
      vlowest = NULL;
      for (x = 0; x != HTSIZE; x++)
            for (vp = htab[x]; vp; vp = vp->next)
                  if (vp->addr < addr && vp->dirty && vp->vfile == vfile && !vp->count) {
                        addr = vp->addr;
                        vlowest = vp;
                  }
      if (vlowest) {
            if (!vfile->name)
                  vfile->name = mktmp(NULL);
            if (!vfile->fd) {
                  vfile->fd = open((char *)(vfile->name), O_RDWR);
            }
            lseek(vfile->fd, addr, 0);
            if (addr + PGSIZE > vsize(vfile)) {
                  joe_write(vfile->fd, vlowest->data, (int) (vsize(vfile) - addr));
                  vfile->size = vsize(vfile);
            } else {
                  joe_write(vfile->fd, vlowest->data, PGSIZE);
                  if (addr + PGSIZE > vfile->size)
                        vfile->size = addr + PGSIZE;
            }
            vlowest->dirty = 0;
            goto loop;
      }
}

static unsigned char *mema(int align, int size)
{
      unsigned char *z = (unsigned char *) joe_malloc(align + size);

      return z + align - physical(z) % align;
}

unsigned char *vlock(VFILE *vfile, unsigned long addr)
{
      VPAGE *vp, *pp;
      int x, y;
      int ofst = (addr & (PGSIZE - 1));

      addr -= ofst;

      for (vp = htab[((addr >> LPGSIZE) + (unsigned long) vfile) & (HTSIZE - 1)]; vp; vp = vp->next)
            if (vp->vfile == vfile && vp->addr == addr) {
                  ++vp->count;
                  return vp->data + ofst;
            }

      if (freepages) {
            vp = freepages;
            freepages = vp->next;
            goto gotit;
      }

      if (curvalloc + PGSIZE <= maxvalloc) {
            vp = (VPAGE *) joe_malloc(sizeof(VPAGE) * INC);
            if (vp) {
                  vp->data = (unsigned char *) mema(PGSIZE, PGSIZE * INC);
                  if (vp->data) {
                        int q;

                        curvalloc += PGSIZE * INC;
                        if (!vheaders) {
                              vheaders = (VPAGE **) joe_malloc((vheadsz = INC) * sizeof(VPAGE *));
                              vbase = vp->data;
                        } else if (physical(vp->data) < physical(vbase)) {
                              VPAGE **t = vheaders;
                              int amnt = (physical(vbase) - physical(vp->data)) >> LPGSIZE;

                              vheaders = (VPAGE **) joe_malloc((amnt + vheadsz) * sizeof(VPAGE *));
                              mmove(vheaders + amnt, t, vheadsz * sizeof(VPAGE *));
                              vheadsz += amnt;
                              vbase = vp->data;
                              joe_free(t);
                        } else if (((physical(vp->data + PGSIZE * INC) - physical(vbase)) >> LPGSIZE) > vheadsz) {
                              vheaders = (VPAGE **)
                                  joe_realloc(vheaders, (vheadsz = (((physical(vp->data + PGSIZE * INC) - physical(vbase)) >> LPGSIZE))) * sizeof(VPAGE *));
                        }
                        for (q = 1; q != INC; ++q) {
                              vp[q].next = freepages;
                              freepages = vp + q;
                              vp[q].data = vp->data + q * PGSIZE;
                              vheader(vp->data + q * PGSIZE) = vp + q;
                        }
                        vheader(vp->data) = vp;
                        goto gotit;
                  }
                  joe_free(vp);
                  vp = NULL;
            }
      }

      for (y = HTSIZE, x = (random() & (HTSIZE - 1)); y; x = ((x + 1) & (HTSIZE - 1)), --y)
            for (pp = (VPAGE *) (htab + x), vp = pp->next; vp; pp = vp, vp = vp->next)
                  if (!vp->count && !vp->dirty) {
                        pp->next = vp->next;
                        goto gotit;
                  }
      vflsh();
      for (y = HTSIZE, x = (random() & (HTSIZE - 1)); y; x = ((x + 1) & (HTSIZE - 1)), --y)
            for (pp = (VPAGE *) (htab + x), vp = pp->next; vp; pp = vp, vp = vp->next)
                  if (!vp->count && !vp->dirty) {
                        pp->next = vp->next;
                        goto gotit;
                  }
      write(2, "vfile: out of memory\n", 21);
      exit(1);

      gotit:
      vp->addr = addr;
      vp->vfile = vfile;
      vp->dirty = 0;
      vp->count = 1;
      vp->next = htab[((addr >> LPGSIZE) + (unsigned long)vfile) & (HTSIZE - 1)];
      htab[((addr >> LPGSIZE) + (unsigned long)vfile) & (HTSIZE - 1)] = vp;

      if (addr < vfile->size) {
            if (!vfile->fd) {
                  vfile->fd = open((char *)(vfile->name), O_RDWR);
            }
            lseek(vfile->fd, addr, 0);
            if (addr + PGSIZE > vfile->size) {
                  joe_read(vfile->fd, vp->data, (int) (vfile->size - addr));
                  mset(vp->data + vfile->size - addr, 0, PGSIZE - (int) (vfile->size - addr));
            } else
                  joe_read(vfile->fd, vp->data, PGSIZE);
      } else
            mset(vp->data, 0, PGSIZE);

      return vp->data + ofst;
}

VFILE *vtmp(void)
{
      VFILE *new = (VFILE *) joe_malloc(sizeof(VFILE));

      new->fd = 0;
      new->name = NULL;
      new->alloc = 0;
      new->size = 0;
      new->left = 0;
      new->lv = 0;
      new->vpage = NULL;
      new->flags = 1;
      new->vpage1 = NULL;
      new->addr = -1;
      return enqueb_f(VFILE, link, &vfiles, new);
}

#ifdef junk

VFILE *vopen(name)
unsigned char *name;
{
      struct stat buf;
      VFILE *new = (VFILE *) joe_malloc(sizeof(VFILE));

      new->name = vsncpy(NULL, 0, sz(name));
      new->fd = open(name, O_RDWR);
      if (!new->fd) {
            fprintf(stderr, "Couldn\'t open file \'%s\'\n", name);
            joe_free(new);
            return NULL;
      }
      fstat(new->fd, &buf);
      new->size = buf.st_size;
      new->alloc = new->size;
      new->left = 0;
      new->lv = 0;
      new->vpage = NULL;
      new->flags = 0;
      new->vpage1 = NULL;
      new->addr = -1;
      return enqueb_f(VFILE, link, &vfiles, new);
}

#endif

void vclose(VFILE *vfile)
{
      VPAGE *vp, *pp;
      int x;

      if (vfile->vpage)
            vunlock(vfile->vpage);
      if (vfile->vpage1)
            vunlock(vfile->vpage1);
      if (vfile->name) {
            if (vfile->flags)
                  unlink((char *)vfile->name);
            else
                  vflshf(vfile);
            vsrm(vfile->name);
      }
      if (vfile->fd)
            close(vfile->fd);
      joe_free(deque_f(VFILE, link, vfile));
      for (x = 0; x != HTSIZE; x++)
            for (pp = (VPAGE *) (htab + x), vp = pp->next; vp;)
                  if (vp->vfile == vfile) {
                        pp->next = vp->next;
                        vp->next = freepages;
                        freepages = vp;
                        vp = pp->next;
                  } else {
                        pp = vp;
                        vp = vp->next;
                  }
}

#ifdef junk
/* this is now broken */
void vlimit(amount)
long amount;
{
      VPAGE *vp, *pp;
      int x, y;

      maxvalloc = amount;
      while (curvalloc > maxvalloc)
            if (freepages) {
                  vp = freepages;
                  freepages = vp->next;
                  joe_free(vp->data);
                  joe_free(vp);
                  curvalloc -= PGSIZE;
            } else {
                  again:
                  for (y = HTSIZE, x = (random() & (HTSIZE - 1)); y; x = ((x + 1) & (HTSIZE - 1)), --y)
                        for (pp = (VPAGE *) (htab + x), vp = pp->next; vp; pp = vp, vp = vp->next)
                              if (!vp->count && !vp->dirty) {
                                    pp->next = vp->next;
                                    joe_free(vp->data);
                                    joe_free(vp);
                                    if ((curvalloc -= PGSIZE)
                                        <= maxvalloc)
                                          return;
                                    goto again;
                              }
                  vflsh();
                  again1:
                  for (y = HTSIZE, x = (random() & (HTSIZE - 1)); y; x = ((x + 1) & (HTSIZE - 1)), --y)
                        for (pp = (VPAGE *) (htab + x), vp = pp->next; vp; pp = vp, vp = vp->next)
                              if (!vp->count && !vp->dirty) {
                                    pp->next = vp->next;
                                    joe_free(vp->data);
                                    joe_free(vp);
                                    if ((curvalloc -= PGSIZE)
                                        <= maxvalloc)
                                          return;
                                    goto again1;
                              }
                  return;
            }
}
#endif

long my_valloc(VFILE *vfile, long int size)
{
      long start = vsize(vfile);

      vfile->alloc = start + size;
      if (vfile->lv) {
            if (vheader(vfile->vpage)->addr + PGSIZE > vfile->alloc)
                  vfile->lv = PGSIZE - (vfile->alloc - vheader(vfile->vpage)->addr);
            else
                  vfile->lv = 0;
      }
      return start;
}

#ifdef junk

void vseek(vfile, addr)
VFILE *vfile;
long addr;
{
      vfile->alloc = vsize(vfile);
      if (addr > vfile->alloc)
            vfile->alloc = addr;
      if (!vfile->vpage)
            vfile->vpage = vlock(vfile, addr & ~(long) (PGSIZE - 1));
      else if (vheader(vfile->vpage)->addr != (addr & ~(long) (PGSIZE - 1))) {
            vunlock(vfile->vpage);
            vfile->vpage = vlock(vfile, addr & ~(long) (PGSIZE - 1));
      }
      vfile->bufp = vfile->vpage + (addr & (PGSIZE - 1));
      vfile->left = vfile->vpage + PGSIZE - vfile->bufp;
      if (vheader(vfile->vpage)->addr + PGSIZE > vfile->alloc)
            vfile->lv = PGSIZE - (vfile->alloc - vheader(vfile->vpage)->addr);
      else
            vfile->lv = 0;
}

int _vrgetc(vfile)
VFILE *vfile;
{
      if (vtell(vfile) == 0)
            return NO_MORE_DATA;
      vseek(vfile, vtell(vfile) - 1);
      ++vfile->bufp;
      --vfile->left;
      return vrgetc(vfile);
}

int _vgetc(vfile)
VFILE *vfile;
{
      if (vtell(vfile) == vsize(vfile))
            return NO_MORE_DATA;
      vseek(vfile, vtell(vfile));
      return vgetc(vfile);
}

int nmvgetc(v)
VFILE *v;
{
      return vgetc(v);
}

int _vputc(vfile, c)
VFILE *vfile;
unsigned char c;
{
      vseek(vfile, vtell(vfile));
      return vputc(vfile, c);
}

short vgetw(vfile)
VFILE *vfile;
{
      short w;

      if (vtell(vfile) + 2 > vsize(vfile))
            return -1;
      w = vgetc(vfile);
      w += ((short) vgetc(vfile) << 8);
      return w;
}

short vputw(vfile, w)
VFILE *vfile;
short w;
{
      vputc(vfile, w);
      vputc(vfile, w >> 8);
      return w;
}

long vgetl(vfile)
VFILE *vfile;
{
      long w;

      if (vtell(vfile) + 4 > vsize(vfile))
            return -1;
      w = vgetc(vfile);
      w += ((long) vgetc(vfile) << 8);
      w += ((long) vgetc(vfile) << 16);
      w += ((long) vgetc(vfile) << 24);
      return w;
}

long vputl(vfile, w)
VFILE *vfile;
long w;
{
      vputc(vfile, w);
      vputc(vfile, w >> 8);
      vputc(vfile, w >> 16);
      vputc(vfile, w >> 24);
      return w;
}

int _rc(vfile, addr)
VFILE *vfile;
long addr;
{
      if (vfile->vpage1)
            vunlock(vfile->vpage1);
      vfile->vpage1 = vlock(vfile, vfile->addr = (addr & ~(long) (PGSIZE - 1)));
      return rc(vfile, addr);
}

int _wc(vfile, addr, c)
VFILE *vfile;
long addr;
unsigned char c;
{
      if (addr + 1 > vsize(vfile))
            my_valloc(vfile, addr + 1 - vsize(vfile));
      if (vfile->vpage1)
            vunlock(vfile->vpage1);
      vfile->vpage1 = vlock(vfile, vfile->addr = (addr & ~(long) (PGSIZE - 1)));
      return wc(vfile, addr, c);
}

short rw(vfile, addr)
VFILE *vfile;
long addr;
{
      short c;

      if (addr + 2 > vsize(vfile))
            return -1;
      c = rc(vfile, addr);
      c += ((short) rc(vfile, addr + 1) << 8);
      return c;
}

short ww(vfile, addr, c)
VFILE *vfile;
long addr;
short c;
{
      if (addr + 2 > vsize(vfile))
            my_valloc(vfile, addr + 2 - vsize(vfile));
      wc(vfile, addr, c);
      wc(vfile, addr + 1, c >> 8);
      return c;
}

long rl(vfile, addr)
VFILE *vfile;
long addr;
{
      long c;

      if (addr + 4 > vsize(vfile))
            return -1;
      c = rc(vfile, addr);
      c += ((long) rc(vfile, addr + 1) << 8);
      c += ((long) rc(vfile, addr + 2) << 16);
      c += ((long) rc(vfile, addr + 3) << 24);
      return c;
}

long wl(vfile, addr, c)
VFILE *vfile;
long addr;
long c;
{
      if (addr + 4 > vsize(vfile))
            my_valloc(vfile, addr + 4 - vsize(vfile));
      wc(vfile, addr, c);
      wc(vfile, addr + 1, c >> 8);
      wc(vfile, addr + 2, c >> 16);
      wc(vfile, addr + 3, c >> 24);
      return c;
}

void vread(v, blk, size)
VFILE *v;
unsigned char *blk;
int size;
{
      long addr = vtell(v);
      unsigned char *src;
      int x;

      while (size) {
            src = vlock(v, addr);
            x = PGSIZE - (addr & (PGSIZE - 1));
            if (x >= size) {
                  vseek(v, addr + size);
                  mcpy(blk, src, size);
                  vunlock(src);
                  return;
            }
            size -= x;
            addr += x;
            mcpy(blk, src, x);
            blk += x;
            vunlock(src);
      }
      vseek(v, addr);
}

void vwrite(v, blk, size)
VFILE *v;
unsigned char *blk;
int size;
{
      long addr = vtell(v);
      unsigned char *src;
      int x;

      if (addr + size > vsize(v))
            my_valloc(v, addr + size - vsize(v));
      while (size) {
            src = vlock(v, addr);
            x = PGSIZE - (addr & (PGSIZE - 1));
            if (x >= size) {
                  vseek(v, addr + size);
                  mcpy(src, blk, size);
                  vchanged(src);
                  vunlock(src);
                  return;
            }
            size -= x;
            addr += x;
            mcpy(src, blk, x);
            blk += x;
            vchanged(src);
            vunlock(src);
      }
      vseek(v, addr);
}

/* Write zstring to vfile */

void vputs(v, s)
VFILE *v;
unsigned char *s;
{
      while (*s) {
            vputc(v, *s);
            ++s;
      }
}

/* Read a line from a file.  Remove '\n' if there was any */

unsigned char *vgets(v, s)
VFILE *v;
unsigned char *s;
{
      unsigned char *b, *a, *x, *y;
      int cnt;

      /* Return with NULL if at end of file */
      if (vtell(v) == vsize(v)) {
            vsrm(s);
            return NULL;
      }

      /* Create string if it doesn't exist */
      if (!s)
            s = vsmk(80);

      /* Zero string length */
      sLen(s) = 0;

      loop:

      /* Set b to end of string, a to page pointer, and cnt to min which ever
       * (string or page) has the least space left
       */
      b = s + sLen(s);
      a = v->bufp;
      cnt = Imin(sSIZ(s) - sLen(s), v->left - v->lv);

      /* Copy until \n is found or until page or buffer out of space */
      if (cnt >= 16)
            do {
                  if ((b[0] = a[0]) == '\n') {
                        a += 1;
                        b += 1;
                        goto ovr;
                  }
                  if ((b[1] = a[1]) == '\n') {
                        a += 2;
                        b += 2;
                        cnt -= 1;
                        goto ovr;
                  }
                  if ((b[2] = a[2]) == '\n') {
                        a += 3;
                        b += 3;
                        cnt -= 2;
                        goto ovr;
                  }
                  if ((b[3] = a[3]) == '\n') {
                        a += 4;
                        b += 4;
                        cnt -= 3;
                        goto ovr;
                  }
                  if ((b[4] = a[4]) == '\n') {
                        a += 5;
                        b += 5;
                        cnt -= 4;
                        goto ovr;
                  }
                  if ((b[5] = a[5]) == '\n') {
                        a += 6;
                        b += 6;
                        cnt -= 5;
                        goto ovr;
                  }
                  if ((b[6] = a[6]) == '\n') {
                        a += 7;
                        b += 7;
                        cnt -= 6;
                        goto ovr;
                  }
                  if ((b[7] = a[7]) == '\n') {
                        a += 8;
                        b += 8;
                        cnt -= 7;
                        goto ovr;
                  }
                  if ((b[8] = a[8]) == '\n') {
                        a += 9;
                        b += 9;
                        cnt -= 8;
                        goto ovr;
                  }
                  if ((b[9] = a[9]) == '\n') {
                        a += 10;
                        b += 10;
                        cnt -= 9;
                        goto ovr;
                  }
                  if ((b[10] = a[10]) == '\n') {
                        a += 11;
                        b += 11;
                        cnt -= 10;
                        goto ovr;
                  }
                  if ((b[11] = a[11]) == '\n') {
                        a += 12;
                        b += 12;
                        cnt -= 11;
                        goto ovr;
                  }
                  if ((b[12] = a[12]) == '\n') {
                        a += 13;
                        b += 13;
                        cnt -= 12;
                        goto ovr;
                  }
                  if ((b[13] = a[13]) == '\n') {
                        a += 14;
                        b += 14;
                        cnt -= 13;
                        goto ovr;
                  }
                  if ((b[14] = a[14]) == '\n') {
                        a += 15;
                        b += 15;
                        cnt -= 14;
                        goto ovr;
                  }
                  if ((b[15] = a[15]) == '\n') {
                        a += 16;
                        b += 16;
                        cnt -= 15;
                        goto ovr;
                  }
            } while (a += 16, b += 16, (cnt -= 16) >= 16);

/*
      x = a;
      y = b;
      a += cnt - 15;
      b += cnt - 15;
      switch(cnt) {
      case 15:    if((b[0]=a[0])=='\n') { a+=1; b+=1; goto zif; }
      case 14:    if((b[1]=a[1])=='\n') { a+=2; b+=2; goto zif; }
      case 13:    if((b[2]=a[2])=='\n') { a+=3; b+=3; goto zif; }
      case 12:    if((b[3]=a[3])=='\n') { a+=4; b+=4; goto zif; }
      case 11:    if((b[4]=a[4])=='\n') { a+=5; b+=5; goto zif; }
      case 10:    if((b[5]=a[5])=='\n') { a+=6; b+=6; goto zif; }
      case 9:           if((b[6]=a[6])=='\n')  { a+=7; b+=7; goto zif; }
      case 8:           if((b[7]=a[7])=='\n')  { a+=8; b+=8; goto zif; }
      case 7:           if((b[8]=a[8])=='\n')  { a+=9; b+=9; goto zif; }
      case 6:           if((b[9]=a[9])=='\n')  { a+=10; b+=10; goto zif; }
      case 5:           if((b[10]=a[10])=='\n'){ a+=11; b+=11; goto zif; }
      case 4:           if((b[11]=a[11])=='\n'){ a+=12; b+=12; goto zif; }
      case 3:           if((b[12]=a[12])=='\n'){ a+=13; b+=13; goto zif; }
      case 2:           if((b[13]=a[13])=='\n'){ a+=14; b+=14; goto zif; }
      case 1:           if((b[14]=a[14])=='\n'){ a+=15; b+=15; goto zif; }
      }
      a = x + cnt;
      b = y + cnt;
      cnt=0;
      goto ovr;
zif:  cnt -= a - x - 1;
*/

      if (cnt)
            do {
                  if ((*b++ = *a++) == '\n')
                        break;
            } while (--cnt);

      ovr:

      /* Update string and page data */
      sLen(s) = b - s;
      v->left -= a - v->bufp;
      v->bufp = a;

      if (!cnt)
            if (vtell(v) == vsize(v))
                  b[0] = 0;
            else {
                  if (sLen(s) == sSiz(s))
                        s = vsensure(s, sLen(s) + (sLen(s) >> 1) + 16);
                  if (!v->left)
                        vseek(v, vtell(v));
                  goto loop;
      } else
            b[-1] = 0;

      return s;
}
#endif

Generated by  Doxygen 1.6.0   Back to index