mirror of
https://hacklab.nilfm.cc/acme
synced 2024-10-22 14:31:48 +00:00
Derek Stevens
2908f1ff9b
window tag/body with keyboard focus will render tick in hilighted text color; doesn't work yet for column/row tags
295 lines
6.2 KiB
C
295 lines
6.2 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <draw.h>
|
|
#include <thread.h>
|
|
#include <cursor.h>
|
|
#include <mouse.h>
|
|
#include <keyboard.h>
|
|
#include "libframe/frame.h"
|
|
#include <fcall.h>
|
|
#include <plumb.h>
|
|
#include <libsec.h>
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
|
|
enum {
|
|
Slop = 100 /* room to grow with reallocation */
|
|
};
|
|
|
|
static void sizecache(Buffer* b, uint n) {
|
|
if (n <= b->cmax)
|
|
return;
|
|
b->cmax = n + Slop;
|
|
b->c = runerealloc(b->c, b->cmax);
|
|
}
|
|
|
|
static void addblock(Buffer* b, uint i, uint n) {
|
|
if (i > b->nbl)
|
|
error("internal error: addblock");
|
|
|
|
b->bl = realloc(b->bl, (b->nbl + 1) * sizeof b->bl[0]);
|
|
if (i < b->nbl)
|
|
memmove(b->bl + i + 1, b->bl + i, (b->nbl - i) * sizeof(Block*));
|
|
b->bl[i] = disknewblock(disk, n);
|
|
b->nbl++;
|
|
}
|
|
|
|
static void delblock(Buffer* b, uint i) {
|
|
if (i >= b->nbl)
|
|
error("internal error: delblock");
|
|
|
|
diskrelease(disk, b->bl[i]);
|
|
b->nbl--;
|
|
if (i < b->nbl)
|
|
memmove(b->bl + i, b->bl + i + 1, (b->nbl - i) * sizeof(Block*));
|
|
b->bl = realloc(b->bl, b->nbl * sizeof b->bl[0]);
|
|
}
|
|
|
|
/*
|
|
* Move cache so b->cq <= q0 < b->cq+b->cnc.
|
|
* If at very end, q0 will fall on end of cache block.
|
|
*/
|
|
|
|
static void flush(Buffer* b) {
|
|
if (b->cdirty || b->cnc == 0) {
|
|
if (b->cnc == 0)
|
|
delblock(b, b->cbi);
|
|
else
|
|
diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
|
|
b->cdirty = FALSE;
|
|
}
|
|
}
|
|
|
|
static void setcache(Buffer* b, uint q0) {
|
|
Block **blp, *bl;
|
|
uint i, q;
|
|
|
|
if (q0 > b->nc)
|
|
error("internal error: setcache");
|
|
/*
|
|
* flush and reload if q0 is not in cache.
|
|
*/
|
|
if (b->nc == 0 || (b->cq <= q0 && q0 < b->cq + b->cnc))
|
|
return;
|
|
/*
|
|
* if q0 is at end of file and end of cache, continue to grow this block
|
|
*/
|
|
if (q0 == b->nc && q0 == b->cq + b->cnc && b->cnc < Maxblock)
|
|
return;
|
|
flush(b);
|
|
/* find block */
|
|
if (q0 < b->cq) {
|
|
q = 0;
|
|
i = 0;
|
|
} else {
|
|
q = b->cq;
|
|
i = b->cbi;
|
|
}
|
|
blp = &b->bl[i];
|
|
while (q + (*blp)->u.n <= q0 && q + (*blp)->u.n < b->nc) {
|
|
q += (*blp)->u.n;
|
|
i++;
|
|
blp++;
|
|
if (i >= b->nbl)
|
|
error("block not found");
|
|
}
|
|
bl = *blp;
|
|
/* remember position */
|
|
b->cbi = i;
|
|
b->cq = q;
|
|
sizecache(b, bl->u.n);
|
|
b->cnc = bl->u.n;
|
|
/*read block*/
|
|
diskread(disk, bl, b->c, b->cnc);
|
|
}
|
|
|
|
void bufinsert(Buffer* b, uint q0, Rune* s, uint n) {
|
|
uint i, m, t, off;
|
|
|
|
if (q0 > b->nc)
|
|
error("internal error: bufinsert");
|
|
|
|
while (n > 0) {
|
|
setcache(b, q0);
|
|
off = q0 - b->cq;
|
|
if (b->cnc + n <= Maxblock) {
|
|
/* Everything fits in one block. */
|
|
t = b->cnc + n;
|
|
m = n;
|
|
if (b->bl == nil) { /* allocate */
|
|
if (b->cnc != 0)
|
|
error("internal error: bufinsert1 cnc!=0");
|
|
addblock(b, 0, t);
|
|
b->cbi = 0;
|
|
}
|
|
sizecache(b, t);
|
|
runemove(b->c + off + m, b->c + off, b->cnc - off);
|
|
runemove(b->c + off, s, m);
|
|
b->cnc = t;
|
|
goto Tail;
|
|
}
|
|
/*
|
|
* We must make a new block. If q0 is at
|
|
* the very beginning or end of this block,
|
|
* just make a new block and fill it.
|
|
*/
|
|
if (q0 == b->cq || q0 == b->cq + b->cnc) {
|
|
if (b->cdirty)
|
|
flush(b);
|
|
m = min(n, Maxblock);
|
|
if (b->bl == nil) { /* allocate */
|
|
if (b->cnc != 0)
|
|
error("internal error: bufinsert2 cnc!=0");
|
|
i = 0;
|
|
} else {
|
|
i = b->cbi;
|
|
if (q0 > b->cq)
|
|
i++;
|
|
}
|
|
addblock(b, i, m);
|
|
sizecache(b, m);
|
|
runemove(b->c, s, m);
|
|
b->cq = q0;
|
|
b->cbi = i;
|
|
b->cnc = m;
|
|
goto Tail;
|
|
}
|
|
/*
|
|
* Split the block; cut off the right side and
|
|
* let go of it.
|
|
*/
|
|
m = b->cnc - off;
|
|
if (m > 0) {
|
|
i = b->cbi + 1;
|
|
addblock(b, i, m);
|
|
diskwrite(disk, &b->bl[i], b->c + off, m);
|
|
b->cnc -= m;
|
|
}
|
|
/*
|
|
* Now at end of block. Take as much input
|
|
* as possible and tack it on end of block.
|
|
*/
|
|
m = min(n, Maxblock - b->cnc);
|
|
sizecache(b, b->cnc + m);
|
|
runemove(b->c + b->cnc, s, m);
|
|
b->cnc += m;
|
|
Tail:
|
|
b->nc += m;
|
|
q0 += m;
|
|
s += m;
|
|
n -= m;
|
|
b->cdirty = TRUE;
|
|
}
|
|
}
|
|
|
|
void bufdelete(Buffer* b, uint q0, uint q1) {
|
|
uint m, n, off;
|
|
|
|
if (!(q0 <= q1 && q0 <= b->nc && q1 <= b->nc))
|
|
error("internal error: bufdelete");
|
|
while (q1 > q0) {
|
|
setcache(b, q0);
|
|
off = q0 - b->cq;
|
|
if (q1 > b->cq + b->cnc)
|
|
n = b->cnc - off;
|
|
else
|
|
n = q1 - q0;
|
|
m = b->cnc - (off + n);
|
|
if (m > 0)
|
|
runemove(b->c + off, b->c + off + n, m);
|
|
b->cnc -= n;
|
|
b->cdirty = TRUE;
|
|
q1 -= n;
|
|
b->nc -= n;
|
|
}
|
|
}
|
|
|
|
static int bufloader(void* v, uint q0, Rune* r, int nr) {
|
|
bufinsert(v, q0, r, nr);
|
|
return nr;
|
|
}
|
|
|
|
uint loadfile(
|
|
int fd, uint q0, int* nulls, int (*f)(void*, uint, Rune*, int), void* arg,
|
|
DigestState* h) {
|
|
char* p;
|
|
Rune* r;
|
|
int l, m, n, nb, nr;
|
|
uint q1;
|
|
|
|
p = emalloc((Maxblock + UTFmax + 1) * sizeof p[0]);
|
|
r = runemalloc(Maxblock);
|
|
m = 0;
|
|
n = 1;
|
|
q1 = q0;
|
|
/*
|
|
* At top of loop, may have m bytes left over from
|
|
* last pass, possibly representing a partial rune.
|
|
*/
|
|
while (n > 0) {
|
|
n = read(fd, p + m, Maxblock);
|
|
if (n < 0) {
|
|
warning(nil, "read error in Buffer.load");
|
|
break;
|
|
}
|
|
if (h != nil)
|
|
sha1((uchar*)p + m, n, nil, h);
|
|
m += n;
|
|
p[m] = 0;
|
|
l = m;
|
|
if (n > 0)
|
|
l -= UTFmax;
|
|
cvttorunes(p, l, r, &nb, &nr, nulls);
|
|
memmove(p, p + nb, m - nb);
|
|
m -= nb;
|
|
q1 += (*f)(arg, q1, r, nr);
|
|
}
|
|
free(p);
|
|
free(r);
|
|
return q1 - q0;
|
|
}
|
|
|
|
uint bufload(Buffer* b, uint q0, int fd, int* nulls, DigestState* h) {
|
|
if (q0 > b->nc)
|
|
error("internal error: bufload");
|
|
return loadfile(fd, q0, nulls, bufloader, b, h);
|
|
}
|
|
|
|
void bufread(Buffer* b, uint q0, Rune* s, uint n) {
|
|
uint m;
|
|
|
|
if (!(q0 <= b->nc && q0 + n <= b->nc))
|
|
error("bufread: internal error");
|
|
|
|
while (n > 0) {
|
|
setcache(b, q0);
|
|
m = min(n, b->cnc - (q0 - b->cq));
|
|
runemove(s, b->c + (q0 - b->cq), m);
|
|
q0 += m;
|
|
s += m;
|
|
n -= m;
|
|
}
|
|
}
|
|
|
|
void bufreset(Buffer* b) {
|
|
int i;
|
|
|
|
b->nc = 0;
|
|
b->cnc = 0;
|
|
b->cq = 0;
|
|
b->cdirty = 0;
|
|
b->cbi = 0;
|
|
/* delete backwards to avoid n² behavior */
|
|
for (i = b->nbl - 1; --i >= 0;)
|
|
delblock(b, i);
|
|
}
|
|
|
|
void bufclose(Buffer* b) {
|
|
bufreset(b);
|
|
free(b->c);
|
|
b->c = nil;
|
|
b->cnc = 0;
|
|
free(b->bl);
|
|
b->bl = nil;
|
|
b->nbl = 0;
|
|
}
|