Switch to simple buffers. - sam - An updated version of the sam text editor.
(HTM) git clone git://vernunftzentrum.de/sam.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
(DIR) commit b74192453a1bd53ded5dca89283ff6f27be028d2
(DIR) parent c278f2b4d6f063d41632760c4e59addd653af041
(HTM) Author: Rob King <jking@deadpixi.com>
Date: Mon, 3 Oct 2016 22:53:59 -0500
Switch to simple buffers.
Diffstat:
sam/Makefile | 2 +-
sam/buffer.c | 267 ++++++++++++++-----------------
sam/disc.c | 335 -------------------------------
sam/file.c | 18 +++++-------------
sam/sam.h | 62 ++-----------------------------
5 files changed, 133 insertions(+), 551 deletions(-)
---
(DIR) diff --git a/sam/Makefile b/sam/Makefile
@@ -33,7 +33,7 @@ CFLAGS=$(STANDARDS) $(INCS) $(INCLUDES) -DUSE64BITS=$(USE64BITS) -DRXPATH='"$(RX
LIB=../libframe/libframe.a ../libXg/libXg.a
CC?=c99
-OBJ=sam.o address.o buffer.o cmd.o disc.o error.o file.o io.o \
+OBJ=sam.o address.o buffer.o cmd.o error.o file.o io.o \
list.o mesg.o moveto.o multi.o rasp.o regexp.o shell.o \
string.o sys.o unix.o xec.o
(DIR) diff --git a/sam/buffer.c b/sam/buffer.c
@@ -1,176 +1,155 @@
-/* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
+/* Copyright 2016 Rob King -- See LICENSE for details */
+
#include "sam.h"
-int incache(Buffer*, Posn, Posn);
+#define BUFFER_MIN 65535
+#define GAPSIZE(b) ((b)->ge - (b)->gs)
-Buffer *
-Bopen(Discdesc *dd)
+typedef size_t pos_t;
+typedef struct Gapbuffer Gapbuffer;
+struct Gapbuffer{
+ size_t size;
+ pos_t gs;
+ pos_t ge;
+ wchar_t *buf;
+};
+
+static void
+movegap(Gapbuffer *b, pos_t p)
{
- Buffer *b;
+ if (p == b->gs)
+ return;
+ else if (p < b->gs){
+ size_t d = b->gs - p;
+ b->gs -= d;
+ b->ge -= d;
+ wmemmove(b->buf + b->ge, b->buf + b->gs, d);
+ } else{
+ size_t d = p - b->gs;
+ b->gs += d;
+ b->ge += d;
+ wmemmove(b->buf + b->gs - d, b->buf + b->ge - d, d);
+ }
+}
- b = emalloc(sizeof(Buffer));
- b->disc = Dopen(dd);
- Strinit(&b->cache);
- return b;
+static void
+ensuregap(Gapbuffer *b, size_t l)
+{
+ size_t ns = b->size + l + BUFFER_MIN;
+ size_t es = b->size - b->ge;
+
+ if (GAPSIZE(b) >= l)
+ return;
+
+ b->buf = realloc(b->buf, ns * RUNESIZE);
+ if (!b->buf)
+ panic("out of memory");
+
+ wmemmove(b->buf + (ns - es), b->buf + b->ge, es);
+ b->ge = ns - es;
+ b->size = ns;
}
-void
-Bterm(Buffer *b)
+static void
+deletebuffer(Gapbuffer *b, pos_t p, size_t l)
{
- Dclose(b->disc);
- Strclose(&b->cache);
- free(b);
+ movegap(b, p);
+ b->ge += l;
}
-int
-Bread(Buffer *b, wchar_t *addr, int n, Posn p0)
+static size_t
+readbuffer(Gapbuffer *b, pos_t p, size_t l, wchar_t *c)
{
- int m;
-
- if(b->c2>b->disc->nrunes || b->c1>b->disc->nrunes)
- panic("bread cache");
- if(p0 < 0)
- panic("Bread p0<0");
- if(p0+n > b->nrunes){
- n = b->nrunes-p0;
- if(n < 0)
- panic("Bread<0");
- }
- if(!incache(b, p0, p0+n)){
- Bflush(b);
- if(n>=BLOCKSIZE/2)
- return Dread(b->disc, addr, n, p0);
- else{
- Posn minp;
- if(b->nrunes-p0>BLOCKSIZE/2)
- m = BLOCKSIZE/2;
- else
- m = b->nrunes-p0;
- if(m<n)
- m = n;
- minp = p0-BLOCKSIZE/2;
- if(minp<0)
- minp = 0;
- m += p0-minp;
- Strinsure(&b->cache, m);
- if(Dread(b->disc, b->cache.s, m, minp)!=m)
- panic("Bread");
- b->cache.n = m;
- b->c1 = minp;
- b->c2 = minp+m;
- b->dirty = false;
- }
+ size_t r = 0;
+
+ if (p < b->gs){
+ size_t d = b->gs - p;
+ size_t t = l > d ? d : l;
+
+ wmemcpy(c, b->buf + p, t);
+ c += t;
+ l -= t;
+ r += t;
+
+ wmemcpy(c, b->buf + b->ge, l);
+ r += l;
+ } else{
+ p += GAPSIZE(b);
+
+ wmemcpy(c, b->buf + p, l);
+ r = l;
}
- memmove(addr, &b->cache.s[p0-b->c1], n*RUNESIZE);
- return n;
+
+ return r;
}
-void
-Binsert(Buffer *b, String *s, Posn p0)
+static void
+insertbuffer(Gapbuffer *b, pos_t p, const wchar_t *s, size_t l)
{
- if(b->c2>b->disc->nrunes || b->c1>b->disc->nrunes)
- panic("binsert cache");
- if(p0<0)
- panic("Binsert p0<0");
- if(s->n == 0)
- return;
- if(incache(b, p0, p0) && b->cache.n+s->n<=STRSIZE){
- Strinsert(&b->cache, s, p0-b->c1);
- b->dirty = true;
- if(b->cache.n > BLOCKSIZE*2){
- b->nrunes += s->n;
- Bflush(b);
- /* try to leave some cache around p0 */
- if(p0 >= b->c1+BLOCKSIZE){
- /* first BLOCKSIZE can go */
- Strdelete(&b->cache, 0, BLOCKSIZE);
- b->c1 += BLOCKSIZE;
- }else if(p0 <= b->c2-BLOCKSIZE){
- /* last BLOCKSIZE can go */
- b->cache.n -= BLOCKSIZE;
- b->c2 -= BLOCKSIZE;
- }else{
- /* too hard; negate the cache and pick up next time */
- Strzero(&b->cache);
- b->c1 = b->c2 = 0;
- }
- return;
- }
- }else{
- Bflush(b);
- if(s->n >= BLOCKSIZE/2){
- b->cache.n = 0;
- b->c1 = b->c2 = 0;
- Dinsert(b->disc, s->s, s->n, p0);
- }else{
- int m;
- Posn minp;
- if(b->nrunes-p0 > BLOCKSIZE/2)
- m = BLOCKSIZE/2;
- else
- m = b->nrunes-p0;
- minp = p0-BLOCKSIZE/2;
- if(minp < 0)
- minp = 0;
- m += p0-minp;
- Strinsure(&b->cache, m);
- if(Dread(b->disc, b->cache.s, m, minp)!=m)
- panic("Bread");
- b->cache.n = m;
- b->c1 = minp;
- b->c2 = minp+m;
- Strinsert(&b->cache, s, p0-b->c1);
- b->dirty = true;
- }
- }
- b->nrunes += s->n;
+ ensuregap(b, l);
+ movegap(b, p);
+ wmemcpy(b->buf + b->gs, s, l);
+ b->gs += l;
}
-void
-Bdelete(Buffer *b, Posn p1, Posn p2)
+Buffer *
+Bopen(void)
{
- if(p1<0 || p2<0)
- panic("Bdelete p<0");
- if(b->c2>b->disc->nrunes || b->c1>b->disc->nrunes)
- panic("bdelete cache");
- if(p1 == p2)
- return;
- if(incache(b, p1, p2)){
- Strdelete(&b->cache, p1-b->c1, p2-b->c1);
- b->dirty = true;
- }else{
- Bflush(b);
- Ddelete(b->disc, p1, p2);
- b->cache.n = 0;
- b->c1 = b->c2 = 0;
- }
- b->nrunes -= p2-p1;
+ Buffer *b = calloc(1, sizeof(Buffer));
+ if (!b)
+ panic("out of memory");
+
+ b->gb = calloc(1, sizeof(Gapbuffer));
+ if (!b->gb)
+ panic("out of memory");
+
+ b->gb->buf = calloc(1, BUFFER_MIN * RUNESIZE);
+ if (!b->gb->buf)
+ panic("out of memory");
+
+ b->gb->size = BUFFER_MIN;
+ b->gb->gs = 0;
+ b->gb->ge = BUFFER_MIN;
+
+ return b;
}
void
-Bflush(Buffer *b)
+Bterm(Buffer *b)
{
- if(b->dirty){
- Dreplace(b->disc, b->c1, b->c2, b->cache.s, b->cache.n);
- b->c2 = b->c1+b->cache.n;
- b->dirty = false;
- if(b->nrunes != b->disc->nrunes)
- panic("Bflush");
+ if (b){
+ free(b->gb->buf);
+ free(b->gb);
+ free(b);
}
}
+int
+Bread(Buffer *b, wchar_t *c, int l, Posn p)
+{
+ if (p + l > b->nrunes)
+ l = b->nrunes - p;
+
+ if (l == 0)
+ return 0;
+
+ size_t r = readbuffer(b->gb, p, l, c);
+ return (int)r;
+}
+
void
-Bclean(Buffer *b)
+Binsert(Buffer *b, String *s, Posn p)
{
- if(b->dirty){
- Bflush(b);
- b->c1 = b->c2 = 0;
- Strzero(&b->cache);
+ if (s->n > 0){
+ insertbuffer(b->gb, (size_t)p, s->s, s->n);
+ b->nrunes += s->n;
}
}
-int
-incache(Buffer *b, Posn p1, Posn p2)
+void
+Bdelete(Buffer *b, Posn p1, Posn p2)
{
- return b->c1<=p1 && p2<=b->c1+b->cache.n;
+ size_t l = p2 - p1;
+ deletebuffer(b->gb, p1, l);
+ b->nrunes -= l;
}
(DIR) diff --git a/sam/disc.c b/sam/disc.c
@@ -1,335 +0,0 @@
-/* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
-#include "sam.h"
-
-#define BLOCKFILL (BLOCKSIZE/2)
-
-static Discdesc desc[NBUFFILES];
-
-void bkalloc(Disc*, int);
-void bkfree(Disc*, int);
-void bkwrite(Disc*, wchar_t*, int, int, int);
-void bkread(Disc*, wchar_t*, int, int, int);
-
-
-Discdesc *
-Dstart(void)
-{
- int i, fd;
- Discdesc *dd;
-
- for(i=0, dd=desc; dd->fd; i++, dd++)
- if(i == NBUFFILES-1)
- panic("too many buffer files");
- fd = newtmp();
- if(fd < 0)
- panic("can't create buffer file");
- dd->fd = fd;
- return dd;
-}
-
-Disc *
-Dopen(Discdesc *dd)
-{
- Disc *d;
-
- d = emalloc(sizeof(Disc));
- d->desc = dd;
- return d;
-}
-
-void
-Dclose(Disc *d)
-{
- int i;
-
- for(i=d->block.nused; --i>=0; ) /* backwards because bkfree() stacks */
- bkfree(d, i);
- free(d->block.listptr);
- free(d);
-}
-
-int
-Dread(Disc *d, wchar_t *addr, int n, Posn p1)
-{
- int i, nb, nr;
- Posn p = 0, p2 = p1+n;
-
- for(i=0; i<d->block.nused; i++){
- if((p+=d->block.blkptr[i].nrunes) > p1){
- p -= d->block.blkptr[i].nrunes;
- goto out;
- }
- }
- if(p == p1)
- return 0; /* eof */
- return -1; /* past eof */
-
- out:
- n = 0;
- if(p != p1){ /* trailing partial block */
- nb = d->block.blkptr[i].nrunes;
- if(p2 > p+nb)
- nr = nb-(p1-p);
- else
- nr = p2-p1;
- bkread(d, addr, nr, i, p1-p);
- /* advance to next block */
- p += nb;
- addr += nr;
- n += nr;
- i++;
- }
- /* whole blocks */
- while(p<p2 && (nb = d->block.blkptr[i].nrunes)<=p2-p){
- if(i >= d->block.nused)
- return n; /* eof */
- bkread(d, addr, nb, i, 0);
- p += nb;
- addr += nb;
- n += nb;
- i++;
- }
- if(p < p2){ /* any initial partial block left? */
- nr = p2-p;
- nb = d->block.blkptr[i].nrunes;
- if(nr>nb)
- nr = nb; /* eof */
- /* just read in the part that survives */
- bkread(d, addr, nr, i, 0);
- n += nr;
- }
- return n;
-}
-
-void
-Dinsert(Disc *d, wchar_t *addr, int n, Posn p0) /* if addr null, just make space */
-{
- int i, nb, ni;
- Posn p = 0;
- wchar_t hold[BLOCKSIZE];
- int nhold;
-
- for(i=0; i<d->block.nused; i++){
- if((p+=d->block.blkptr[i].nrunes) >= p0){
- p -= d->block.blkptr[i].nrunes;
- goto out;
- }
- }
- if(p != p0)
- panic("Dinsert"); /* beyond eof */
-
- out:
- d->nrunes += n;
- nhold = 0;
- if(i<d->block.nused && (nb=d->block.blkptr[i].nrunes)>p0-p){
- nhold = nb-(p0-p);
- bkread(d, hold, nhold, i, p0-p);
- d->block.blkptr[i].nrunes -= nhold; /* no write necessary */
- }
- /* insertion point is now at end of block i (which may not exist) */
- while(n > 0){
- if(i < d->block.nused
- && (nb=d->block.blkptr[i].nrunes) < BLOCKFILL){
- /* fill this block */
- if(nb+n > BLOCKSIZE)
- ni = BLOCKFILL-nb;
- else
- ni = n;
- if(addr)
- bkwrite(d, addr, ni, i, nb);
- nb += ni;
- }else{ /* make new block */
- if(i < d->block.nused)
- i++; /* put after this block, if it exists */
- bkalloc(d, i);
- if(n > BLOCKSIZE)
- ni = BLOCKFILL;
- else
- ni = n;
- if(addr)
- bkwrite(d, addr, ni, i, 0);
- nb = ni;
- }
- d->block.blkptr[i].nrunes = nb;
- if(addr)
- addr += ni;
- n -= ni;
- }
- if(nhold){
- if(i < d->block.nused
- && (nb=d->block.blkptr[i].nrunes)+nhold < BLOCKSIZE){
- /* fill this block */
- bkwrite(d, hold, nhold, i, nb);
- nb += nhold;
- }else{ /* make new block */
- if(i < d->block.nused)
- i++; /* put after this block, if it exists */
- bkalloc(d, i);
- bkwrite(d, hold, nhold, i, 0);
- nb = nhold;
- }
- d->block.blkptr[i].nrunes = nb;
- }
-}
-
-void
-Ddelete(Disc *d, Posn p1, Posn p2)
-{
- int i, nb, nd;
- Posn p = 0;
- wchar_t buf[BLOCKSIZE];
-
- for(i = 0; i<d->block.nused; i++){
- if((p+=d->block.blkptr[i].nrunes) > p1){
- p -= d->block.blkptr[i].nrunes;
- goto out;
- }
- }
- if(p1!=d->nrunes || p2!=p1)
- panic("Ddelete");
- return; /* beyond eof */
-
- out:
- d->nrunes -= p2-p1;
- if(p != p1){ /* throw away partial block */
- nb = d->block.blkptr[i].nrunes;
- bkread(d, buf, nb, i, 0);
- if(p2 >= p+nb)
- nd = nb-(p1-p);
- else{
- nd = p2-p1;
- memmove(buf+(p1-p), buf+(p1-p)+nd, RUNESIZE*(nb-((p1-p)+nd)));
- }
- nb -= nd;
- bkwrite(d, buf, nb, i, 0);
- d->block.blkptr[i].nrunes = nb;
- p2 -= nd;
- /* advance to next block */
- p += nb;
- i++;
- }
- /* throw away whole blocks */
- while(p<p2 && (nb = d->block.blkptr[i].nrunes)<=p2-p){
- if(i >= d->block.nused)
- panic("Ddelete 2");
- bkfree(d, i);
- p2 -= nb;
- }
- if(p >= p2) /* any initial partial block left to delete? */
- return; /* no */
- nd = p2-p;
- nb = d->block.blkptr[i].nrunes;
- /* just read in the part that survives */
- bkread(d, buf, nb-=nd, i, nd);
- /* a little block merging */
- if(nb<BLOCKSIZE/2 && i>0 && (nd = d->block.blkptr[i-1].nrunes)<BLOCKSIZE/2){
- memmove(buf+nd, buf, RUNESIZE*nb);
- bkread(d, buf, nd, --i, 0);
- bkfree(d, i);
- nb += nd;
- }
- bkwrite(d, buf, nb, i, 0);
- d->block.blkptr[i].nrunes = nb;
-}
-
-void
-Dreplace(Disc *d, Posn p1, Posn p2, wchar_t *addr, int n)
-{
- int i, nb, nr;
- Posn p = 0;
- wchar_t buf[BLOCKSIZE];
-
- if(p2-p1 > n)
- Ddelete(d, p1+n, p2);
- else if(p2-p1 < n)
- Dinsert(d, 0, n-(p2-p1), p2);
- if(n == 0)
- return;
- p2 = p1+n;
- /* they're now conformal; replace in place */
- for(i=0; i<d->block.nused; i++){
- if((p+=d->block.blkptr[i].nrunes) > p1){
- p -= d->block.blkptr[i].nrunes;
- goto out;
- }
- }
- panic("Dreplace");
-
- out:
- if(p != p1){ /* trailing partial block */
- nb = d->block.blkptr[i].nrunes;
- bkread(d, buf, nb, i, 0);
- if(p2 > p+nb)
- nr = nb-(p1-p);
- else
- nr = p2-p1;
- memmove(buf+p1-p, addr, RUNESIZE*nr);
- bkwrite(d, buf, nb, i, 0);
- /* advance to next block */
- p += nb;
- addr += nr;
- i++;
- }
- /* whole blocks */
- while(p<p2 && (nb = d->block.blkptr[i].nrunes)<=p2-p){
- if(i >= d->block.nused)
- panic("Dreplace 2");
- bkwrite(d, addr, nb, i, 0);
- p += nb;
- addr += nb;
- i++;
- }
- if(p < p2){ /* any initial partial block left? */
- nr = p2-p;
- nb = d->block.blkptr[i].nrunes;
- /* just read in the part that survives */
- bkread(d, buf+nr, nb-nr, i, nr);
- memmove(buf, addr, RUNESIZE*nr);
- bkwrite(d, buf, nb, i, 0);
- }
-}
-
-void
-bkread(Disc *d, wchar_t *loc, int n, int bk, int off)
-{
- Seek(d->desc->fd, RUNESIZE*(BLOCKSIZE*d->block.blkptr[bk].bnum+off), 0);
- Read(d->desc->fd, loc, n*RUNESIZE);
-}
-
-void
-bkwrite(Disc *d, wchar_t *loc, int n, int bk, int off)
-{
- Seek(d->desc->fd, RUNESIZE*(BLOCKSIZE*d->block.blkptr[bk].bnum+off), 0);
- Write(d->desc->fd, loc, n*RUNESIZE);
- /*
- * sleazy hack to avoid silly SGI kernel bug
- * fill partial block with garbage
- */
- if (off+n >= d->block.blkptr[bk].nrunes && off+n < BLOCKSIZE)
- Write(d->desc->fd, genbuf, (BLOCKSIZE-(off+n))*RUNESIZE);
-}
-
-void
-bkalloc(Disc *d, int n)
-{
- Discdesc *dd = d->desc;
- uint64_t bnum;
-
- if(dd->free.nused)
- bnum = dd->free.longptr[--dd->free.nused];
- else
- bnum = dd->nbk++;
- if(bnum >= 1<<(8*(sizeof(((Block*)0)->bnum))))
- error(Etmpovfl);
- inslist(&d->block, n, 0L);
- d->block.blkptr[n].bnum = bnum;
-}
-
-void
-bkfree(Disc *d, int n)
-{
- Discdesc *dd = d->desc;
-
- inslist(&dd->free, dd->free.nused, d->block.blkptr[n].bnum);
- dellist(&d->block, n);
-}
(DIR) diff --git a/sam/file.c b/sam/file.c
@@ -3,8 +3,6 @@
/*
* Files are splayed out a factor of NDISC to reduce indirect block access
*/
-Discdesc *files[NDISC];
-Discdesc *transcripts[NDISC];
Buffer *undobuf;
static String *ftempstr(wchar_t*, int);
int fcount;
@@ -24,9 +22,9 @@ enum{
void
Fstart(void)
{
- undobuf = Bopen(Dstart());
- snarfbuf = Bopen(Dstart());
- plan9buf = Bopen(Dstart());
+ undobuf = Bopen();
+ snarfbuf = Bopen();
+ plan9buf = Bopen();
}
void
@@ -56,12 +54,8 @@ Fopen(void)
File *f;
f = emalloc(sizeof(File));
- if(files[fcount] == 0){
- files[fcount] = Dstart();
- transcripts[fcount] = Dstart();
- }
- f->buf = Bopen(files[fcount]);
- f->transcript = Bopen(transcripts[fcount]);
+ f->buf = Bopen();
+ f->transcript = Bopen();
if(++fcount == NDISC)
fcount = 0;
f->nrunes = 0;
@@ -232,8 +226,6 @@ Fupdate(File *f, int mktrans, int toterm)
if(f->state == Readerr)
return false;
- if(lastfile && f!=lastfile)
- Bclean(lastfile->transcript); /* save memory when multifile */
lastfile = f;
Fflush(f);
if(f->marked)
(DIR) diff --git a/sam/sam.h b/sam/sam.h
@@ -23,8 +23,6 @@ typedef uint16_t Mod; /* modification number */
typedef struct Address Address;
typedef struct Block Block;
typedef struct Buffer Buffer;
-typedef struct Disc Disc;
-typedef struct Discdesc Discdesc;
typedef struct File File;
typedef struct List List;
typedef struct Mark Mark;
@@ -79,47 +77,6 @@ struct List /* code depends on a int64_t being able to hold a pointer */
#define filepptr g.filep
#define listval g.listv
-/*
- * Block must fit in a int64_t because the list routines manage arrays of
- * blocks. Two problems: some machines (e.g. Cray) can't pull this off
- * -- on them, use bitfields -- and the uint16_t bnum limits temp file sizes
- * to about 200 megabytes. Advantages: small, simple code and small
- * memory overhead. If you really want to edit huge files, making BLOCKSIZE
- * bigger is the easiest way.
-*
-* The necessary conditions are even stronger:
-* sizeof(struct Block)==sizeof(int64_t)
-* && the first 32 bits must hold bnum and nrunes.
-* When sizeof(uint16_t)+sizeof(int16_t) < sizeof(int64_t),
-* add padding at the beginning on a little endian and at
-* the end on a big endian, as shown below for the DEC Alpha.
- */
-struct Block
-{
-#if USE64BITS == 1
- char pad[sizeof(int64_t)-sizeof(uint16_t)-sizeof(int16_t)];
-#endif
- uint16_t bnum; /* absolute number on disk */
- int16_t nrunes; /* runes stored in this block */
-#if USE64BITS == 2
- char pad[sizeof(int64_t)-sizeof(uint16_t)-sizeof(int16_t)];
-#endif
-};
-
-struct Discdesc
-{
- int fd; /* plan 9 file descriptor of temp file */
- uint64_t nbk; /* high water mark */
- List free; /* array of free block indices */
-};
-
-struct Disc
-{
- Discdesc *desc; /* descriptor of temp file */
- Posn nrunes; /* runes on disc file */
- List block; /* list of used block indices */
-};
-
struct String
{
int16_t n;
@@ -127,14 +84,11 @@ struct String
wchar_t *s;
};
+struct Gapbuffer;
struct Buffer
{
- Disc *disc; /* disc storage */
- Posn nrunes; /* total length of buffer */
- String cache; /* in-core storage for efficiency */
- Posn c1, c2; /* cache start and end positions in disc */
- /* note: if dirty, cache is really c1, c1+cache.n */
- int dirty; /* cache dirty */
+ Posn nrunes;
+ struct Gapbuffer *gb;
};
#define NGETC 128
@@ -209,19 +163,12 @@ union Hdr
#define Fgetc(f) ((--(f)->ngetc<0)? Fgetcload(f, (f)->getcp) : (f)->getcbuf[(f)->getcp++, (f)->getci++])
#define Fbgetc(f) (((f)->getci<=0)? Fbgetcload(f, (f)->getcp) : (f)->getcbuf[--(f)->getcp, --(f)->getci])
-void Bclean(Buffer*);
void Bterm(Buffer*);
void Bdelete(Buffer*, Posn, Posn);
void Bflush(Buffer*);
void Binsert(Buffer*, String*, Posn);
-Buffer *Bopen(Discdesc*);
+Buffer *Bopen(void);
int Bread(Buffer*, wchar_t*, int, Posn);
-void Dclose(Disc*);
-void Ddelete(Disc*, Posn, Posn);
-void Dinsert(Disc*, wchar_t*, int, Posn);
-Disc *Dopen(Discdesc*);
-int Dread(Disc*, wchar_t*, int, Posn);
-void Dreplace(Disc*, Posn, Posn, wchar_t*, int);
int Fbgetcload(File*, Posn);
int Fbgetcset(File*, Posn);
int64_t Fchars(File*, wchar_t*, Posn, Posn);
@@ -334,7 +281,6 @@ void warn_S(Warn, String*);
int whichmenu(File*);
void writef(File*);
Posn writeio(File*);
-Discdesc *Dstart(void);
extern wchar_t samname[]; /* compiler dependent */
extern wchar_t *left[];