add gitignore, clang-format, build script; merge src's patch for spaces in filenames

This commit is contained in:
Iris Lightshard 2021-06-12 23:54:54 -06:00
parent cf57dbe235
commit 5540d37849
Signed by: nilix
GPG key ID: 3B7FBC22144E6398
38 changed files with 15300 additions and 15770 deletions

23
.clang-format Normal file
View file

@ -0,0 +1,23 @@
TabWidth: 2
IndentWidth: 2
ContinuationIndentWidth: 2
UseTab: Never
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
PenaltyReturnTypeOnItsOwnLine: 255
IndentCaseLabels: true
SpaceBeforeParens: ControlStatements
AlignAfterOpenBracket: AlwaysBreak
BinPackArguments: false
BinPackArguments: false
PointerAlignment: Left
BreakBeforeBraces: Attach
SortIncludes: false
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AlignEscapedNewlines: Left

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
**/*.o **/*.o
**/o.* **/o.*
acme

679
acme.c

File diff suppressed because it is too large Load diff

196
addr.c
View file

@ -12,39 +12,27 @@
#include "dat.h" #include "dat.h"
#include "fns.h" #include "fns.h"
enum enum { None = 0, Fore = '+', Back = '-' };
{
None = 0,
Fore = '+',
Back = '-'
};
enum enum { Char, Line };
{
Char,
Line
};
int int isaddrc(int r) {
isaddrc(int r) if (r && utfrune("0123456789+-/$.#,;?", r) != nil)
{
if(r && utfrune("0123456789+-/$.#,;?", r)!=nil)
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
/* /*
* quite hard: could be almost anything but white space, but we are a little conservative, * quite hard: could be almost anything but white space, but we are a little
* aiming for regular expressions of alphanumerics and no white space * conservative, aiming for regular expressions of alphanumerics and no white
* space
*/ */
int int isregexc(int r) {
isregexc(int r) if (r == 0)
{
if(r == 0)
return FALSE; return FALSE;
if(isalnum(r)) if (isalnum(r))
return TRUE; return TRUE;
if(utfrune("^+-.*?#,;[]()$", r)!=nil) if (utfrune("^+-.*?#,;[]()$", r) != nil)
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
@ -54,130 +42,125 @@ isregexc(int r)
// and then nr chars, being careful not to walk past // and then nr chars, being careful not to walk past
// the end of the current line. // the end of the current line.
// It returns the final position. // It returns the final position.
long long nlcounttopos(Text* t, long q0, long nl, long nr) {
nlcounttopos(Text *t, long q0, long nl, long nr) while (nl > 0 && q0 < t->file->b.nc) {
{ if (textreadc(t, q0++) == '\n')
while(nl > 0 && q0 < t->file->b.nc) {
if(textreadc(t, q0++) == '\n')
nl--; nl--;
} }
if(nl > 0) if (nl > 0)
return q0; return q0;
while(nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') { while (nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') {
q0++; q0++;
nr--; nr--;
} }
return q0; return q0;
} }
Range Range number(
number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp) uint showerr, Text* t, Range r, int line, int dir, int size, int* evalp) {
{
uint q0, q1; uint q0, q1;
if(size == Char){ if (size == Char) {
if(dir == Fore) if (dir == Fore)
line = r.q1+line; line = r.q1 + line;
else if(dir == Back){ else if (dir == Back) {
if(r.q0==0 && line>0) if (r.q0 == 0 && line > 0)
r.q0 = t->file->b.nc; r.q0 = t->file->b.nc;
line = r.q0 - line; line = r.q0 - line;
} }
if(line<0 || line>t->file->b.nc) if (line < 0 || line > t->file->b.nc)
goto Rescue; goto Rescue;
*evalp = TRUE; *evalp = TRUE;
return range(line, line); return range(line, line);
} }
q0 = r.q0; q0 = r.q0;
q1 = r.q1; q1 = r.q1;
switch(dir){ switch (dir) {
case None: case None:
q0 = 0; q0 = 0;
q1 = 0; q1 = 0;
Forward: Forward:
while(line>0 && q1<t->file->b.nc) while (line > 0 && q1 < t->file->b.nc)
if(textreadc(t, q1++) == '\n' || q1==t->file->b.nc) if (textreadc(t, q1++) == '\n' || q1 == t->file->b.nc)
if(--line > 0) if (--line > 0)
q0 = q1; q0 = q1;
if(line==1 && q1==t->file->b.nc) // 6 goes to end of 5-line file if (line == 1 && q1 == t->file->b.nc) // 6 goes to end of 5-line file
break; break;
if(line > 0) if (line > 0)
goto Rescue; goto Rescue;
break; break;
case Fore: case Fore:
if(q1 > 0) if (q1 > 0)
while(q1<t->file->b.nc && textreadc(t, q1-1) != '\n') while (q1 < t->file->b.nc && textreadc(t, q1 - 1) != '\n')
q1++; q1++;
q0 = q1; q0 = q1;
goto Forward; goto Forward;
case Back: case Back:
if(q0 < t->file->b.nc) if (q0 < t->file->b.nc)
while(q0>0 && textreadc(t, q0-1)!='\n') while (q0 > 0 && textreadc(t, q0 - 1) != '\n')
q0--; q0--;
q1 = q0; q1 = q0;
while(line>0 && q0>0){ while (line > 0 && q0 > 0) {
if(textreadc(t, q0-1) == '\n'){ if (textreadc(t, q0 - 1) == '\n') {
if(--line >= 0) if (--line >= 0)
q1 = q0; q1 = q0;
} }
--q0; --q0;
} }
/* :1-1 is :0 = #0, but :1-2 is an error */ /* :1-1 is :0 = #0, but :1-2 is an error */
if(line > 1) if (line > 1)
goto Rescue; goto Rescue;
while(q0>0 && textreadc(t, q0-1)!='\n') while (q0 > 0 && textreadc(t, q0 - 1) != '\n')
--q0; --q0;
} }
*evalp = TRUE; *evalp = TRUE;
return range(q0, q1); return range(q0, q1);
Rescue: Rescue:
if(showerr) if (showerr)
warning(nil, "address out of range\n"); warning(nil, "address out of range\n");
*evalp = FALSE; *evalp = FALSE;
return r; return r;
} }
Range regexp(
Range uint showerr, Text* t, Range lim, Range r, Rune* pat, int dir, int* foundp) {
regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
{
int found; int found;
Rangeset sel; Rangeset sel;
int q; int q;
if(pat[0] == '\0' && rxnull()){ if (pat[0] == '\0' && rxnull()) {
if(showerr) if (showerr)
warning(nil, "no previous regular expression\n"); warning(nil, "no previous regular expression\n");
*foundp = FALSE; *foundp = FALSE;
return r; return r;
} }
if(pat[0] && rxcompile(pat) == FALSE){ if (pat[0] && rxcompile(pat) == FALSE) {
*foundp = FALSE; *foundp = FALSE;
return r; return r;
} }
if(dir == Back) if (dir == Back)
found = rxbexecute(t, r.q0, &sel); found = rxbexecute(t, r.q0, &sel);
else{ else {
if(lim.q0 < 0) if (lim.q0 < 0)
q = Infinity; q = Infinity;
else else
q = lim.q1; q = lim.q1;
found = rxexecute(t, nil, r.q1, q, &sel); found = rxexecute(t, nil, r.q1, q, &sel);
} }
if(!found && showerr) if (!found && showerr)
warning(nil, "no match for regexp\n"); warning(nil, "no match for regexp\n");
*foundp = found; *foundp = found;
return sel.r[0]; return sel.r[0];
} }
Range Range address(
address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp) uint showerr, Text* t, Range lim, Range ar, void* a, uint q0, uint q1,
{ int (*getc)(void*, uint), int* evalp, uint* qp) {
int dir, size, npat; int dir, size, npat;
int prevc, c, nc, n; int prevc, c, nc, n;
uint q; uint q;
Rune *pat; Rune* pat;
Range r, nr; Range r, nr;
r = ar; r = ar;
@ -185,22 +168,22 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
dir = None; dir = None;
size = Line; size = Line;
c = 0; c = 0;
while(q < q1){ while (q < q1) {
prevc = c; prevc = c;
c = (*getc)(a, q++); c = (*getc)(a, q++);
switch(c){ switch (c) {
default: default:
*qp = q-1; *qp = q - 1;
return r; return r;
case ';': case ';':
ar = r; ar = r;
/* fall through */ /* fall through */
case ',': case ',':
if(prevc == 0) /* lhs defaults to 0 */ if (prevc == 0) /* lhs defaults to 0 */
r.q0 = 0; r.q0 = 0;
if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */ if (q >= q1 && t != nil && t->file != nil) /* rhs defaults to $ */
r.q1 = t->file->b.nc; r.q1 = t->file->b.nc;
else{ else {
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q); nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
r.q1 = nr.q1; r.q1 = nr.q1;
} }
@ -208,46 +191,55 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
return r; return r;
case '+': case '+':
case '-': case '-':
if(*evalp && (prevc=='+' || prevc=='-')) if (*evalp && (prevc == '+' || prevc == '-'))
if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?') if ((nc = (*getc)(a, q)) != '#' && nc != '/' && nc != '?')
r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */ r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one
*/
dir = c; dir = c;
break; break;
case '.': case '.':
case '$': case '$':
if(q != q0+1){ if (q != q0 + 1) {
*qp = q-1; *qp = q - 1;
return r; return r;
} }
if(*evalp) if (*evalp)
if(c == '.') if (c == '.')
r = ar; r = ar;
else else
r = range(t->file->b.nc, t->file->b.nc); r = range(t->file->b.nc, t->file->b.nc);
if(q < q1) if (q < q1)
dir = Fore; dir = Fore;
else else
dir = None; dir = None;
break; break;
case '#': case '#':
if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){ if (q == q1 || (c = (*getc)(a, q++)) < '0' || '9' < c) {
*qp = q-1; *qp = q - 1;
return r; return r;
} }
size = Char; size = Char;
/* fall through */ /* fall through */
case '0': case '1': case '2': case '3': case '4': case '0':
case '5': case '6': case '7': case '8': case '9': case '1':
n = c -'0'; case '2':
while(q<q1){ case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
n = c - '0';
while (q < q1) {
nc = (*getc)(a, q++); nc = (*getc)(a, q++);
if(nc<'0' || '9'<nc){ if (nc < '0' || '9' < nc) {
q--; q--;
break; break;
} }
n = n*10+(nc-'0'); n = n * 10 + (nc - '0');
} }
if(*evalp) if (*evalp)
r = number(showerr, t, r, n, dir, size, evalp); r = number(showerr, t, r, n, dir, size, evalp);
dir = None; dir = None;
size = Line; size = Line;
@ -258,29 +250,29 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
case '/': case '/':
npat = 0; npat = 0;
pat = nil; pat = nil;
while(q<q1){ while (q < q1) {
c = (*getc)(a, q++); c = (*getc)(a, q++);
switch(c){ switch (c) {
case '\n': case '\n':
--q; --q;
goto out; goto out;
case '\\': case '\\':
pat = runerealloc(pat, npat+1); pat = runerealloc(pat, npat + 1);
pat[npat++] = c; pat[npat++] = c;
if(q == q1) if (q == q1)
goto out; goto out;
c = (*getc)(a, q++); c = (*getc)(a, q++);
break; break;
case '/': case '/':
goto out; goto out;
} }
pat = runerealloc(pat, npat+1); pat = runerealloc(pat, npat + 1);
pat[npat++] = c; pat[npat++] = c;
} }
out: out:
pat = runerealloc(pat, npat+1); pat = runerealloc(pat, npat + 1);
pat[npat] = 0; pat[npat] = 0;
if(*evalp) if (*evalp)
r = regexp(showerr, t, lim, r, pat, dir, evalp); r = regexp(showerr, t, lim, r, pat, dir, evalp);
free(pat); free(pat);
dir = None; dir = None;
@ -288,7 +280,7 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
break; break;
} }
} }
if(*evalp && dir != None) if (*evalp && dir != None)
r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */ r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
*qp = q; *qp = q;
return r; return r;

194
buff.c
View file

@ -12,47 +12,37 @@
#include "dat.h" #include "dat.h"
#include "fns.h" #include "fns.h"
enum enum {
{
Slop = 100 /* room to grow with reallocation */ Slop = 100 /* room to grow with reallocation */
}; };
static static void sizecache(Buffer* b, uint n) {
void if (n <= b->cmax)
sizecache(Buffer *b, uint n)
{
if(n <= b->cmax)
return; return;
b->cmax = n+Slop; b->cmax = n + Slop;
b->c = runerealloc(b->c, b->cmax); b->c = runerealloc(b->c, b->cmax);
} }
static static void addblock(Buffer* b, uint i, uint n) {
void if (i > b->nbl)
addblock(Buffer *b, uint i, uint n)
{
if(i > b->nbl)
error("internal error: addblock"); error("internal error: addblock");
b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]); b->bl = realloc(b->bl, (b->nbl + 1) * sizeof b->bl[0]);
if(i < b->nbl) if (i < b->nbl)
memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*)); memmove(b->bl + i + 1, b->bl + i, (b->nbl - i) * sizeof(Block*));
b->bl[i] = disknewblock(disk, n); b->bl[i] = disknewblock(disk, n);
b->nbl++; b->nbl++;
} }
static static void delblock(Buffer* b, uint i) {
void if (i >= b->nbl)
delblock(Buffer *b, uint i)
{
if(i >= b->nbl)
error("internal error: delblock"); error("internal error: delblock");
diskrelease(disk, b->bl[i]); diskrelease(disk, b->bl[i]);
b->nbl--; b->nbl--;
if(i < b->nbl) if (i < b->nbl)
memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*)); memmove(b->bl + i, b->bl + i + 1, (b->nbl - i) * sizeof(Block*));
b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]); b->bl = realloc(b->bl, b->nbl * sizeof b->bl[0]);
} }
/* /*
@ -60,12 +50,9 @@ delblock(Buffer *b, uint i)
* If at very end, q0 will fall on end of cache block. * If at very end, q0 will fall on end of cache block.
*/ */
static static void flush(Buffer* b) {
void if (b->cdirty || b->cnc == 0) {
flush(Buffer *b) if (b->cnc == 0)
{
if(b->cdirty || b->cnc==0){
if(b->cnc == 0)
delblock(b, b->cbi); delblock(b, b->cbi);
else else
diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc); diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
@ -73,40 +60,37 @@ flush(Buffer *b)
} }
} }
static static void setcache(Buffer* b, uint q0) {
void
setcache(Buffer *b, uint q0)
{
Block **blp, *bl; Block **blp, *bl;
uint i, q; uint i, q;
if(q0 > b->nc) if (q0 > b->nc)
error("internal error: setcache"); error("internal error: setcache");
/* /*
* flush and reload if q0 is not in cache. * flush and reload if q0 is not in cache.
*/ */
if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc)) if (b->nc == 0 || (b->cq <= q0 && q0 < b->cq + b->cnc))
return; return;
/* /*
* if q0 is at end of file and end of cache, continue to grow this block * 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) if (q0 == b->nc && q0 == b->cq + b->cnc && b->cnc < Maxblock)
return; return;
flush(b); flush(b);
/* find block */ /* find block */
if(q0 < b->cq){ if (q0 < b->cq) {
q = 0; q = 0;
i = 0; i = 0;
}else{ } else {
q = b->cq; q = b->cq;
i = b->cbi; i = b->cbi;
} }
blp = &b->bl[i]; blp = &b->bl[i];
while(q+(*blp)->u.n <= q0 && q+(*blp)->u.n < b->nc){ while (q + (*blp)->u.n <= q0 && q + (*blp)->u.n < b->nc) {
q += (*blp)->u.n; q += (*blp)->u.n;
i++; i++;
blp++; blp++;
if(i >= b->nbl) if (i >= b->nbl)
error("block not found"); error("block not found");
} }
bl = *blp; bl = *blp;
@ -119,30 +103,28 @@ setcache(Buffer *b, uint q0)
diskread(disk, bl, b->c, b->cnc); diskread(disk, bl, b->c, b->cnc);
} }
void void bufinsert(Buffer* b, uint q0, Rune* s, uint n) {
bufinsert(Buffer *b, uint q0, Rune *s, uint n)
{
uint i, m, t, off; uint i, m, t, off;
if(q0 > b->nc) if (q0 > b->nc)
error("internal error: bufinsert"); error("internal error: bufinsert");
while(n > 0){ while (n > 0) {
setcache(b, q0); setcache(b, q0);
off = q0-b->cq; off = q0 - b->cq;
if(b->cnc+n <= Maxblock){ if (b->cnc + n <= Maxblock) {
/* Everything fits in one block. */ /* Everything fits in one block. */
t = b->cnc+n; t = b->cnc + n;
m = n; m = n;
if(b->bl == nil){ /* allocate */ if (b->bl == nil) { /* allocate */
if(b->cnc != 0) if (b->cnc != 0)
error("internal error: bufinsert1 cnc!=0"); error("internal error: bufinsert1 cnc!=0");
addblock(b, 0, t); addblock(b, 0, t);
b->cbi = 0; b->cbi = 0;
} }
sizecache(b, t); sizecache(b, t);
runemove(b->c+off+m, b->c+off, b->cnc-off); runemove(b->c + off + m, b->c + off, b->cnc - off);
runemove(b->c+off, s, m); runemove(b->c + off, s, m);
b->cnc = t; b->cnc = t;
goto Tail; goto Tail;
} }
@ -151,17 +133,17 @@ bufinsert(Buffer *b, uint q0, Rune *s, uint n)
* the very beginning or end of this block, * the very beginning or end of this block,
* just make a new block and fill it. * just make a new block and fill it.
*/ */
if(q0==b->cq || q0==b->cq+b->cnc){ if (q0 == b->cq || q0 == b->cq + b->cnc) {
if(b->cdirty) if (b->cdirty)
flush(b); flush(b);
m = min(n, Maxblock); m = min(n, Maxblock);
if(b->bl == nil){ /* allocate */ if (b->bl == nil) { /* allocate */
if(b->cnc != 0) if (b->cnc != 0)
error("internal error: bufinsert2 cnc!=0"); error("internal error: bufinsert2 cnc!=0");
i = 0; i = 0;
}else{ } else {
i = b->cbi; i = b->cbi;
if(q0 > b->cq) if (q0 > b->cq)
i++; i++;
} }
addblock(b, i, m); addblock(b, i, m);
@ -176,20 +158,20 @@ bufinsert(Buffer *b, uint q0, Rune *s, uint n)
* Split the block; cut off the right side and * Split the block; cut off the right side and
* let go of it. * let go of it.
*/ */
m = b->cnc-off; m = b->cnc - off;
if(m > 0){ if (m > 0) {
i = b->cbi+1; i = b->cbi + 1;
addblock(b, i, m); addblock(b, i, m);
diskwrite(disk, &b->bl[i], b->c+off, m); diskwrite(disk, &b->bl[i], b->c + off, m);
b->cnc -= m; b->cnc -= m;
} }
/* /*
* Now at end of block. Take as much input * Now at end of block. Take as much input
* as possible and tack it on end of block. * as possible and tack it on end of block.
*/ */
m = min(n, Maxblock-b->cnc); m = min(n, Maxblock - b->cnc);
sizecache(b, b->cnc+m); sizecache(b, b->cnc + m);
runemove(b->c+b->cnc, s, m); runemove(b->c + b->cnc, s, m);
b->cnc += m; b->cnc += m;
Tail: Tail:
b->nc += m; b->nc += m;
@ -200,23 +182,21 @@ bufinsert(Buffer *b, uint q0, Rune *s, uint n)
} }
} }
void void bufdelete(Buffer* b, uint q0, uint q1) {
bufdelete(Buffer *b, uint q0, uint q1)
{
uint m, n, off; uint m, n, off;
if(!(q0<=q1 && q0<=b->nc && q1<=b->nc)) if (!(q0 <= q1 && q0 <= b->nc && q1 <= b->nc))
error("internal error: bufdelete"); error("internal error: bufdelete");
while(q1 > q0){ while (q1 > q0) {
setcache(b, q0); setcache(b, q0);
off = q0-b->cq; off = q0 - b->cq;
if(q1 > b->cq+b->cnc) if (q1 > b->cq + b->cnc)
n = b->cnc - off; n = b->cnc - off;
else else
n = q1-q0; n = q1 - q0;
m = b->cnc - (off+n); m = b->cnc - (off + n);
if(m > 0) if (m > 0)
runemove(b->c+off, b->c+off+n, m); runemove(b->c + off, b->c + off + n, m);
b->cnc -= n; b->cnc -= n;
b->cdirty = TRUE; b->cdirty = TRUE;
q1 -= n; q1 -= n;
@ -224,22 +204,20 @@ bufdelete(Buffer *b, uint q0, uint q1)
} }
} }
static int static int bufloader(void* v, uint q0, Rune* r, int nr) {
bufloader(void *v, uint q0, Rune *r, int nr)
{
bufinsert(v, q0, r, nr); bufinsert(v, q0, r, nr);
return nr; return nr;
} }
uint uint loadfile(
loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg, DigestState *h) int fd, uint q0, int* nulls, int (*f)(void*, uint, Rune*, int), void* arg,
{ DigestState* h) {
char *p; char* p;
Rune *r; Rune* r;
int l, m, n, nb, nr; int l, m, n, nb, nr;
uint q1; uint q1;
p = emalloc((Maxblock+UTFmax+1)*sizeof p[0]); p = emalloc((Maxblock + UTFmax + 1) * sizeof p[0]);
r = runemalloc(Maxblock); r = runemalloc(Maxblock);
m = 0; m = 0;
n = 1; n = 1;
@ -248,58 +226,52 @@ loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *ar
* At top of loop, may have m bytes left over from * At top of loop, may have m bytes left over from
* last pass, possibly representing a partial rune. * last pass, possibly representing a partial rune.
*/ */
while(n > 0){ while (n > 0) {
n = read(fd, p+m, Maxblock); n = read(fd, p + m, Maxblock);
if(n < 0){ if (n < 0) {
warning(nil, "read error in Buffer.load"); warning(nil, "read error in Buffer.load");
break; break;
} }
if(h != nil) if (h != nil)
sha1((uchar*)p+m, n, nil, h); sha1((uchar*)p + m, n, nil, h);
m += n; m += n;
p[m] = 0; p[m] = 0;
l = m; l = m;
if(n > 0) if (n > 0)
l -= UTFmax; l -= UTFmax;
cvttorunes(p, l, r, &nb, &nr, nulls); cvttorunes(p, l, r, &nb, &nr, nulls);
memmove(p, p+nb, m-nb); memmove(p, p + nb, m - nb);
m -= nb; m -= nb;
q1 += (*f)(arg, q1, r, nr); q1 += (*f)(arg, q1, r, nr);
} }
free(p); free(p);
free(r); free(r);
return q1-q0; return q1 - q0;
} }
uint uint bufload(Buffer* b, uint q0, int fd, int* nulls, DigestState* h) {
bufload(Buffer *b, uint q0, int fd, int *nulls, DigestState *h) if (q0 > b->nc)
{
if(q0 > b->nc)
error("internal error: bufload"); error("internal error: bufload");
return loadfile(fd, q0, nulls, bufloader, b, h); return loadfile(fd, q0, nulls, bufloader, b, h);
} }
void void bufread(Buffer* b, uint q0, Rune* s, uint n) {
bufread(Buffer *b, uint q0, Rune *s, uint n)
{
uint m; uint m;
if(!(q0<=b->nc && q0+n<=b->nc)) if (!(q0 <= b->nc && q0 + n <= b->nc))
error("bufread: internal error"); error("bufread: internal error");
while(n > 0){ while (n > 0) {
setcache(b, q0); setcache(b, q0);
m = min(n, b->cnc-(q0-b->cq)); m = min(n, b->cnc - (q0 - b->cq));
runemove(s, b->c+(q0-b->cq), m); runemove(s, b->c + (q0 - b->cq), m);
q0 += m; q0 += m;
s += m; s += m;
n -= m; n -= m;
} }
} }
void void bufreset(Buffer* b) {
bufreset(Buffer *b)
{
int i; int i;
b->nc = 0; b->nc = 0;
@ -308,13 +280,11 @@ bufreset(Buffer *b)
b->cdirty = 0; b->cdirty = 0;
b->cbi = 0; b->cbi = 0;
/* delete backwards to avoid n² behavior */ /* delete backwards to avoid n² behavior */
for(i=b->nbl-1; --i>=0; ) for (i = b->nbl - 1; --i >= 0;)
delblock(b, i); delblock(b, i);
} }
void void bufclose(Buffer* b) {
bufclose(Buffer *b)
{
bufreset(b); bufreset(b);
free(b->c); free(b->c);
b->c = nil; b->c = nil;

8
build.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
clang-format -i ./*.c
clang-format -i ./mail/*.c
mk
mv o.acme acme

433
cols.c
View file

@ -12,24 +12,21 @@
#include "dat.h" #include "dat.h"
#include "fns.h" #include "fns.h"
static Rune Lheader[] = { static Rune Lheader[] = {'N', 'e', 'w', ' ', 'C', 'u', 't', ' ', 'P', 'a',
'N', 'e', 'w', ' ', 's', 't', 'e', ' ', 'S', 'n', 'a', 'r', 'f', ' ',
'C', 'u', 't', ' ', 'S', 'o', 'r', 't', ' ', 'Z', 'e', 'r', 'o', 'x',
'P', 'a', 's', 't', 'e', ' ', ' ', 'D', 'e', 'l', 'c', 'o', 'l', ' ', 0};
'S', 'n', 'a', 'r', 'f', ' ',
'S', 'o', 'r', 't', ' ',
'Z', 'e', 'r', 'o', 'x', ' ',
'D', 'e', 'l', 'c', 'o', 'l', ' ',
0
};
void void colinit(Column* c, Rectangle r) {
colinit(Column *c, Rectangle r)
{
Rectangle r1; Rectangle r1;
Text *t; Text* t;
draw(screen, r, allocimage(display,Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
c->r = r; c->r = r;
c->w = nil; c->w = nil;
c->nw = 0; c->nw = 0;
@ -42,44 +39,47 @@ colinit(Column *c, Rectangle r)
t->what = Columntag; t->what = Columntag;
r1.min.y = r1.max.y; r1.min.y = r1.max.y;
r1.max.y += Border; r1.max.y += Border;
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r1,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
textinsert(t, 0, Lheader, 38, TRUE); textinsert(t, 0, Lheader, 38, TRUE);
textsetselect(t, t->file->b.nc, t->file->b.nc); textsetselect(t, t->file->b.nc, t->file->b.nc);
draw(screen, t->scrollr, colbutton, nil, colbutton->r.min); draw(screen, t->scrollr, colbutton, nil, colbutton->r.min);
c->safe = TRUE; c->safe = TRUE;
} }
Window* Window* coladd(Column* c, Window* w, Window* clone, int y) {
coladd(Column *c, Window *w, Window *clone, int y)
{
Rectangle r, r1; Rectangle r, r1;
Window *v; Window* v;
int i, j, minht, ymax, buggered; int i, j, minht, ymax, buggered;
v = nil; v = nil;
r = c->r; r = c->r;
r.min.y = c->tag.fr.r.max.y+Border; r.min.y = c->tag.fr.r.max.y + Border;
if(y<r.min.y && c->nw>0){ /* steal half of last window by default */ if (y < r.min.y && c->nw > 0) { /* steal half of last window by default */
v = c->w[c->nw-1]; v = c->w[c->nw - 1];
y = v->body.fr.r.min.y+Dy(v->body.fr.r)/2; y = v->body.fr.r.min.y + Dy(v->body.fr.r) / 2;
} }
/* look for window we'll land on */ /* look for window we'll land on */
for(i=0; i<c->nw; i++){ for (i = 0; i < c->nw; i++) {
v = c->w[i]; v = c->w[i];
if(y < v->r.max.y) if (y < v->r.max.y)
break; break;
} }
buggered = 0; buggered = 0;
if(c->nw > 0){ if (c->nw > 0) {
if(i < c->nw) if (i < c->nw)
i++; /* new window will go after v */ i++; /* new window will go after v */
/* /*
* if landing window (v) is too small, grow it first. * if landing window (v) is too small, grow it first.
*/ */
minht = v->tag.fr.font->height+Border+1; minht = v->tag.fr.font->height + Border + 1;
j = 0; j = 0;
while(!c->safe || v->body.fr.maxlines<=3 || Dy(v->body.all) <= minht){ while (!c->safe || v->body.fr.maxlines <= 3 || Dy(v->body.all) <= minht) {
if(++j > 10){ if (++j > 10) {
buggered = 1; /* too many windows in column */ buggered = 1; /* too many windows in column */
break; break;
} }
@ -91,19 +91,19 @@ coladd(Column *c, Window *w, Window *clone, int y)
*/ */
/* new window stops where next window begins */ /* new window stops where next window begins */
if(i < c->nw) if (i < c->nw)
ymax = c->w[i]->r.min.y-Border; ymax = c->w[i]->r.min.y - Border;
else else
ymax = c->r.max.y; ymax = c->r.max.y;
/* new window must start after v's tag ends */ /* new window must start after v's tag ends */
y = max(y, v->tagtop.max.y+Border); y = max(y, v->tagtop.max.y + Border);
/* new window must start early enough to end before ymax */ /* new window must start early enough to end before ymax */
y = min(y, ymax - minht); y = min(y, ymax - minht);
/* if y is too small, too many windows in column */ /* if y is too small, too many windows in column */
if(y < v->tagtop.max.y+Border) if (y < v->tagtop.max.y + Border)
buggered = 1; buggered = 1;
/* /*
@ -113,23 +113,32 @@ coladd(Column *c, Window *w, Window *clone, int y)
r.max.y = ymax; r.max.y = ymax;
draw(screen, r, textcols[BACK], nil, ZP); draw(screen, r, textcols[BACK], nil, ZP);
r1 = r; r1 = r;
y = min(y, ymax-(v->tag.fr.font->height*v->taglines+v->body.fr.font->height+Border+1)); y = min(
r1.max.y = min(y, v->body.fr.r.min.y+v->body.fr.nlines*v->body.fr.font->height); y,
ymax - (v->tag.fr.font->height * v->taglines + v->body.fr.font->height +
Border + 1));
r1.max.y =
min(y, v->body.fr.r.min.y + v->body.fr.nlines * v->body.fr.font->height);
r1.min.y = winresize(v, r1, FALSE, FALSE); r1.min.y = winresize(v, r1, FALSE, FALSE);
r1.max.y = r1.min.y+Border; r1.max.y = r1.min.y + Border;
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r1,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
/* /*
* leave r with w's coordinates * leave r with w's coordinates
*/ */
r.min.y = r1.max.y; r.min.y = r1.max.y;
} }
if(w == nil){ if (w == nil) {
w = emalloc(sizeof(Window)); w = emalloc(sizeof(Window));
w->col = c; w->col = c;
draw(screen, r, textcols[BACK], nil, ZP); draw(screen, r, textcols[BACK], nil, ZP);
wininit(w, clone, r); wininit(w, clone, r);
}else{ } else {
w->col = c; w->col = c;
winresize(w, r, FALSE, TRUE); winresize(w, r, FALSE, TRUE);
} }
@ -137,14 +146,14 @@ coladd(Column *c, Window *w, Window *clone, int y)
w->tag.row = c->row; w->tag.row = c->row;
w->body.col = c; w->body.col = c;
w->body.row = c->row; w->body.row = c->row;
c->w = realloc(c->w, (c->nw+1)*sizeof(Window*)); c->w = realloc(c->w, (c->nw + 1) * sizeof(Window*));
memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*)); memmove(c->w + i + 1, c->w + i, (c->nw - i) * sizeof(Window*));
c->nw++; c->nw++;
c->w[i] = w; c->w[i] = w;
c->safe = TRUE; c->safe = TRUE;
/* if there were too many windows, redraw the whole column */ /* if there were too many windows, redraw the whole column */
if(buggered) if (buggered)
colresize(c, c->r); colresize(c, c->r);
savemouse(w); savemouse(w);
@ -154,66 +163,67 @@ coladd(Column *c, Window *w, Window *clone, int y)
return w; return w;
} }
void void colclose(Column* c, Window* w, int dofree) {
colclose(Column *c, Window *w, int dofree)
{
Rectangle r; Rectangle r;
int i, didmouse, up; int i, didmouse, up;
/* w is locked */ /* w is locked */
if(!c->safe) if (!c->safe)
colgrow(c, w, 1); colgrow(c, w, 1);
for(i=0; i<c->nw; i++) for (i = 0; i < c->nw; i++)
if(c->w[i] == w) if (c->w[i] == w)
goto Found; goto Found;
error("can't find window"); error("can't find window");
Found: Found:
r = w->r; r = w->r;
w->tag.col = nil; w->tag.col = nil;
w->body.col = nil; w->body.col = nil;
w->col = nil; w->col = nil;
didmouse = restoremouse(w); didmouse = restoremouse(w);
if(dofree){ if (dofree) {
windelete(w); windelete(w);
winclose(w); winclose(w);
} }
c->nw--; c->nw--;
memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*)); memmove(c->w + i, c->w + i + 1, (c->nw - i) * sizeof(Window*));
c->w = realloc(c->w, c->nw*sizeof(Window*)); c->w = realloc(c->w, c->nw * sizeof(Window*));
if(c->nw == 0){ if (c->nw == 0) {
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
return; return;
} }
up = 0; up = 0;
if(i == c->nw){ /* extend last window down */ if (i == c->nw) { /* extend last window down */
w = c->w[i-1]; w = c->w[i - 1];
r.min.y = w->r.min.y; r.min.y = w->r.min.y;
r.max.y = c->r.max.y; r.max.y = c->r.max.y;
}else{ /* extend next window up */ } else { /* extend next window up */
up = 1; up = 1;
w = c->w[i]; w = c->w[i];
r.max.y = w->r.max.y; r.max.y = w->r.max.y;
} }
draw(screen, r, textcols[BACK], nil, ZP); draw(screen, r, textcols[BACK], nil, ZP);
if(c->safe) { if (c->safe) {
if(!didmouse && up) if (!didmouse && up)
w->showdel = TRUE; w->showdel = TRUE;
winresize(w, r, FALSE, TRUE); winresize(w, r, FALSE, TRUE);
if(!didmouse && up) if (!didmouse && up)
movetodel(w); movetodel(w);
} }
} }
void void colcloseall(Column* c) {
colcloseall(Column *c)
{
int i; int i;
Window *w; Window* w;
if(c == activecol) if (c == activecol)
activecol = nil; activecol = nil;
textclose(&c->tag); textclose(&c->tag);
for(i=0; i<c->nw; i++){ for (i = 0; i < c->nw; i++) {
w = c->w[i]; w = c->w[i];
winclose(w); winclose(w);
} }
@ -223,18 +233,14 @@ colcloseall(Column *c)
clearmouse(); clearmouse();
} }
void void colmousebut(Column* c) {
colmousebut(Column *c)
{
moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2)); moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2));
} }
void void colresize(Column* c, Rectangle r) {
colresize(Column *c, Rectangle r)
{
int i; int i;
Rectangle r1, r2; Rectangle r1, r2;
Window *w; Window* w;
clearmouse(); clearmouse();
r1 = r; r1 = r;
@ -243,33 +249,40 @@ colresize(Column *c, Rectangle r)
draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min); draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
r1.min.y = r1.max.y; r1.min.y = r1.max.y;
r1.max.y += Border; r1.max.y += Border;
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r1,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
r1.max.y = r.max.y; r1.max.y = r.max.y;
for(i=0; i<c->nw; i++){ for (i = 0; i < c->nw; i++) {
w = c->w[i]; w = c->w[i];
w->maxlines = 0; w->maxlines = 0;
if(i == c->nw-1) if (i == c->nw - 1)
r1.max.y = r.max.y; r1.max.y = r.max.y;
else{ else {
r1.max.y = r1.min.y; r1.max.y = r1.min.y;
if(Dy(c->r) != 0){ if (Dy(c->r) != 0) {
r1.max.y += (Dy(w->r)+Border)*Dy(r)/Dy(c->r); r1.max.y += (Dy(w->r) + Border) * Dy(r) / Dy(c->r);
} }
} }
r1.max.y = max(r1.max.y, r1.min.y + Border+font->height); r1.max.y = max(r1.max.y, r1.min.y + Border + font->height);
r2 = r1; r2 = r1;
r2.max.y = r2.min.y+Border; r2.max.y = r2.min.y + Border;
draw(screen, r2, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r2,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
r1.min.y = r2.max.y; r1.min.y = r2.max.y;
r1.min.y = winresize(w, r1, FALSE, i==c->nw-1); r1.min.y = winresize(w, r1, FALSE, i == c->nw - 1);
} }
c->r = r; c->r = r;
} }
static static int colcmp(const void* a, const void* b) {
int
colcmp(const void *a, const void *b)
{
Rune *r1, *r2; Rune *r1, *r2;
int i, nr1, nr2; int i, nr1, nr2;
@ -277,86 +290,87 @@ colcmp(const void *a, const void *b)
nr1 = (*(Window**)a)->body.file->nname; nr1 = (*(Window**)a)->body.file->nname;
r2 = (*(Window**)b)->body.file->name; r2 = (*(Window**)b)->body.file->name;
nr2 = (*(Window**)b)->body.file->nname; nr2 = (*(Window**)b)->body.file->nname;
for(i=0; i<nr1 && i<nr2; i++){ for (i = 0; i < nr1 && i < nr2; i++) {
if(*r1 != *r2) if (*r1 != *r2)
return *r1-*r2; return *r1 - *r2;
r1++; r1++;
r2++; r2++;
} }
return nr1-nr2; return nr1 - nr2;
} }
void void colsort(Column* c) {
colsort(Column *c)
{
int i, y; int i, y;
Rectangle r, r1, *rp; Rectangle r, r1, *rp;
Window **wp, *w; Window **wp, *w;
if(c->nw == 0) if (c->nw == 0)
return; return;
clearmouse(); clearmouse();
rp = emalloc(c->nw*sizeof(Rectangle)); rp = emalloc(c->nw * sizeof(Rectangle));
wp = emalloc(c->nw*sizeof(Window*)); wp = emalloc(c->nw * sizeof(Window*));
memmove(wp, c->w, c->nw*sizeof(Window*)); memmove(wp, c->w, c->nw * sizeof(Window*));
qsort(wp, c->nw, sizeof(Window*), colcmp); qsort(wp, c->nw, sizeof(Window*), colcmp);
for(i=0; i<c->nw; i++) for (i = 0; i < c->nw; i++)
rp[i] = wp[i]->r; rp[i] = wp[i]->r;
r = c->r; r = c->r;
r.min.y = c->tag.fr.r.max.y; r.min.y = c->tag.fr.r.max.y;
draw(screen, r, textcols[BACK], nil, ZP); draw(screen, r, textcols[BACK], nil, ZP);
y = r.min.y; y = r.min.y;
for(i=0; i<c->nw; i++){ for (i = 0; i < c->nw; i++) {
w = wp[i]; w = wp[i];
r.min.y = y; r.min.y = y;
if(i == c->nw-1) if (i == c->nw - 1)
r.max.y = c->r.max.y; r.max.y = c->r.max.y;
else else
r.max.y = r.min.y+Dy(w->r)+Border; r.max.y = r.min.y + Dy(w->r) + Border;
r1 = r; r1 = r;
r1.max.y = r1.min.y+Border; r1.max.y = r1.min.y + Border;
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r1,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
r.min.y = r1.max.y; r.min.y = r1.max.y;
y = winresize(w, r, FALSE, i==c->nw-1); y = winresize(w, r, FALSE, i == c->nw - 1);
} }
free(rp); free(rp);
free(c->w); free(c->w);
c->w = wp; c->w = wp;
} }
void void colgrow(Column* c, Window* w, int but) {
colgrow(Column *c, Window *w, int but)
{
Rectangle r, cr; Rectangle r, cr;
int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h; int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h;
Window *v; Window* v;
for(i=0; i<c->nw; i++) for (i = 0; i < c->nw; i++)
if(c->w[i] == w) if (c->w[i] == w)
goto Found; goto Found;
error("can't find window"); error("can't find window");
Found: Found:
cr = c->r; cr = c->r;
if(but < 0){ /* make sure window fills its own space properly */ if (but < 0) { /* make sure window fills its own space properly */
r = w->r; r = w->r;
if(i==c->nw-1 || c->safe==FALSE) if (i == c->nw - 1 || c->safe == FALSE)
r.max.y = cr.max.y; r.max.y = cr.max.y;
else else
r.max.y = c->w[i+1]->r.min.y - Border; r.max.y = c->w[i + 1]->r.min.y - Border;
winresize(w, r, FALSE, TRUE); winresize(w, r, FALSE, TRUE);
return; return;
} }
cr.min.y = c->w[0]->r.min.y; cr.min.y = c->w[0]->r.min.y;
if(but == 3){ /* full size */ if (but == 3) { /* full size */
if(i != 0){ if (i != 0) {
v = c->w[0]; v = c->w[0];
c->w[0] = w; c->w[0] = w;
c->w[i] = v; c->w[i] = v;
} }
draw(screen, cr, textcols[BACK], nil, ZP); draw(screen, cr, textcols[BACK], nil, ZP);
winresize(w, cr, FALSE, TRUE); winresize(w, cr, FALSE, TRUE);
for(i=1; i<c->nw; i++) for (i = 1; i < c->nw; i++)
c->w[i]->body.fr.maxlines = 0; c->w[i]->body.fr.maxlines = 0;
c->safe = FALSE; c->safe = FALSE;
return; return;
@ -366,64 +380,69 @@ colgrow(Column *c, Window *w, int but)
nl = emalloc(c->nw * sizeof(int)); nl = emalloc(c->nw * sizeof(int));
ny = emalloc(c->nw * sizeof(int)); ny = emalloc(c->nw * sizeof(int));
tot = 0; tot = 0;
for(j=0; j<c->nw; j++){ for (j = 0; j < c->nw; j++) {
l = c->w[j]->taglines-1 + c->w[j]->body.fr.maxlines; l = c->w[j]->taglines - 1 + c->w[j]->body.fr.maxlines;
nl[j] = l; nl[j] = l;
tot += l; tot += l;
} }
/* approximate new #lines for this window */ /* approximate new #lines for this window */
if(but == 2){ /* as big as can be */ if (but == 2) { /* as big as can be */
memset(nl, 0, c->nw * sizeof(int)); memset(nl, 0, c->nw * sizeof(int));
goto Pack; goto Pack;
} }
nnl = min(onl + max(min(5, w->taglines-1+w->maxlines), onl/2), tot); nnl = min(onl + max(min(5, w->taglines - 1 + w->maxlines), onl / 2), tot);
if(nnl < w->taglines-1+w->maxlines) if (nnl < w->taglines - 1 + w->maxlines)
nnl = (w->taglines-1+w->maxlines + nnl)/2; nnl = (w->taglines - 1 + w->maxlines + nnl) / 2;
if(nnl == 0) if (nnl == 0)
nnl = 2; nnl = 2;
dnl = nnl - onl; dnl = nnl - onl;
/* compute new #lines for each window */ /* compute new #lines for each window */
for(k=1; k<c->nw; k++){ for (k = 1; k < c->nw; k++) {
/* prune from later window */ /* prune from later window */
j = i+k; j = i + k;
if(j<c->nw && nl[j]){ if (j < c->nw && nl[j]) {
l = min(dnl, max(1, nl[j]/2)); l = min(dnl, max(1, nl[j] / 2));
nl[j] -= l; nl[j] -= l;
nl[i] += l; nl[i] += l;
dnl -= l; dnl -= l;
} }
/* prune from earlier window */ /* prune from earlier window */
j = i-k; j = i - k;
if(j>=0 && nl[j]){ if (j >= 0 && nl[j]) {
l = min(dnl, max(1, nl[j]/2)); l = min(dnl, max(1, nl[j] / 2));
nl[j] -= l; nl[j] -= l;
nl[i] += l; nl[i] += l;
dnl -= l; dnl -= l;
} }
} }
Pack: Pack:
/* pack everyone above */ /* pack everyone above */
y1 = cr.min.y; y1 = cr.min.y;
for(j=0; j<i; j++){ for (j = 0; j < i; j++) {
v = c->w[j]; v = c->w[j];
r = v->r; r = v->r;
r.min.y = y1; r.min.y = y1;
r.max.y = y1+Dy(v->tagtop); r.max.y = y1 + Dy(v->tagtop);
if(nl[j]) if (nl[j])
r.max.y += 1 + nl[j]*v->body.fr.font->height; r.max.y += 1 + nl[j] * v->body.fr.font->height;
r.min.y = winresize(v, r, c->safe, FALSE); r.min.y = winresize(v, r, c->safe, FALSE);
r.max.y += Border; r.max.y += Border;
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
y1 = r.max.y; y1 = r.max.y;
} }
/* scan to see new size of everyone below */ /* scan to see new size of everyone below */
y2 = c->r.max.y; y2 = c->r.max.y;
for(j=c->nw-1; j>i; j--){ for (j = c->nw - 1; j > i; j--) {
v = c->w[j]; v = c->w[j];
r = v->r; r = v->r;
r.min.y = y2-Dy(v->tagtop); r.min.y = y2 - Dy(v->tagtop);
if(nl[j]) if (nl[j])
r.min.y -= 1 + nl[j]*v->body.fr.font->height; r.min.y -= 1 + nl[j] * v->body.fr.font->height;
r.min.y -= Border; r.min.y -= Border;
ny[j] = r.min.y; ny[j] = r.min.y;
y2 = r.min.y; y2 = r.min.y;
@ -433,31 +452,41 @@ colgrow(Column *c, Window *w, int but)
r.min.y = y1; r.min.y = y1;
r.max.y = y2; r.max.y = y2;
h = w->body.fr.font->height; h = w->body.fr.font->height;
if(Dy(r) < Dy(w->tagtop)+1+h+Border) if (Dy(r) < Dy(w->tagtop) + 1 + h + Border)
r.max.y = r.min.y + Dy(w->tagtop)+1+h+Border; r.max.y = r.min.y + Dy(w->tagtop) + 1 + h + Border;
/* draw window */ /* draw window */
r.max.y = winresize(w, r, c->safe, TRUE); r.max.y = winresize(w, r, c->safe, TRUE);
if(i < c->nw-1){ if (i < c->nw - 1) {
r.min.y = r.max.y; r.min.y = r.max.y;
r.max.y += Border; r.max.y += Border;
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
for(j=i+1; j<c->nw; j++) screen,
ny[j] -= (y2-r.max.y); r,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
for (j = i + 1; j < c->nw; j++)
ny[j] -= (y2 - r.max.y);
} }
/* pack everyone below */ /* pack everyone below */
y1 = r.max.y; y1 = r.max.y;
for(j=i+1; j<c->nw; j++){ for (j = i + 1; j < c->nw; j++) {
v = c->w[j]; v = c->w[j];
r = v->r; r = v->r;
r.min.y = y1; r.min.y = y1;
r.max.y = y1+Dy(v->tagtop); r.max.y = y1 + Dy(v->tagtop);
if(nl[j]) if (nl[j])
r.max.y += 1 + nl[j]*v->body.fr.font->height; r.max.y += 1 + nl[j] * v->body.fr.font->height;
y1 = winresize(v, r, c->safe, j==c->nw-1); y1 = winresize(v, r, c->safe, j == c->nw - 1);
if(j < c->nw-1){ /* no border on last window */ if (j < c->nw - 1) { /* no border on last window */
r.min.y = y1; r.min.y = y1;
r.max.y += Border; r.max.y += Border;
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
y1 = r.max.y; y1 = r.max.y;
} }
} }
@ -467,106 +496,108 @@ colgrow(Column *c, Window *w, int but)
winmousebut(w); winmousebut(w);
} }
void void coldragwin(Column* c, Window* w, int but) {
coldragwin(Column *c, Window *w, int but)
{
Rectangle r; Rectangle r;
int i, b; int i, b;
Point p, op; Point p, op;
Window *v; Window* v;
Column *nc; Column* nc;
clearmouse(); clearmouse();
setcursor2(mousectl, &boxcursor, &boxcursor2); setcursor2(mousectl, &boxcursor, &boxcursor2);
b = mouse->buttons; b = mouse->buttons;
op = mouse->xy; op = mouse->xy;
while(mouse->buttons == b) while (mouse->buttons == b)
readmouse(mousectl); readmouse(mousectl);
setcursor(mousectl, nil); setcursor(mousectl, nil);
if(mouse->buttons){ if (mouse->buttons) {
while(mouse->buttons) while (mouse->buttons)
readmouse(mousectl); readmouse(mousectl);
return; return;
} }
for(i=0; i<c->nw; i++) for (i = 0; i < c->nw; i++)
if(c->w[i] == w) if (c->w[i] == w)
goto Found; goto Found;
error("can't find window"); error("can't find window");
Found: Found:
if(w->tagexpand) /* force recomputation of window tag size */ if (w->tagexpand) /* force recomputation of window tag size */
w->taglines = 1; w->taglines = 1;
p = mouse->xy; p = mouse->xy;
if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){ if (abs(p.x - op.x) < 5 && abs(p.y - op.y) < 5) {
colgrow(c, w, but); colgrow(c, w, but);
winmousebut(w); winmousebut(w);
return; return;
} }
/* is it a flick to the right? */ /* is it a flick to the right? */
if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c) if (abs(p.y - op.y) < 10 && p.x > op.x + 30 && rowwhichcol(c->row, p) == c)
p.x = op.x+Dx(w->r); /* yes: toss to next column */ p.x = op.x + Dx(w->r); /* yes: toss to next column */
nc = rowwhichcol(c->row, p); nc = rowwhichcol(c->row, p);
if(nc!=nil && nc!=c){ if (nc != nil && nc != c) {
colclose(c, w, FALSE); colclose(c, w, FALSE);
coladd(nc, w, nil, p.y); coladd(nc, w, nil, p.y);
winmousebut(w); winmousebut(w);
return; return;
} }
if(i==0 && c->nw==1) if (i == 0 && c->nw == 1)
return; /* can't do it */ return; /* can't do it */
if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max.y) if (
|| (i==0 && p.y>w->r.max.y)){ (i > 0 && p.y < c->w[i - 1]->r.min.y) ||
(i < c->nw - 1 && p.y > w->r.max.y) || (i == 0 && p.y > w->r.max.y)) {
/* shuffle */ /* shuffle */
colclose(c, w, FALSE); colclose(c, w, FALSE);
coladd(c, w, nil, p.y); coladd(c, w, nil, p.y);
winmousebut(w); winmousebut(w);
return; return;
} }
if(i == 0) if (i == 0)
return; return;
v = c->w[i-1]; v = c->w[i - 1];
if(p.y < v->tagtop.max.y) if (p.y < v->tagtop.max.y)
p.y = v->tagtop.max.y; p.y = v->tagtop.max.y;
if(p.y > w->r.max.y-Dy(w->tagtop)-Border) if (p.y > w->r.max.y - Dy(w->tagtop) - Border)
p.y = w->r.max.y-Dy(w->tagtop)-Border; p.y = w->r.max.y - Dy(w->tagtop) - Border;
r = v->r; r = v->r;
r.max.y = p.y; r.max.y = p.y;
if(r.max.y > v->body.fr.r.min.y){ if (r.max.y > v->body.fr.r.min.y) {
r.max.y -= (r.max.y-v->body.fr.r.min.y)%v->body.fr.font->height; r.max.y -= (r.max.y - v->body.fr.r.min.y) % v->body.fr.font->height;
if(v->body.fr.r.min.y == v->body.fr.r.max.y) if (v->body.fr.r.min.y == v->body.fr.r.max.y)
r.max.y++; r.max.y++;
} }
r.min.y = winresize(v, r, c->safe, FALSE); r.min.y = winresize(v, r, c->safe, FALSE);
r.max.y = r.min.y+Border; r.max.y = r.min.y + Border;
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP); draw(
screen,
r,
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
nil,
ZP);
r.min.y = r.max.y; r.min.y = r.max.y;
if(i == c->nw-1) if (i == c->nw - 1)
r.max.y = c->r.max.y; r.max.y = c->r.max.y;
else else
r.max.y = c->w[i+1]->r.min.y-Border; r.max.y = c->w[i + 1]->r.min.y - Border;
winresize(w, r, c->safe, TRUE); winresize(w, r, c->safe, TRUE);
c->safe = TRUE; c->safe = TRUE;
winmousebut(w); winmousebut(w);
} }
Text* Text* colwhich(Column* c, Point p) {
colwhich(Column *c, Point p)
{
int i; int i;
Window *w; Window* w;
if(!ptinrect(p, c->r)) if (!ptinrect(p, c->r))
return nil; return nil;
if(ptinrect(p, c->tag.all)) if (ptinrect(p, c->tag.all))
return &c->tag; return &c->tag;
for(i=0; i<c->nw; i++){ for (i = 0; i < c->nw; i++) {
w = c->w[i]; w = c->w[i];
if(ptinrect(p, w->r)){ if (ptinrect(p, w->r)) {
if(ptinrect(p, w->tagtop) || ptinrect(p, w->tag.all)) if (ptinrect(p, w->tagtop) || ptinrect(p, w->tag.all))
return &w->tag; return &w->tag;
/* exclude partial line at bottom */ /* exclude partial line at bottom */
if(p.x >= w->body.scrollr.max.x && p.y >= w->body.fr.r.max.y) if (p.x >= w->body.scrollr.max.x && p.y >= w->body.fr.r.max.y)
return nil; return nil;
return &w->body; return &w->body;
} }
@ -574,13 +605,11 @@ colwhich(Column *c, Point p)
return nil; return nil;
} }
int int colclean(Column* c) {
colclean(Column *c)
{
int i, clean; int i, clean;
clean = TRUE; clean = TRUE;
for(i=0; i<c->nw; i++) for (i = 0; i < c->nw; i++)
clean &= winclean(c->w[i], TRUE); clean &= winclean(c->w[i], TRUE);
return clean; return clean;
} }

79
disk.c
View file

@ -12,78 +12,69 @@
#include "dat.h" #include "dat.h"
#include "fns.h" #include "fns.h"
static Block *blist; static Block* blist;
int int tempfile(void) {
tempfile(void)
{
char buf[128]; char buf[128];
int i, fd; int i, fd;
snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser()); snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser());
for(i='A'; i<='Z'; i++){ for (i = 'A'; i <= 'Z'; i++) {
buf[5] = i; buf[5] = i;
if(access(buf, AEXIST) == 0) if (access(buf, AEXIST) == 0)
continue; continue;
fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600); fd = create(buf, ORDWR | ORCLOSE | OCEXEC, 0600);
if(fd >= 0) if (fd >= 0)
return fd; return fd;
} }
return -1; return -1;
} }
Disk* Disk* diskinit() {
diskinit() Disk* d;
{
Disk *d;
d = emalloc(sizeof(Disk)); d = emalloc(sizeof(Disk));
d->fd = tempfile(); d->fd = tempfile();
if(d->fd < 0){ if (d->fd < 0) {
fprint(2, "acme: can't create temp file: %r\n"); fprint(2, "acme: can't create temp file: %r\n");
threadexitsall("diskinit"); threadexitsall("diskinit");
} }
return d; return d;
} }
static static uint ntosize(uint n, uint* ip) {
uint
ntosize(uint n, uint *ip)
{
uint size; uint size;
if(n > Maxblock) if (n > Maxblock)
error("internal error: ntosize"); error("internal error: ntosize");
size = n; size = n;
if(size & (Blockincr-1)) if (size & (Blockincr - 1))
size += Blockincr - (size & (Blockincr-1)); size += Blockincr - (size & (Blockincr - 1));
/* last bucket holds blocks of exactly Maxblock */ /* last bucket holds blocks of exactly Maxblock */
if(ip) if (ip)
*ip = size/Blockincr; *ip = size / Blockincr;
return size * sizeof(Rune); return size * sizeof(Rune);
} }
Block* Block* disknewblock(Disk* d, uint n) {
disknewblock(Disk *d, uint n)
{
uint i, j, size; uint i, j, size;
Block *b; Block* b;
size = ntosize(n, &i); size = ntosize(n, &i);
b = d->free[i]; b = d->free[i];
if(b) if (b)
d->free[i] = b->u.next; d->free[i] = b->u.next;
else{ else {
/* allocate in chunks to reduce malloc overhead */ /* allocate in chunks to reduce malloc overhead */
if(blist == nil){ if (blist == nil) {
blist = emalloc(100*sizeof(Block)); blist = emalloc(100 * sizeof(Block));
for(j=0; j<100-1; j++) for (j = 0; j < 100 - 1; j++)
blist[j].u.next = &blist[j+1]; blist[j].u.next = &blist[j + 1];
} }
b = blist; b = blist;
blist = b->u.next; blist = b->u.next;
b->addr = d->addr; b->addr = d->addr;
if(d->addr+size < d->addr){ if (d->addr + size < d->addr) {
error("temp file overflow"); error("temp file overflow");
} }
d->addr += size; d->addr += size;
@ -92,9 +83,7 @@ disknewblock(Disk *d, uint n)
return b; return b;
} }
void void diskrelease(Disk* d, Block* b) {
diskrelease(Disk *d, Block *b)
{
uint i; uint i;
ntosize(b->u.n, &i); ntosize(b->u.n, &i);
@ -102,32 +91,28 @@ diskrelease(Disk *d, Block *b)
d->free[i] = b; d->free[i] = b;
} }
void void diskwrite(Disk* d, Block** bp, Rune* r, uint n) {
diskwrite(Disk *d, Block **bp, Rune *r, uint n)
{
int size, nsize; int size, nsize;
Block *b; Block* b;
b = *bp; b = *bp;
size = ntosize(b->u.n, nil); size = ntosize(b->u.n, nil);
nsize = ntosize(n, nil); nsize = ntosize(n, nil);
if(size != nsize){ if (size != nsize) {
diskrelease(d, b); diskrelease(d, b);
b = disknewblock(d, n); b = disknewblock(d, n);
*bp = b; *bp = b;
} }
if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) if (pwrite(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
error("write error to temp file"); error("write error to temp file");
b->u.n = n; b->u.n = n;
} }
void void diskread(Disk* d, Block* b, Rune* r, uint n) {
diskread(Disk *d, Block *b, Rune *r, uint n) if (n > b->u.n)
{
if(n > b->u.n)
error("internal error: diskread"); error("internal error: diskread");
ntosize(b->u.n, nil); ntosize(b->u.n, nil);
if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) if (pread(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
error("read error from temp file"); error("read error from temp file");
} }

878
ecmd.c

File diff suppressed because it is too large Load diff

710
edit.c

File diff suppressed because it is too large Load diff

211
elog.c
View file

@ -27,65 +27,52 @@ static int warned = FALSE;
*/ */
typedef struct Buflog Buflog; typedef struct Buflog Buflog;
struct Buflog struct Buflog {
{
short type; /* Replace, Filename */ short type; /* Replace, Filename */
uint q0; /* location of change (unused in f) */ uint q0; /* location of change (unused in f) */
uint nd; /* # runes to delete */ uint nd; /* # runes to delete */
uint nr; /* # runes in string or file name */ uint nr; /* # runes in string or file name */
}; };
enum enum { Buflogsize = sizeof(Buflog) / sizeof(Rune) };
{
Buflogsize = sizeof(Buflog)/sizeof(Rune)
};
/* /*
* Minstring shouldn't be very big or we will do lots of I/O for small changes. * Minstring shouldn't be very big or we will do lots of I/O for small changes.
* Maxstring is RBUFSIZE so we can fbufalloc() once and not realloc elog.r. * Maxstring is RBUFSIZE so we can fbufalloc() once and not realloc elog.r.
*/ */
enum enum {
{
Minstring = 16, /* distance beneath which we merge changes */ Minstring = 16, /* distance beneath which we merge changes */
Maxstring = RBUFSIZE /* maximum length of change we will merge into one */ Maxstring = RBUFSIZE /* maximum length of change we will merge into one */
}; };
void void eloginit(File* f) {
eloginit(File *f) if (f->elog.type != Empty)
{
if(f->elog.type != Empty)
return; return;
f->elog.type = Null; f->elog.type = Null;
if(f->elogbuf == nil) if (f->elogbuf == nil)
f->elogbuf = emalloc(sizeof(Buffer)); f->elogbuf = emalloc(sizeof(Buffer));
if(f->elog.r == nil) if (f->elog.r == nil)
f->elog.r = fbufalloc(); f->elog.r = fbufalloc();
bufreset(f->elogbuf); bufreset(f->elogbuf);
} }
void void elogclose(File* f) {
elogclose(File *f) if (f->elogbuf) {
{
if(f->elogbuf){
bufclose(f->elogbuf); bufclose(f->elogbuf);
free(f->elogbuf); free(f->elogbuf);
f->elogbuf = nil; f->elogbuf = nil;
} }
} }
void void elogreset(File* f) {
elogreset(File *f)
{
f->elog.type = Null; f->elog.type = Null;
f->elog.nd = 0; f->elog.nd = 0;
f->elog.nr = 0; f->elog.nr = 0;
} }
void void elogterm(File* f) {
elogterm(File *f)
{
elogreset(f); elogreset(f);
if(f->elogbuf) if (f->elogbuf)
bufreset(f->elogbuf); bufreset(f->elogbuf);
f->elog.type = Empty; f->elog.type = Empty;
fbuffree(f->elog.r); fbuffree(f->elog.r);
@ -93,16 +80,14 @@ elogterm(File *f)
warned = FALSE; warned = FALSE;
} }
void void elogflush(File* f) {
elogflush(File *f)
{
Buflog b; Buflog b;
b.type = f->elog.type; b.type = f->elog.type;
b.q0 = f->elog.q0; b.q0 = f->elog.q0;
b.nd = f->elog.nd; b.nd = f->elog.nd;
b.nr = f->elog.nr; b.nr = f->elog.nr;
switch(f->elog.type){ switch (f->elog.type) {
default: default:
warning(nil, "unknown elog type 0x%ux\n", f->elog.type); warning(nil, "unknown elog type 0x%ux\n", f->elog.type);
break; break;
@ -110,7 +95,7 @@ elogflush(File *f)
break; break;
case Insert: case Insert:
case Replace: case Replace:
if(f->elog.nr > 0) if (f->elog.nr > 0)
bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr); bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr);
/* fall through */ /* fall through */
case Delete: case Delete:
@ -120,29 +105,27 @@ elogflush(File *f)
elogreset(f); elogreset(f);
} }
void void elogreplace(File* f, int q0, int q1, Rune* r, int nr) {
elogreplace(File *f, int q0, int q1, Rune *r, int nr)
{
uint gap; uint gap;
if(q0==q1 && nr==0) if (q0 == q1 && nr == 0)
return; return;
eloginit(f); eloginit(f);
if(f->elog.type!=Null && q0<f->elog.q0){ if (f->elog.type != Null && q0 < f->elog.q0) {
if(warned++ == 0) if (warned++ == 0)
warning(nil, Wsequence); warning(nil, Wsequence);
elogflush(f); elogflush(f);
} }
/* try to merge with previous */ /* try to merge with previous */
gap = q0 - (f->elog.q0+f->elog.nd); /* gap between previous and this */ gap = q0 - (f->elog.q0 + f->elog.nd); /* gap between previous and this */
if(f->elog.type==Replace && f->elog.nr+gap+nr<Maxstring){ if (f->elog.type == Replace && f->elog.nr + gap + nr < Maxstring) {
if(gap < Minstring){ if (gap < Minstring) {
if(gap > 0){ if (gap > 0) {
bufread(&f->b, f->elog.q0+f->elog.nd, f->elog.r+f->elog.nr, gap); bufread(&f->b, f->elog.q0 + f->elog.nd, f->elog.r + f->elog.nr, gap);
f->elog.nr += gap; f->elog.nr += gap;
} }
f->elog.nd += gap + q1-q0; f->elog.nd += gap + q1 - q0;
runemove(f->elog.r+f->elog.nr, r, nr); runemove(f->elog.r + f->elog.nr, r, nr);
f->elog.nr += nr; f->elog.nr += nr;
return; return;
} }
@ -150,38 +133,37 @@ elogreplace(File *f, int q0, int q1, Rune *r, int nr)
elogflush(f); elogflush(f);
f->elog.type = Replace; f->elog.type = Replace;
f->elog.q0 = q0; f->elog.q0 = q0;
f->elog.nd = q1-q0; f->elog.nd = q1 - q0;
f->elog.nr = nr; f->elog.nr = nr;
if(nr > RBUFSIZE) if (nr > RBUFSIZE)
editerror("internal error: replacement string too large(%d)", nr); editerror("internal error: replacement string too large(%d)", nr);
runemove(f->elog.r, r, nr); runemove(f->elog.r, r, nr);
} }
void void eloginsert(File* f, int q0, Rune* r, int nr) {
eloginsert(File *f, int q0, Rune *r, int nr)
{
int n; int n;
if(nr == 0) if (nr == 0)
return; return;
eloginit(f); eloginit(f);
if(f->elog.type!=Null && q0<f->elog.q0){ if (f->elog.type != Null && q0 < f->elog.q0) {
if(warned++ == 0) if (warned++ == 0)
warning(nil, Wsequence); warning(nil, Wsequence);
elogflush(f); elogflush(f);
} }
/* try to merge with previous */ /* try to merge with previous */
if(f->elog.type==Insert && q0==f->elog.q0 && f->elog.nr+nr<Maxstring){ if (
runemove(f->elog.r+f->elog.nr, r, nr); f->elog.type == Insert && q0 == f->elog.q0 && f->elog.nr + nr < Maxstring) {
runemove(f->elog.r + f->elog.nr, r, nr);
f->elog.nr += nr; f->elog.nr += nr;
return; return;
} }
while(nr > 0){ while (nr > 0) {
elogflush(f); elogflush(f);
f->elog.type = Insert; f->elog.type = Insert;
f->elog.q0 = q0; f->elog.q0 = q0;
n = nr; n = nr;
if(n > RBUFSIZE) if (n > RBUFSIZE)
n = RBUFSIZE; n = RBUFSIZE;
f->elog.nr = n; f->elog.nr = n;
runemove(f->elog.r, r, n); runemove(f->elog.r, r, n);
@ -190,38 +172,34 @@ eloginsert(File *f, int q0, Rune *r, int nr)
} }
} }
void void elogdelete(File* f, int q0, int q1) {
elogdelete(File *f, int q0, int q1) if (q0 == q1)
{
if(q0 == q1)
return; return;
eloginit(f); eloginit(f);
if(f->elog.type!=Null && q0<f->elog.q0+f->elog.nd){ if (f->elog.type != Null && q0 < f->elog.q0 + f->elog.nd) {
if(warned++ == 0) if (warned++ == 0)
warning(nil, Wsequence); warning(nil, Wsequence);
elogflush(f); elogflush(f);
} }
/* try to merge with previous */ /* try to merge with previous */
if(f->elog.type==Delete && f->elog.q0+f->elog.nd==q0){ if (f->elog.type == Delete && f->elog.q0 + f->elog.nd == q0) {
f->elog.nd += q1-q0; f->elog.nd += q1 - q0;
return; return;
} }
elogflush(f); elogflush(f);
f->elog.type = Delete; f->elog.type = Delete;
f->elog.q0 = q0; f->elog.q0 = q0;
f->elog.nd = q1-q0; f->elog.nd = q1 - q0;
} }
#define tracelog 0 #define tracelog 0
void void elogapply(File* f) {
elogapply(File *f)
{
Buflog b; Buflog b;
Rune *buf; Rune* buf;
uint i, n, up, mod; uint i, n, up, mod;
uint tq0, tq1; uint tq0, tq1;
Buffer *log; Buffer* log;
Text *t; Text* t;
int owner; int owner;
elogflush(f); elogflush(f);
@ -232,19 +210,19 @@ elogapply(File *f)
mod = FALSE; mod = FALSE;
owner = 0; owner = 0;
if(t->w){ if (t->w) {
owner = t->w->owner; owner = t->w->owner;
if(owner == 0) if (owner == 0)
t->w->owner = 'E'; t->w->owner = 'E';
} }
/* /*
* The edit commands have already updated the selection in t->q0, t->q1, * The edit commands have already updated the selection in t->q0, t->q1,
* but using coordinates relative to the unmodified buffer. As we apply the log, * but using coordinates relative to the unmodified buffer. As we apply the
* we have to update the coordinates to be relative to the modified buffer. * log, we have to update the coordinates to be relative to the modified
* Textinsert and textdelete will do this for us; our only work is to apply the * buffer. Textinsert and textdelete will do this for us; our only work is to
* convention that an insertion at t->q0==t->q1 is intended to select the * apply the convention that an insertion at t->q0==t->q1 is intended to
* inserted text. * select the inserted text.
*/ */
/* /*
@ -254,71 +232,86 @@ elogapply(File *f)
* keep things in range. * keep things in range.
*/ */
while(log->nc > 0){ while (log->nc > 0) {
up = log->nc-Buflogsize; up = log->nc - Buflogsize;
bufread(log, up, (Rune*)&b, Buflogsize); bufread(log, up, (Rune*)&b, Buflogsize);
switch(b.type){ switch (b.type) {
default: default:
fprint(2, "elogapply: 0x%ux\n", b.type); fprint(2, "elogapply: 0x%ux\n", b.type);
abort(); abort();
break; break;
case Replace: case Replace:
if(tracelog) if (tracelog)
warning(nil, "elog replace %d %d (%d %d)\n", warning(
b.q0, b.q0+b.nd, t->q0, t->q1); nil,
if(!mod){ "elog replace %d %d (%d %d)\n",
b.q0,
b.q0 + b.nd,
t->q0,
t->q1);
if (!mod) {
mod = TRUE; mod = TRUE;
filemark(f); filemark(f);
} }
textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1); textconstrain(t, b.q0, b.q0 + b.nd, &tq0, &tq1);
textdelete(t, tq0, tq1, TRUE); textdelete(t, tq0, tq1, TRUE);
up -= b.nr; up -= b.nr;
for(i=0; i<b.nr; i+=n){ for (i = 0; i < b.nr; i += n) {
n = b.nr - i; n = b.nr - i;
if(n > RBUFSIZE) if (n > RBUFSIZE)
n = RBUFSIZE; n = RBUFSIZE;
bufread(log, up+i, buf, n); bufread(log, up + i, buf, n);
textinsert(t, tq0+i, buf, n, TRUE); textinsert(t, tq0 + i, buf, n, TRUE);
} }
if(t->q0 == b.q0 && t->q1 == b.q0) if (t->q0 == b.q0 && t->q1 == b.q0)
t->q1 += b.nr; t->q1 += b.nr;
break; break;
case Delete: case Delete:
if(tracelog) if (tracelog)
warning(nil, "elog delete %d %d (%d %d)\n", warning(
b.q0, b.q0+b.nd, t->q0, t->q1); nil,
if(!mod){ "elog delete %d %d (%d %d)\n",
b.q0,
b.q0 + b.nd,
t->q0,
t->q1);
if (!mod) {
mod = TRUE; mod = TRUE;
filemark(f); filemark(f);
} }
textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1); textconstrain(t, b.q0, b.q0 + b.nd, &tq0, &tq1);
textdelete(t, tq0, tq1, TRUE); textdelete(t, tq0, tq1, TRUE);
break; break;
case Insert: case Insert:
if(tracelog) if (tracelog)
warning(nil, "elog insert %d %d (%d %d)\n", warning(
b.q0, b.q0+b.nr, t->q0, t->q1); nil,
if(!mod){ "elog insert %d %d (%d %d)\n",
b.q0,
b.q0 + b.nr,
t->q0,
t->q1);
if (!mod) {
mod = TRUE; mod = TRUE;
filemark(f); filemark(f);
} }
textconstrain(t, b.q0, b.q0, &tq0, &tq1); textconstrain(t, b.q0, b.q0, &tq0, &tq1);
up -= b.nr; up -= b.nr;
for(i=0; i<b.nr; i+=n){ for (i = 0; i < b.nr; i += n) {
n = b.nr - i; n = b.nr - i;
if(n > RBUFSIZE) if (n > RBUFSIZE)
n = RBUFSIZE; n = RBUFSIZE;
bufread(log, up+i, buf, n); bufread(log, up + i, buf, n);
textinsert(t, tq0+i, buf, n, TRUE); textinsert(t, tq0 + i, buf, n, TRUE);
} }
if(t->q0 == b.q0 && t->q1 == b.q0) if (t->q0 == b.q0 && t->q1 == b.q0)
t->q1 += b.nr; t->q1 += b.nr;
break; break;
/* case Filename: /* case Filename:
f->seq = u.seq; f->seq = u.seq;
fileunsetname(f, epsilon); fileunsetname(f, epsilon);
f->mod = u.mod; f->mod = u.mod;
@ -331,7 +324,7 @@ elogapply(File *f)
bufread(delta, up, f->name, u.n); bufread(delta, up, f->name, u.n);
f->nname = u.n; f->nname = u.n;
break; break;
*/ */
} }
bufdelete(log, up, log->nc); bufdelete(log, up, log->nc);
} }
@ -342,13 +335,13 @@ elogapply(File *f)
* Bad addresses will cause bufload to crash, so double check. * Bad addresses will cause bufload to crash, so double check.
* If changes were out of order, we expect problems so don't complain further. * If changes were out of order, we expect problems so don't complain further.
*/ */
if(t->q0 > f->b.nc || t->q1 > f->b.nc || t->q0 > t->q1){ if (t->q0 > f->b.nc || t->q1 > f->b.nc || t->q0 > t->q1) {
if(!warned) if (!warned)
warning(nil, "elogapply: can't happen %d %d %d\n", t->q0, t->q1, f->b.nc); warning(nil, "elogapply: can't happen %d %d %d\n", t->q0, t->q1, f->b.nc);
t->q1 = min(t->q1, f->b.nc); t->q1 = min(t->q1, f->b.nc);
t->q0 = min(t->q0, t->q1); t->q0 = min(t->q0, t->q1);
} }
if(t->w) if (t->w)
t->w->owner = owner; t->w->owner = owner;
} }

1128
exec.c

File diff suppressed because it is too large Load diff

165
file.c
View file

@ -23,8 +23,7 @@
*/ */
typedef struct Undo Undo; typedef struct Undo Undo;
struct Undo struct Undo {
{
short type; /* Delete, Insert, Filename */ short type; /* Delete, Insert, Filename */
short mod; /* modify bit */ short mod; /* modify bit */
uint seq; /* sequence number */ uint seq; /* sequence number */
@ -32,60 +31,49 @@ struct Undo
uint n; /* # runes in string or file name */ uint n; /* # runes in string or file name */
}; };
enum enum { Undosize = sizeof(Undo) / sizeof(Rune) };
{
Undosize = sizeof(Undo)/sizeof(Rune)
};
File* File* fileaddtext(File* f, Text* t) {
fileaddtext(File *f, Text *t) if (f == nil) {
{
if(f == nil){
f = emalloc(sizeof(File)); f = emalloc(sizeof(File));
f->unread = TRUE; f->unread = TRUE;
} }
f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*)); f->text = realloc(f->text, (f->ntext + 1) * sizeof(Text*));
f->text[f->ntext++] = t; f->text[f->ntext++] = t;
f->curtext = t; f->curtext = t;
return f; return f;
} }
void void filedeltext(File* f, Text* t) {
filedeltext(File *f, Text *t)
{
int i; int i;
for(i=0; i<f->ntext; i++) for (i = 0; i < f->ntext; i++)
if(f->text[i] == t) if (f->text[i] == t)
goto Found; goto Found;
error("can't find text in filedeltext"); error("can't find text in filedeltext");
Found: Found:
f->ntext--; f->ntext--;
if(f->ntext == 0){ if (f->ntext == 0) {
fileclose(f); fileclose(f);
return; return;
} }
memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*)); memmove(f->text + i, f->text + i + 1, (f->ntext - i) * sizeof(Text*));
if(f->curtext == t) if (f->curtext == t)
f->curtext = f->text[0]; f->curtext = f->text[0];
} }
void void fileinsert(File* f, uint p0, Rune* s, uint ns) {
fileinsert(File *f, uint p0, Rune *s, uint ns) if (p0 > f->b.nc)
{
if(p0 > f->b.nc)
error("internal error: fileinsert"); error("internal error: fileinsert");
if(f->seq > 0) if (f->seq > 0)
fileuninsert(f, &f->delta, p0, ns); fileuninsert(f, &f->delta, p0, ns);
bufinsert(&f->b, p0, s, ns); bufinsert(&f->b, p0, s, ns);
if(ns) if (ns)
f->mod = TRUE; f->mod = TRUE;
} }
void void fileuninsert(File* f, Buffer* delta, uint p0, uint ns) {
fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
{
Undo u; Undo u;
/* undo an insertion by deleting */ /* undo an insertion by deleting */
@ -97,23 +85,19 @@ fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
bufinsert(delta, delta->nc, (Rune*)&u, Undosize); bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
} }
void void filedelete(File* f, uint p0, uint p1) {
filedelete(File *f, uint p0, uint p1) if (!(p0 <= p1 && p0 <= f->b.nc && p1 <= f->b.nc))
{
if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
error("internal error: filedelete"); error("internal error: filedelete");
if(f->seq > 0) if (f->seq > 0)
fileundelete(f, &f->delta, p0, p1); fileundelete(f, &f->delta, p0, p1);
bufdelete(&f->b, p0, p1); bufdelete(&f->b, p0, p1);
if(p1 > p0) if (p1 > p0)
f->mod = TRUE; f->mod = TRUE;
} }
void void fileundelete(File* f, Buffer* delta, uint p0, uint p1) {
fileundelete(File *f, Buffer *delta, uint p0, uint p1)
{
Undo u; Undo u;
Rune *buf; Rune* buf;
uint i, n; uint i, n;
/* undo a deletion by inserting */ /* undo a deletion by inserting */
@ -121,24 +105,21 @@ fileundelete(File *f, Buffer *delta, uint p0, uint p1)
u.mod = f->mod; u.mod = f->mod;
u.seq = f->seq; u.seq = f->seq;
u.p0 = p0; u.p0 = p0;
u.n = p1-p0; u.n = p1 - p0;
buf = fbufalloc(); buf = fbufalloc();
for(i=p0; i<p1; i+=n){ for (i = p0; i < p1; i += n) {
n = p1 - i; n = p1 - i;
if(n > RBUFSIZE) if (n > RBUFSIZE)
n = RBUFSIZE; n = RBUFSIZE;
bufread(&f->b, i, buf, n); bufread(&f->b, i, buf, n);
bufinsert(delta, delta->nc, buf, n); bufinsert(delta, delta->nc, buf, n);
} }
fbuffree(buf); fbuffree(buf);
bufinsert(delta, delta->nc, (Rune*)&u, Undosize); bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
} }
void void filesetname(File* f, Rune* name, int n) {
filesetname(File *f, Rune *name, int n) if (f->seq > 0)
{
if(f->seq > 0)
fileunsetname(f, &f->delta); fileunsetname(f, &f->delta);
free(f->name); free(f->name);
f->name = runemalloc(n); f->name = runemalloc(n);
@ -147,9 +128,7 @@ filesetname(File *f, Rune *name, int n)
f->unread = TRUE; f->unread = TRUE;
} }
void void fileunsetname(File* f, Buffer* delta) {
fileunsetname(File *f, Buffer *delta)
{
Undo u; Undo u;
/* undo a file name change by restoring old name */ /* undo a file name change by restoring old name */
@ -158,48 +137,42 @@ fileunsetname(File *f, Buffer *delta)
u.seq = f->seq; u.seq = f->seq;
u.p0 = 0; /* unused */ u.p0 = 0; /* unused */
u.n = f->nname; u.n = f->nname;
if(f->nname) if (f->nname)
bufinsert(delta, delta->nc, f->name, f->nname); bufinsert(delta, delta->nc, f->name, f->nname);
bufinsert(delta, delta->nc, (Rune*)&u, Undosize); bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
} }
uint uint fileload(File* f, uint p0, int fd, int* nulls, DigestState* h) {
fileload(File *f, uint p0, int fd, int *nulls, DigestState *h) if (f->seq > 0)
{
if(f->seq > 0)
error("undo in file.load unimplemented"); error("undo in file.load unimplemented");
return bufload(&f->b, p0, fd, nulls, h); return bufload(&f->b, p0, fd, nulls, h);
} }
/* return sequence number of pending redo */ /* return sequence number of pending redo */
uint uint fileredoseq(File* f) {
fileredoseq(File *f)
{
Undo u; Undo u;
Buffer *delta; Buffer* delta;
delta = &f->epsilon; delta = &f->epsilon;
if(delta->nc == 0) if (delta->nc == 0)
return 0; return 0;
bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize); bufread(delta, delta->nc - Undosize, (Rune*)&u, Undosize);
return u.seq; return u.seq;
} }
void void fileundo(File* f, int isundo, uint* q0p, uint* q1p) {
fileundo(File *f, int isundo, uint *q0p, uint *q1p)
{
Undo u; Undo u;
Rune *buf; Rune* buf;
uint i, j, n, up; uint i, j, n, up;
uint stop; uint stop;
Buffer *delta, *epsilon; Buffer *delta, *epsilon;
if(isundo){ if (isundo) {
/* undo; reverse delta onto epsilon, seq decreases */ /* undo; reverse delta onto epsilon, seq decreases */
delta = &f->delta; delta = &f->delta;
epsilon = &f->epsilon; epsilon = &f->epsilon;
stop = f->seq; stop = f->seq;
}else{ } else {
/* redo; reverse epsilon onto delta, seq increases */ /* redo; reverse epsilon onto delta, seq increases */
delta = &f->epsilon; delta = &f->epsilon;
epsilon = &f->delta; epsilon = &f->delta;
@ -207,21 +180,21 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
} }
buf = fbufalloc(); buf = fbufalloc();
while(delta->nc > 0){ while (delta->nc > 0) {
up = delta->nc-Undosize; up = delta->nc - Undosize;
bufread(delta, up, (Rune*)&u, Undosize); bufread(delta, up, (Rune*)&u, Undosize);
if(isundo){ if (isundo) {
if(u.seq < stop){ if (u.seq < stop) {
f->seq = u.seq; f->seq = u.seq;
goto Return; goto Return;
} }
}else{ } else {
if(stop == 0) if (stop == 0)
stop = u.seq; stop = u.seq;
if(u.seq > stop) if (u.seq > stop)
goto Return; goto Return;
} }
switch(u.type){ switch (u.type) {
default: default:
fprint(2, "undo: 0x%ux\n", u.type); fprint(2, "undo: 0x%ux\n", u.type);
abort(); abort();
@ -229,11 +202,11 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
case Delete: case Delete:
f->seq = u.seq; f->seq = u.seq;
fileundelete(f, epsilon, u.p0, u.p0+u.n); fileundelete(f, epsilon, u.p0, u.p0 + u.n);
f->mod = u.mod; f->mod = u.mod;
bufdelete(&f->b, u.p0, u.p0+u.n); bufdelete(&f->b, u.p0, u.p0 + u.n);
for(j=0; j<f->ntext; j++) for (j = 0; j < f->ntext; j++)
textdelete(f->text[j], u.p0, u.p0+u.n, FALSE); textdelete(f->text[j], u.p0, u.p0 + u.n, FALSE);
*q0p = u.p0; *q0p = u.p0;
*q1p = u.p0; *q1p = u.p0;
break; break;
@ -243,17 +216,17 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
fileuninsert(f, epsilon, u.p0, u.n); fileuninsert(f, epsilon, u.p0, u.n);
f->mod = u.mod; f->mod = u.mod;
up -= u.n; up -= u.n;
for(i=0; i<u.n; i+=n){ for (i = 0; i < u.n; i += n) {
n = u.n - i; n = u.n - i;
if(n > RBUFSIZE) if (n > RBUFSIZE)
n = RBUFSIZE; n = RBUFSIZE;
bufread(delta, up+i, buf, n); bufread(delta, up + i, buf, n);
bufinsert(&f->b, u.p0+i, buf, n); bufinsert(&f->b, u.p0 + i, buf, n);
for(j=0; j<f->ntext; j++) for (j = 0; j < f->ntext; j++)
textinsert(f->text[j], u.p0+i, buf, n, FALSE); textinsert(f->text[j], u.p0 + i, buf, n, FALSE);
} }
*q0p = u.p0; *q0p = u.p0;
*q1p = u.p0+u.n; *q1p = u.p0 + u.n;
break; break;
case Filename: case Filename:
@ -262,7 +235,7 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
f->mod = u.mod; f->mod = u.mod;
up -= u.n; up -= u.n;
free(f->name); free(f->name);
if(u.n == 0) if (u.n == 0)
f->name = nil; f->name = nil;
else else
f->name = runemalloc(u.n); f->name = runemalloc(u.n);
@ -272,23 +245,19 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
} }
bufdelete(delta, up, delta->nc); bufdelete(delta, up, delta->nc);
} }
if(isundo) if (isundo)
f->seq = 0; f->seq = 0;
Return: Return:
fbuffree(buf); fbuffree(buf);
} }
void void filereset(File* f) {
filereset(File *f)
{
bufreset(&f->delta); bufreset(&f->delta);
bufreset(&f->epsilon); bufreset(&f->epsilon);
f->seq = 0; f->seq = 0;
} }
void void fileclose(File* f) {
fileclose(File *f)
{
free(f->name); free(f->name);
f->nname = 0; f->nname = 0;
f->name = nil; f->name = nil;
@ -302,10 +271,8 @@ fileclose(File *f)
free(f); free(f);
} }
void void filemark(File* f) {
filemark(File *f) if (f->epsilon.nc)
{
if(f->epsilon.nc)
bufdelete(&f->epsilon, 0, f->epsilon.nc); bufdelete(&f->epsilon, 0, f->epsilon.nc);
f->seq = seq; f->seq = seq;
} }

1
fns.h
View file

@ -95,6 +95,7 @@ void flushwarnings(void);
void startplumbing(void); void startplumbing(void);
long nlcount(Text*, long, long, long*); long nlcount(Text*, long, long, long*);
long nlcounttopos(Text*, long, long, long); long nlcounttopos(Text*, long, long, long);
Rune* parsetag(Window*, int*);
Runestr runestr(Rune*, uint); Runestr runestr(Rune*, uint);
Range range(int, int); Range range(int, int);

411
fsys.c
View file

@ -14,15 +14,11 @@
static int sfd; static int sfd;
enum enum { Nhash = 16, DEBUG = 0 };
{
Nhash = 16,
DEBUG = 0
};
static Fid *fids[Nhash]; static Fid* fids[Nhash];
Fid *newfid(int); Fid* newfid(int);
static Xfid* fsysflush(Xfid*, Fid*); static Xfid* fsysflush(Xfid*, Fid*);
static Xfid* fsysauth(Xfid*, Fid*); static Xfid* fsysauth(Xfid*, Fid*);
@ -40,9 +36,7 @@ static Xfid* fsyswstat(Xfid*, Fid*);
Xfid* (*fcall[Tmax])(Xfid*, Fid*); Xfid* (*fcall[Tmax])(Xfid*, Fid*);
static void static void initfcall(void) {
initfcall(void)
{
fcall[Tflush] = fsysflush; fcall[Tflush] = fsysflush;
fcall[Tversion] = fsysversion; fcall[Tversion] = fsysversion;
fcall[Tauth] = fsysauth; fcall[Tauth] = fsysauth;
@ -53,7 +47,7 @@ initfcall(void)
fcall[Tread] = fsysread; fcall[Tread] = fsysread;
fcall[Twrite] = fsyswrite; fcall[Twrite] = fsyswrite;
fcall[Tclunk] = fsysclunk; fcall[Tclunk] = fsysclunk;
fcall[Tremove]= fsysremove; fcall[Tremove] = fsysremove;
fcall[Tstat] = fsysstat; fcall[Tstat] = fsysstat;
fcall[Twstat] = fsyswstat; fcall[Twstat] = fsyswstat;
} }
@ -62,44 +56,46 @@ char Eperm[] = "permission denied";
char Eexist[] = "file does not exist"; char Eexist[] = "file does not exist";
char Enotdir[] = "not a directory"; char Enotdir[] = "not a directory";
Dirtab dirtab[]= Dirtab dirtab[] = {
{ {".", QTDIR, Qdir, 0500 | DMDIR},
{ ".", QTDIR, Qdir, 0500|DMDIR }, {"acme", QTDIR, Qacme, 0500 | DMDIR},
{ "acme", QTDIR, Qacme, 0500|DMDIR }, {"cons", QTFILE, Qcons, 0600},
{ "cons", QTFILE, Qcons, 0600 }, {"consctl", QTFILE, Qconsctl, 0000},
{ "consctl", QTFILE, Qconsctl, 0000 }, {"draw",
{ "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */ QTDIR,
{ "editout", QTFILE, Qeditout, 0200 }, Qdraw,
{ "index", QTFILE, Qindex, 0400 }, 0000 | DMDIR}, /* to suppress graphics progs started in acme */
{ "label", QTFILE, Qlabel, 0600 }, {"editout", QTFILE, Qeditout, 0200},
{ "log", QTFILE, Qlog, 0400 }, {"index", QTFILE, Qindex, 0400},
{ "new", QTDIR, Qnew, 0500|DMDIR }, {"label", QTFILE, Qlabel, 0600},
{ nil, } {"log", QTFILE, Qlog, 0400},
}; {"new", QTDIR, Qnew, 0500 | DMDIR},
{
nil,
}};
Dirtab dirtabw[]= Dirtab dirtabw[] = {
{ {".", QTDIR, Qdir, 0500 | DMDIR},
{ ".", QTDIR, Qdir, 0500|DMDIR }, {"addr", QTFILE, QWaddr, 0600},
{ "addr", QTFILE, QWaddr, 0600 }, {"body", QTAPPEND, QWbody, 0600 | DMAPPEND},
{ "body", QTAPPEND, QWbody, 0600|DMAPPEND }, {"ctl", QTFILE, QWctl, 0600},
{ "ctl", QTFILE, QWctl, 0600 }, {"data", QTFILE, QWdata, 0600},
{ "data", QTFILE, QWdata, 0600 }, {"editout", QTFILE, QWeditout, 0200},
{ "editout", QTFILE, QWeditout, 0200 }, {"errors", QTFILE, QWerrors, 0200},
{ "errors", QTFILE, QWerrors, 0200 }, {"event", QTFILE, QWevent, 0600},
{ "event", QTFILE, QWevent, 0600 }, {"rdsel", QTFILE, QWrdsel, 0400},
{ "rdsel", QTFILE, QWrdsel, 0400 }, {"wrsel", QTFILE, QWwrsel, 0200},
{ "wrsel", QTFILE, QWwrsel, 0200 }, {"tag", QTAPPEND, QWtag, 0600 | DMAPPEND},
{ "tag", QTAPPEND, QWtag, 0600|DMAPPEND }, {"xdata", QTFILE, QWxdata, 0600},
{ "xdata", QTFILE, QWxdata, 0600 }, {
{ nil, } nil,
}; }};
typedef struct Mnt Mnt; typedef struct Mnt Mnt;
struct Mnt struct Mnt {
{
QLock lk; QLock lk;
int id; int id;
Mntdir *md; Mntdir* md;
}; };
Mnt mnt; Mnt mnt;
@ -108,64 +104,62 @@ Xfid* respond(Xfid*, Fcall*, char*);
int dostat(int, Dirtab*, uchar*, int, uint); int dostat(int, Dirtab*, uchar*, int, uint);
uint getclock(void); uint getclock(void);
char *user = "Wile E. Coyote"; char* user = "Wile E. Coyote";
static int closing = 0; static int closing = 0;
int messagesize = Maxblock+IOHDRSZ; /* good start */ int messagesize = Maxblock + IOHDRSZ; /* good start */
void fsysproc(void *); void fsysproc(void*);
void void fsysinit(void) {
fsysinit(void)
{
int p[2]; int p[2];
char *u; char* u;
initfcall(); initfcall();
if(pipe(p) < 0) if (pipe(p) < 0)
error("can't create pipe"); error("can't create pipe");
if(post9pservice(p[0], "acme", mtpt) < 0) if (post9pservice(p[0], "acme", mtpt) < 0)
error("can't post service"); error("can't post service");
sfd = p[1]; sfd = p[1];
fmtinstall('F', fcallfmt); fmtinstall('F', fcallfmt);
if((u = getuser()) != nil) if ((u = getuser()) != nil)
user = estrdup(u); user = estrdup(u);
proccreate(fsysproc, nil, STACK); proccreate(fsysproc, nil, STACK);
} }
void void fsysproc(void* v) {
fsysproc(void *v)
{
int n; int n;
Xfid *x; Xfid* x;
Fid *f; Fid* f;
Fcall t; Fcall t;
uchar *buf; uchar* buf;
threadsetname("fsysproc"); threadsetname("fsysproc");
USED(v); USED(v);
x = nil; x = nil;
for(;;){ for (;;) {
buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */ buf = emalloc(
messagesize +
UTFmax); /* overflow for appending partial rune in xfidwrite */
n = read9pmsg(sfd, buf, messagesize); n = read9pmsg(sfd, buf, messagesize);
if(n <= 0){ if (n <= 0) {
if(closing) if (closing)
break; break;
error("i/o error on server channel"); error("i/o error on server channel");
} }
if(x == nil){ if (x == nil) {
sendp(cxfidalloc, nil); sendp(cxfidalloc, nil);
x = recvp(cxfidalloc); x = recvp(cxfidalloc);
} }
x->buf = buf; x->buf = buf;
if(convM2S(buf, n, &x->fcall) != n) if (convM2S(buf, n, &x->fcall) != n)
error("convert error in convM2S"); error("convert error in convM2S");
if(DEBUG) if (DEBUG)
fprint(2, "%F\n", &x->fcall); fprint(2, "%F\n", &x->fcall);
if(fcall[x->fcall.type] == nil) if (fcall[x->fcall.type] == nil)
x = respond(x, &t, "bad fcall type"); x = respond(x, &t, "bad fcall type");
else{ else {
switch(x->fcall.type){ switch (x->fcall.type) {
case Tversion: case Tversion:
case Tauth: case Tauth:
case Tflush: case Tflush:
@ -176,7 +170,7 @@ fsysproc(void *v)
break; break;
default: default:
f = newfid(x->fcall.fid); f = newfid(x->fcall.fid);
if(!f->busy){ if (!f->busy) {
x->f = f; x->f = f;
x = respond(x, &t, "fid not in use"); x = respond(x, &t, "fid not in use");
continue; continue;
@ -189,10 +183,8 @@ fsysproc(void *v)
} }
} }
Mntdir* Mntdir* fsysaddid(Rune* dir, int ndir, Rune** incl, int nincl) {
fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl) Mntdir* m;
{
Mntdir *m;
int id; int id;
qlock(&mnt.lk); qlock(&mnt.lk);
@ -210,36 +202,32 @@ fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
return m; return m;
} }
void void fsysincid(Mntdir* m) {
fsysincid(Mntdir *m)
{
qlock(&mnt.lk); qlock(&mnt.lk);
m->ref++; m->ref++;
qunlock(&mnt.lk); qunlock(&mnt.lk);
} }
void void fsysdelid(Mntdir* idm) {
fsysdelid(Mntdir *idm)
{
Mntdir *m, *prev; Mntdir *m, *prev;
int i; int i;
char buf[64]; char buf[64];
if(idm == nil) if (idm == nil)
return; return;
qlock(&mnt.lk); qlock(&mnt.lk);
if(--idm->ref > 0){ if (--idm->ref > 0) {
qunlock(&mnt.lk); qunlock(&mnt.lk);
return; return;
} }
prev = nil; prev = nil;
for(m=mnt.md; m; m=m->next){ for (m = mnt.md; m; m = m->next) {
if(m == idm){ if (m == idm) {
if(prev) if (prev)
prev->next = m->next; prev->next = m->next;
else else
mnt.md = m->next; mnt.md = m->next;
for(i=0; i<m->nincl; i++) for (i = 0; i < m->nincl; i++)
free(m->incl[i]); free(m->incl[i]);
free(m->incl); free(m->incl);
free(m->dir); free(m->dir);
@ -257,15 +245,11 @@ fsysdelid(Mntdir *idm)
/* /*
* Called only in exec.c:/^run(), from a different FD group * Called only in exec.c:/^run(), from a different FD group
*/ */
Mntdir* Mntdir* fsysmount(Rune* dir, int ndir, Rune** incl, int nincl) {
fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
{
return fsysaddid(dir, ndir, incl, nincl); return fsysaddid(dir, ndir, incl, nincl);
} }
void void fsysclose(void) {
fsysclose(void)
{
closing = 1; closing = 1;
/* /*
* apparently this is not kosher on openbsd. * apparently this is not kosher on openbsd.
@ -275,78 +259,64 @@ fsysclose(void)
*/ */
} }
Xfid* Xfid* respond(Xfid* x, Fcall* t, char* err) {
respond(Xfid *x, Fcall *t, char *err)
{
int n; int n;
if(err){ if (err) {
t->type = Rerror; t->type = Rerror;
t->ename = err; t->ename = err;
}else } else
t->type = x->fcall.type+1; t->type = x->fcall.type + 1;
t->fid = x->fcall.fid; t->fid = x->fcall.fid;
t->tag = x->fcall.tag; t->tag = x->fcall.tag;
if(x->buf == nil) if (x->buf == nil)
x->buf = emalloc(messagesize); x->buf = emalloc(messagesize);
n = convS2M(t, x->buf, messagesize); n = convS2M(t, x->buf, messagesize);
if(n <= 0) if (n <= 0)
error("convert error in convS2M"); error("convert error in convS2M");
if(write(sfd, x->buf, n) != n) if (write(sfd, x->buf, n) != n)
error("write error in respond"); error("write error in respond");
free(x->buf); free(x->buf);
x->buf = nil; x->buf = nil;
if(DEBUG) if (DEBUG)
fprint(2, "r: %F\n", t); fprint(2, "r: %F\n", t);
return x; return x;
} }
static static Xfid* fsysversion(Xfid* x, Fid* f) {
Xfid*
fsysversion(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
USED(f); USED(f);
if(x->fcall.msize < 256) if (x->fcall.msize < 256)
return respond(x, &t, "version: message size too small"); return respond(x, &t, "version: message size too small");
messagesize = x->fcall.msize; messagesize = x->fcall.msize;
t.msize = messagesize; t.msize = messagesize;
if(strncmp(x->fcall.version, "9P2000", 6) != 0) if (strncmp(x->fcall.version, "9P2000", 6) != 0)
return respond(x, &t, "unrecognized 9P version"); return respond(x, &t, "unrecognized 9P version");
t.version = "9P2000"; t.version = "9P2000";
return respond(x, &t, nil); return respond(x, &t, nil);
} }
static static Xfid* fsysauth(Xfid* x, Fid* f) {
Xfid*
fsysauth(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
USED(f); USED(f);
return respond(x, &t, "acme: authentication not required"); return respond(x, &t, "acme: authentication not required");
} }
static static Xfid* fsysflush(Xfid* x, Fid* f) {
Xfid*
fsysflush(Xfid *x, Fid *f)
{
USED(f); USED(f);
sendp(x->c, (void*)xfidflush); sendp(x->c, (void*)xfidflush);
return nil; return nil;
} }
static static Xfid* fsysattach(Xfid* x, Fid* f) {
Xfid*
fsysattach(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
int id; int id;
Mntdir *m; Mntdir* m;
char buf[128]; char buf[128];
if(strcmp(x->fcall.uname, user) != 0) if (strcmp(x->fcall.uname, user) != 0)
return respond(x, &t, Eperm); return respond(x, &t, Eperm);
f->busy = TRUE; f->busy = TRUE;
f->open = FALSE; f->open = FALSE;
@ -360,13 +330,13 @@ fsysattach(Xfid *x, Fid *f)
f->mntdir = nil; f->mntdir = nil;
id = atoi(x->fcall.aname); id = atoi(x->fcall.aname);
qlock(&mnt.lk); qlock(&mnt.lk);
for(m=mnt.md; m; m=m->next) for (m = mnt.md; m; m = m->next)
if(m->id == id){ if (m->id == id) {
f->mntdir = m; f->mntdir = m;
m->ref++; m->ref++;
break; break;
} }
if(m == nil && x->fcall.aname[0]){ if (m == nil && x->fcall.aname[0]) {
snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname); snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
sendp(cerr, estrdup(buf)); sendp(cerr, estrdup(buf));
} }
@ -374,38 +344,35 @@ fsysattach(Xfid *x, Fid *f)
return respond(x, &t, nil); return respond(x, &t, nil);
} }
static static Xfid* fsyswalk(Xfid* x, Fid* f) {
Xfid*
fsyswalk(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
int c, i, j, id; int c, i, j, id;
Qid q; Qid q;
uchar type; uchar type;
ulong path; ulong path;
Fid *nf; Fid* nf;
Dirtab *d, *dir; Dirtab *d, *dir;
Window *w; Window* w;
char *err; char* err;
nf = nil; nf = nil;
w = nil; w = nil;
if(f->open) if (f->open)
return respond(x, &t, "walk of open file"); return respond(x, &t, "walk of open file");
if(x->fcall.fid != x->fcall.newfid){ if (x->fcall.fid != x->fcall.newfid) {
nf = newfid(x->fcall.newfid); nf = newfid(x->fcall.newfid);
if(nf->busy) if (nf->busy)
return respond(x, &t, "newfid already in use"); return respond(x, &t, "newfid already in use");
nf->busy = TRUE; nf->busy = TRUE;
nf->open = FALSE; nf->open = FALSE;
nf->mntdir = f->mntdir; nf->mntdir = f->mntdir;
if(f->mntdir) if (f->mntdir)
f->mntdir->ref++; f->mntdir->ref++;
nf->dir = f->dir; nf->dir = f->dir;
nf->qid = f->qid; nf->qid = f->qid;
nf->w = f->w; nf->w = f->w;
nf->nrpart = 0; /* not open, so must be zero */ nf->nrpart = 0; /* not open, so must be zero */
if(nf->w) if (nf->w)
incref(&nf->w->ref); incref(&nf->w->ref);
f = nf; /* walk f */ f = nf; /* walk f */
} }
@ -416,23 +383,23 @@ fsyswalk(Xfid *x, Fid *f)
id = WIN(f->qid); id = WIN(f->qid);
q = f->qid; q = f->qid;
if(x->fcall.nwname > 0){ if (x->fcall.nwname > 0) {
for(i=0; i<x->fcall.nwname; i++){ for (i = 0; i < x->fcall.nwname; i++) {
if((q.type & QTDIR) == 0){ if ((q.type & QTDIR) == 0) {
err = Enotdir; err = Enotdir;
break; break;
} }
if(strcmp(x->fcall.wname[i], "..") == 0){ if (strcmp(x->fcall.wname[i], "..") == 0) {
type = QTDIR; type = QTDIR;
path = Qdir; path = Qdir;
id = 0; id = 0;
if(w){ if (w) {
winclose(w); winclose(w);
w = nil; w = nil;
} }
Accept: Accept:
if(i == MAXWELEM){ if (i == MAXWELEM) {
err = "name too long"; err = "name too long";
break; break;
} }
@ -444,16 +411,16 @@ fsyswalk(Xfid *x, Fid *f)
} }
/* is it a numeric name? */ /* is it a numeric name? */
for(j=0; (c=x->fcall.wname[i][j]); j++) for (j = 0; (c = x->fcall.wname[i][j]); j++)
if(c<'0' || '9'<c) if (c < '0' || '9' < c)
goto Regular; goto Regular;
/* yes: it's a directory */ /* yes: it's a directory */
if(w) /* name has form 27/23; get out before losing w */ if (w) /* name has form 27/23; get out before losing w */
break; break;
id = atoi(x->fcall.wname[i]); id = atoi(x->fcall.wname[i]);
qlock(&row.lk); qlock(&row.lk);
w = lookid(id, FALSE); w = lookid(id, FALSE);
if(w == nil){ if (w == nil) {
qunlock(&row.lk); qunlock(&row.lk);
break; break;
} }
@ -465,8 +432,8 @@ fsyswalk(Xfid *x, Fid *f)
goto Accept; goto Accept;
Regular: Regular:
if(strcmp(x->fcall.wname[i], "new") == 0){ if (strcmp(x->fcall.wname[i], "new") == 0) {
if(w) if (w)
error("w set in walk to new"); error("w set in walk to new");
sendp(cnewwindow, nil); /* signal newwindowthread */ sendp(cnewwindow, nil); /* signal newwindowthread */
w = recvp(cnewwindow); /* receive new window */ w = recvp(cnewwindow); /* receive new window */
@ -478,13 +445,13 @@ fsyswalk(Xfid *x, Fid *f)
goto Accept; goto Accept;
} }
if(id == 0) if (id == 0)
d = dirtab; d = dirtab;
else else
d = dirtabw; d = dirtabw;
d++; /* skip '.' */ d++; /* skip '.' */
for(; d->name; d++) for (; d->name; d++)
if(strcmp(x->fcall.wname[i], d->name) == 0){ if (strcmp(x->fcall.wname[i], d->name) == 0) {
path = d->qid; path = d->qid;
type = d->type; type = d->type;
dir = d; dir = d;
@ -494,44 +461,41 @@ fsyswalk(Xfid *x, Fid *f)
break; /* file not found */ break; /* file not found */
} }
if(i==0 && err == nil) if (i == 0 && err == nil)
err = Eexist; err = Eexist;
} }
if(err!=nil || t.nwqid<x->fcall.nwname){ if (err != nil || t.nwqid < x->fcall.nwname) {
if(nf){ if (nf) {
nf->busy = FALSE; nf->busy = FALSE;
fsysdelid(nf->mntdir); fsysdelid(nf->mntdir);
} }
}else if(t.nwqid == x->fcall.nwname){ } else if (t.nwqid == x->fcall.nwname) {
if(w){ if (w) {
f->w = w; f->w = w;
w = nil; /* don't drop the reference */ w = nil; /* don't drop the reference */
} }
if(dir) if (dir)
f->dir = dir; f->dir = dir;
f->qid = q; f->qid = q;
} }
if(w != nil) if (w != nil)
winclose(w); winclose(w);
return respond(x, &t, err); return respond(x, &t, err);
} }
static static Xfid* fsysopen(Xfid* x, Fid* f) {
Xfid*
fsysopen(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
int m; int m;
/* can't truncate anything, so just disregard */ /* can't truncate anything, so just disregard */
x->fcall.mode &= ~(OTRUNC|OCEXEC); x->fcall.mode &= ~(OTRUNC | OCEXEC);
/* can't execute or remove anything */ /* can't execute or remove anything */
if(x->fcall.mode==OEXEC || (x->fcall.mode&ORCLOSE)) if (x->fcall.mode == OEXEC || (x->fcall.mode & ORCLOSE))
goto Deny; goto Deny;
switch(x->fcall.mode){ switch (x->fcall.mode) {
default: default:
goto Deny; goto Deny;
case OREAD: case OREAD:
@ -544,79 +508,68 @@ fsysopen(Xfid *x, Fid *f)
m = 0600; m = 0600;
break; break;
} }
if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m) if (((f->dir->perm & ~(DMDIR | DMAPPEND)) & m) != m)
goto Deny; goto Deny;
sendp(x->c, (void*)xfidopen); sendp(x->c, (void*)xfidopen);
return nil; return nil;
Deny: Deny:
return respond(x, &t, Eperm); return respond(x, &t, Eperm);
} }
static static Xfid* fsyscreate(Xfid* x, Fid* f) {
Xfid*
fsyscreate(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
USED(f); USED(f);
return respond(x, &t, Eperm); return respond(x, &t, Eperm);
} }
static static int idcmp(const void* a, const void* b) { return *(int*)a - *(int*)b; }
int
idcmp(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
static static Xfid* fsysread(Xfid* x, Fid* f) {
Xfid*
fsysread(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
uchar *b; uchar* b;
int i, id, n, o, e, j, k, *ids, nids; int i, id, n, o, e, j, k, *ids, nids;
Dirtab *d, dt; Dirtab *d, dt;
Column *c; Column* c;
uint clock, len; uint clock, len;
char buf[16]; char buf[16];
if(f->qid.type & QTDIR){ if (f->qid.type & QTDIR) {
if(FILE(f->qid) == Qacme){ /* empty dir */ if (FILE(f->qid) == Qacme) { /* empty dir */
t.data = nil; t.data = nil;
t.count = 0; t.count = 0;
respond(x, &t, nil); respond(x, &t, nil);
return x; return x;
} }
o = x->fcall.offset; o = x->fcall.offset;
e = x->fcall.offset+x->fcall.count; e = x->fcall.offset + x->fcall.count;
clock = getclock(); clock = getclock();
b = emalloc(messagesize); b = emalloc(messagesize);
id = WIN(f->qid); id = WIN(f->qid);
n = 0; n = 0;
if(id > 0) if (id > 0)
d = dirtabw; d = dirtabw;
else else
d = dirtab; d = dirtab;
d++; /* first entry is '.' */ d++; /* first entry is '.' */
for(i=0; d->name!=nil && i<e; i+=len){ for (i = 0; d->name != nil && i < e; i += len) {
len = dostat(WIN(x->f->qid), d, b+n, x->fcall.count-n, clock); len = dostat(WIN(x->f->qid), d, b + n, x->fcall.count - n, clock);
if(len <= BIT16SZ) if (len <= BIT16SZ)
break; break;
if(i >= o) if (i >= o)
n += len; n += len;
d++; d++;
} }
if(id == 0){ if (id == 0) {
qlock(&row.lk); qlock(&row.lk);
nids = 0; nids = 0;
ids = nil; ids = nil;
for(j=0; j<row.ncol; j++){ for (j = 0; j < row.ncol; j++) {
c = row.col[j]; c = row.col[j];
for(k=0; k<c->nw; k++){ for (k = 0; k < c->nw; k++) {
ids = realloc(ids, (nids+1)*sizeof(int)); ids = realloc(ids, (nids + 1) * sizeof(int));
ids[nids++] = c->w[k]->id; ids[nids++] = c->w[k]->id;
} }
} }
@ -624,16 +577,16 @@ fsysread(Xfid *x, Fid *f)
qsort(ids, nids, sizeof ids[0], idcmp); qsort(ids, nids, sizeof ids[0], idcmp);
j = 0; j = 0;
dt.name = buf; dt.name = buf;
for(; j<nids && i<e; i+=len){ for (; j < nids && i < e; i += len) {
k = ids[j]; k = ids[j];
sprint(dt.name, "%d", k); sprint(dt.name, "%d", k);
dt.qid = QID(k, Qdir); dt.qid = QID(k, Qdir);
dt.type = QTDIR; dt.type = QTDIR;
dt.perm = DMDIR|0700; dt.perm = DMDIR | 0700;
len = dostat(k, &dt, b+n, x->fcall.count-n, clock); len = dostat(k, &dt, b + n, x->fcall.count - n, clock);
if(len == 0) if (len == 0)
break; break;
if(i >= o) if (i >= o)
n += len; n += len;
j++; j++;
} }
@ -649,70 +602,54 @@ fsysread(Xfid *x, Fid *f)
return nil; return nil;
} }
static static Xfid* fsyswrite(Xfid* x, Fid* f) {
Xfid*
fsyswrite(Xfid *x, Fid *f)
{
USED(f); USED(f);
sendp(x->c, (void*)xfidwrite); sendp(x->c, (void*)xfidwrite);
return nil; return nil;
} }
static static Xfid* fsysclunk(Xfid* x, Fid* f) {
Xfid*
fsysclunk(Xfid *x, Fid *f)
{
fsysdelid(f->mntdir); fsysdelid(f->mntdir);
sendp(x->c, (void*)xfidclose); sendp(x->c, (void*)xfidclose);
return nil; return nil;
} }
static static Xfid* fsysremove(Xfid* x, Fid* f) {
Xfid*
fsysremove(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
USED(f); USED(f);
return respond(x, &t, Eperm); return respond(x, &t, Eperm);
} }
static static Xfid* fsysstat(Xfid* x, Fid* f) {
Xfid*
fsysstat(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
t.stat = emalloc(messagesize-IOHDRSZ); t.stat = emalloc(messagesize - IOHDRSZ);
t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock()); t.nstat =
dostat(WIN(x->f->qid), f->dir, t.stat, messagesize - IOHDRSZ, getclock());
x = respond(x, &t, nil); x = respond(x, &t, nil);
free(t.stat); free(t.stat);
return x; return x;
} }
static static Xfid* fsyswstat(Xfid* x, Fid* f) {
Xfid*
fsyswstat(Xfid *x, Fid *f)
{
Fcall t; Fcall t;
USED(f); USED(f);
return respond(x, &t, Eperm); return respond(x, &t, Eperm);
} }
Fid* Fid* newfid(int fid) {
newfid(int fid)
{
Fid *f, *ff, **fh; Fid *f, *ff, **fh;
ff = nil; ff = nil;
fh = &fids[fid&(Nhash-1)]; fh = &fids[fid & (Nhash - 1)];
for(f=*fh; f; f=f->next) for (f = *fh; f; f = f->next)
if(f->fid == fid) if (f->fid == fid)
return f; return f;
else if(ff==nil && f->busy==FALSE) else if (ff == nil && f->busy == FALSE)
ff = f; ff = f;
if(ff){ if (ff) {
ff->fid = fid; ff->fid = fid;
return ff; return ff;
} }
@ -723,15 +660,9 @@ newfid(int fid)
return f; return f;
} }
uint uint getclock(void) { return time(0); }
getclock(void)
{
return time(0);
}
int int dostat(int id, Dirtab* dir, uchar* buf, int nbuf, uint clock) {
dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
{
Dir d; Dir d;
d.qid.path = QID(id, dir->qid); d.qid.path = QID(id, dir->qid);

99
logf.c
View file

@ -14,40 +14,37 @@
// State for global log file. // State for global log file.
typedef struct Log Log; typedef struct Log Log;
struct Log struct Log {
{
QLock lk; QLock lk;
Rendez r; Rendez r;
vlong start; // msg[0] corresponds to 'start' in the global sequence of events vlong start; // msg[0] corresponds to 'start' in the global sequence of events
// queued events (nev=entries in ev, mev=capacity of p) // queued events (nev=entries in ev, mev=capacity of p)
char **ev; char** ev;
int nev; int nev;
int mev; int mev;
// open acme/put files that need to read events // open acme/put files that need to read events
Fid **f; Fid** f;
int nf; int nf;
int mf; int mf;
// active (blocked) reads waiting for events // active (blocked) reads waiting for events
Xfid **read; Xfid** read;
int nread; int nread;
int mread; int mread;
}; };
static Log eventlog; static Log eventlog;
void void xfidlogopen(Xfid* x) {
xfidlogopen(Xfid *x)
{
qlock(&eventlog.lk); qlock(&eventlog.lk);
if(eventlog.nf >= eventlog.mf) { if (eventlog.nf >= eventlog.mf) {
eventlog.mf = eventlog.mf*2; eventlog.mf = eventlog.mf * 2;
if(eventlog.mf == 0) if (eventlog.mf == 0)
eventlog.mf = 8; eventlog.mf = 8;
eventlog.f = erealloc(eventlog.f, eventlog.mf*sizeof eventlog.f[0]); eventlog.f = erealloc(eventlog.f, eventlog.mf * sizeof eventlog.f[0]);
} }
eventlog.f[eventlog.nf++] = x->f; eventlog.f[eventlog.nf++] = x->f;
x->f->logoff = eventlog.start + eventlog.nev; x->f->logoff = eventlog.start + eventlog.nev;
@ -55,14 +52,12 @@ xfidlogopen(Xfid *x)
qunlock(&eventlog.lk); qunlock(&eventlog.lk);
} }
void void xfidlogclose(Xfid* x) {
xfidlogclose(Xfid *x)
{
int i; int i;
qlock(&eventlog.lk); qlock(&eventlog.lk);
for(i=0; i<eventlog.nf; i++) { for (i = 0; i < eventlog.nf; i++) {
if(eventlog.f[i] == x->f) { if (eventlog.f[i] == x->f) {
eventlog.f[i] = eventlog.f[--eventlog.nf]; eventlog.f[i] = eventlog.f[--eventlog.nf];
break; break;
} }
@ -70,36 +65,35 @@ xfidlogclose(Xfid *x)
qunlock(&eventlog.lk); qunlock(&eventlog.lk);
} }
void void xfidlogread(Xfid* x) {
xfidlogread(Xfid *x) char* p;
{
char *p;
int i; int i;
Fcall fc; Fcall fc;
qlock(&eventlog.lk); qlock(&eventlog.lk);
if(eventlog.nread >= eventlog.mread) { if (eventlog.nread >= eventlog.mread) {
eventlog.mread = eventlog.mread*2; eventlog.mread = eventlog.mread * 2;
if(eventlog.mread == 0) if (eventlog.mread == 0)
eventlog.mread = 8; eventlog.mread = 8;
eventlog.read = erealloc(eventlog.read, eventlog.mread*sizeof eventlog.read[0]); eventlog.read =
erealloc(eventlog.read, eventlog.mread * sizeof eventlog.read[0]);
} }
eventlog.read[eventlog.nread++] = x; eventlog.read[eventlog.nread++] = x;
if(eventlog.r.l == nil) if (eventlog.r.l == nil)
eventlog.r.l = &eventlog.lk; eventlog.r.l = &eventlog.lk;
x->flushed = FALSE; x->flushed = FALSE;
while(x->f->logoff >= eventlog.start+eventlog.nev && !x->flushed) while (x->f->logoff >= eventlog.start + eventlog.nev && !x->flushed)
rsleep(&eventlog.r); rsleep(&eventlog.r);
for(i=0; i<eventlog.nread; i++) { for (i = 0; i < eventlog.nread; i++) {
if(eventlog.read[i] == x) { if (eventlog.read[i] == x) {
eventlog.read[i] = eventlog.read[--eventlog.nread]; eventlog.read[i] = eventlog.read[--eventlog.nread];
break; break;
} }
} }
if(x->flushed) { if (x->flushed) {
qunlock(&eventlog.lk); qunlock(&eventlog.lk);
return; return;
} }
@ -115,16 +109,14 @@ xfidlogread(Xfid *x)
free(p); free(p);
} }
void void xfidlogflush(Xfid* x) {
xfidlogflush(Xfid *x)
{
int i; int i;
Xfid *rx; Xfid* rx;
qlock(&eventlog.lk); qlock(&eventlog.lk);
for(i=0; i<eventlog.nread; i++) { for (i = 0; i < eventlog.nread; i++) {
rx = eventlog.read[i]; rx = eventlog.read[i];
if(rx->fcall.tag == x->fcall.oldtag) { if (rx->fcall.tag == x->fcall.oldtag) {
rx->flushed = TRUE; rx->flushed = TRUE;
rwakeupall(&eventlog.r); rwakeupall(&eventlog.r);
} }
@ -153,46 +145,47 @@ xfidlogflush(Xfid *x)
* op == "del" for deleted window * op == "del" for deleted window
* - called from winclose * - called from winclose
*/ */
void void xfidlog(Window* w, char* op) {
xfidlog(Window *w, char *op)
{
int i, n; int i, n;
vlong min; vlong min;
File *f; File* f;
char *name; char* name;
qlock(&eventlog.lk); qlock(&eventlog.lk);
if(eventlog.nev >= eventlog.mev) { if (eventlog.nev >= eventlog.mev) {
// Remove and free any entries that all readers have read. // Remove and free any entries that all readers have read.
min = eventlog.start + eventlog.nev; min = eventlog.start + eventlog.nev;
for(i=0; i<eventlog.nf; i++) { for (i = 0; i < eventlog.nf; i++) {
if(min > eventlog.f[i]->logoff) if (min > eventlog.f[i]->logoff)
min = eventlog.f[i]->logoff; min = eventlog.f[i]->logoff;
} }
if(min > eventlog.start) { if (min > eventlog.start) {
n = min - eventlog.start; n = min - eventlog.start;
for(i=0; i<n; i++) for (i = 0; i < n; i++)
free(eventlog.ev[i]); free(eventlog.ev[i]);
eventlog.nev -= n; eventlog.nev -= n;
eventlog.start += n; eventlog.start += n;
memmove(eventlog.ev, eventlog.ev+n, eventlog.nev*sizeof eventlog.ev[0]); memmove(
eventlog.ev,
eventlog.ev + n,
eventlog.nev * sizeof eventlog.ev[0]);
} }
// Otherwise grow. // Otherwise grow.
if(eventlog.nev >= eventlog.mev) { if (eventlog.nev >= eventlog.mev) {
eventlog.mev = eventlog.mev*2; eventlog.mev = eventlog.mev * 2;
if(eventlog.mev == 0) if (eventlog.mev == 0)
eventlog.mev = 8; eventlog.mev = 8;
eventlog.ev = erealloc(eventlog.ev, eventlog.mev*sizeof eventlog.ev[0]); eventlog.ev = erealloc(eventlog.ev, eventlog.mev * sizeof eventlog.ev[0]);
} }
} }
f = w->body.file; f = w->body.file;
name = runetobyte(f->name, f->nname); name = runetobyte(f->name, f->nname);
if(name == nil) if (name == nil)
name = estrdup(""); name = estrdup("");
eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name); eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name);
free(name); free(name);
if(eventlog.r.l == nil) if (eventlog.r.l == nil)
eventlog.r.l = &eventlog.lk; eventlog.r.l = &eventlog.lk;
rwakeupall(&eventlog.r); rwakeupall(&eventlog.r);
qunlock(&eventlog.lk); qunlock(&eventlog.lk);

599
look.c

File diff suppressed because it is too large Load diff

View file

@ -7,23 +7,21 @@
#include <9pclient.h> #include <9pclient.h>
#include "dat.h" #include "dat.h"
char* char* formathtml(char* body, int* np) {
formathtml(char *body, int *np)
{
int i, j, p[2], q[2]; int i, j, p[2], q[2];
Exec *e; Exec* e;
char buf[1024]; char buf[1024];
Channel *sync; Channel* sync;
e = emalloc(sizeof(struct Exec)); e = emalloc(sizeof(struct Exec));
if(pipe(p) < 0 || pipe(q) < 0) if (pipe(p) < 0 || pipe(q) < 0)
error("can't create pipe: %r"); error("can't create pipe: %r");
e->p[0] = p[0]; e->p[0] = p[0];
e->p[1] = p[1]; e->p[1] = p[1];
e->q[0] = q[0]; e->q[0] = q[0];
e->q[1] = q[1]; e->q[1] = q[1];
e->argv = emalloc(3*sizeof(char*)); e->argv = emalloc(3 * sizeof(char*));
e->argv[0] = estrdup("htmlfmt"); e->argv[0] = estrdup("htmlfmt");
e->argv[1] = estrdup("-cutf-8"); e->argv[1] = estrdup("-cutf-8");
e->argv[2] = nil; e->argv[2] = nil;
@ -35,7 +33,7 @@ formathtml(char *body, int *np)
close(p[0]); close(p[0]);
close(q[1]); close(q[1]);
if((i=write(p[1], body, *np)) != *np){ if ((i = write(p[1], body, *np)) != *np) {
fprint(2, "Mail: warning: htmlfmt failed: wrote %d of %d: %r\n", i, *np); fprint(2, "Mail: warning: htmlfmt failed: wrote %d of %d: %r\n", i, *np);
close(p[1]); close(p[1]);
close(q[0]); close(q[0]);
@ -46,14 +44,14 @@ formathtml(char *body, int *np)
free(body); free(body);
body = nil; body = nil;
i = 0; i = 0;
for(;;){ for (;;) {
j = read(q[0], buf, sizeof buf); j = read(q[0], buf, sizeof buf);
if(j <= 0) if (j <= 0)
break; break;
body = realloc(body, i+j+1); body = realloc(body, i + j + 1);
if(body == nil) if (body == nil)
error("realloc failed: %r"); error("realloc failed: %r");
memmove(body+i, buf, j); memmove(body + i, buf, j);
i += j; i += j;
body[i] = '\0'; body[i] = '\0';
} }
@ -63,13 +61,11 @@ formathtml(char *body, int *np)
return body; return body;
} }
char* char* readbody(char* type, char* dir, int* np) {
readbody(char *type, char *dir, int *np) char* body;
{
char *body;
body = readfile(dir, "body", np); body = readfile(dir, "body", np);
if(body != nil && strcmp(type, "text/html") == 0) if (body != nil && strcmp(type, "text/html") == 0)
return formathtml(body, np); return formathtml(body, np);
return body; return body;
} }

Binary file not shown.

View file

@ -7,25 +7,25 @@
#include <ctype.h> #include <ctype.h>
#include "dat.h" #include "dat.h"
char *maildir = "Mail/"; /* mountpoint of mail file system */ char* maildir = "Mail/"; /* mountpoint of mail file system */
char *mboxname = "mbox"; /* mailboxdir/mboxname is mail spool file */ char* mboxname = "mbox"; /* mailboxdir/mboxname is mail spool file */
char *mailboxdir = nil; /* nil == /mail/box/$user */ char* mailboxdir = nil; /* nil == /mail/box/$user */
char *fsname; /* filesystem for mailboxdir/mboxname is at maildir/fsname */ char* fsname; /* filesystem for mailboxdir/mboxname is at maildir/fsname */
char *user; char* user;
char *outgoing; char* outgoing;
char *srvname; char* srvname;
Window *wbox; Window* wbox;
Message mbox; Message mbox;
Message replies; Message replies;
char *home; char* home;
CFid *plumbsendfd; CFid* plumbsendfd;
CFid *plumbseemailfd; CFid* plumbseemailfd;
CFid *plumbshowmailfd; CFid* plumbshowmailfd;
CFid *plumbsendmailfd; CFid* plumbsendmailfd;
Channel *cplumb; Channel* cplumb;
Channel *cplumbshow; Channel* cplumbshow;
Channel *cplumbsend; Channel* cplumbsend;
int wctlfd; int wctlfd;
void mainctl(void*); void mainctl(void*);
void plumbproc(void*); void plumbproc(void*);
@ -37,44 +37,39 @@ void plumbsendthread(void*);
int shortmenu; int shortmenu;
CFsys *mailfs; CFsys* mailfs;
CFsys *acmefs; CFsys* acmefs;
void void usage(void) {
usage(void) fprint(
{ 2,
fprint(2, "usage: Mail [-sS] [-n srvname] [-o outgoing] [mailboxname [directoryname]]\n"); "usage: Mail [-sS] [-n srvname] [-o outgoing] [mailboxname "
"[directoryname]]\n");
threadexitsall("usage"); threadexitsall("usage");
} }
void void removeupasfs(void) {
removeupasfs(void)
{
char buf[256]; char buf[256];
if(strcmp(mboxname, "mbox") == 0) if (strcmp(mboxname, "mbox") == 0)
return; return;
snprint(buf, sizeof buf, "close %s", mboxname); snprint(buf, sizeof buf, "close %s", mboxname);
fswrite(mbox.ctlfd, buf, strlen(buf)); fswrite(mbox.ctlfd, buf, strlen(buf));
} }
int int ismaildir(char* s) {
ismaildir(char *s) Dir* d;
{
Dir *d;
int ret; int ret;
d = fsdirstat(mailfs, s); d = fsdirstat(mailfs, s);
if(d == nil) if (d == nil)
return 0; return 0;
ret = d->qid.type & QTDIR; ret = d->qid.type & QTDIR;
free(d); free(d);
return ret; return ret;
} }
void void threadmain(int argc, char* argv[]) {
threadmain(int argc, char *argv[])
{
char *s, *name; char *s, *name;
char err[ERRMAX], *cmd; char err[ERRMAX], *cmd;
int i, newdir; int i, newdir;
@ -83,17 +78,18 @@ threadmain(int argc, char *argv[])
doquote = needsrcquote; doquote = needsrcquote;
quotefmtinstall(); quotefmtinstall();
/* open these early so we won't miss notification of new mail messages while we read mbox */ /* open these early so we won't miss notification of new mail messages while
if((plumbsendfd = plumbopenfid("send", OWRITE|OCEXEC)) == nil) * we read mbox */
if ((plumbsendfd = plumbopenfid("send", OWRITE | OCEXEC)) == nil)
fprint(2, "warning: open plumb/send: %r\n"); fprint(2, "warning: open plumb/send: %r\n");
if((plumbseemailfd = plumbopenfid("seemail", OREAD|OCEXEC)) == nil) if ((plumbseemailfd = plumbopenfid("seemail", OREAD | OCEXEC)) == nil)
fprint(2, "warning: open plumb/seemail: %r\n"); fprint(2, "warning: open plumb/seemail: %r\n");
if((plumbshowmailfd = plumbopenfid("showmail", OREAD|OCEXEC)) == nil) if ((plumbshowmailfd = plumbopenfid("showmail", OREAD | OCEXEC)) == nil)
fprint(2, "warning: open plumb/showmail: %r\n"); fprint(2, "warning: open plumb/showmail: %r\n");
shortmenu = 0; shortmenu = 0;
srvname = "mail"; srvname = "mail";
ARGBEGIN{ ARGBEGIN {
case 's': case 's':
shortmenu = 1; shortmenu = 1;
break; break;
@ -111,41 +107,42 @@ threadmain(int argc, char *argv[])
break; break;
default: default:
usage(); usage();
}ARGEND }
ARGEND
acmefs = nsmount("acme",nil); acmefs = nsmount("acme", nil);
if(acmefs == nil) if (acmefs == nil)
error("cannot mount acme: %r"); error("cannot mount acme: %r");
mailfs = nsmount(srvname, nil); mailfs = nsmount(srvname, nil);
if(mailfs == nil) if (mailfs == nil)
error("cannot mount %s: %r", srvname); error("cannot mount %s: %r", srvname);
name = "mbox"; name = "mbox";
newdir = 1; newdir = 1;
if(argc > 0){ if (argc > 0) {
i = strlen(argv[0]); i = strlen(argv[0]);
if(argc>2 || i==0) if (argc > 2 || i == 0)
usage(); usage();
/* see if the name is that of an existing /mail/fs directory */ /* see if the name is that of an existing /mail/fs directory */
if(argc==1 && argv[0][0] != '/' && ismaildir(argv[0])){ if (argc == 1 && argv[0][0] != '/' && ismaildir(argv[0])) {
name = argv[0]; name = argv[0];
mboxname = estrdup(name); mboxname = estrdup(name);
newdir = 0; newdir = 0;
}else{ } else {
if(argv[0][i-1] == '/') if (argv[0][i - 1] == '/')
argv[0][i-1] = '\0'; argv[0][i - 1] = '\0';
s = strrchr(argv[0], '/'); s = strrchr(argv[0], '/');
if(s == nil) if (s == nil)
mboxname = estrdup(argv[0]); mboxname = estrdup(argv[0]);
else{ else {
*s++ = '\0'; *s++ = '\0';
if(*s == '\0') if (*s == '\0')
usage(); usage();
mailboxdir = argv[0]; mailboxdir = argv[0];
mboxname = estrdup(s); mboxname = estrdup(s);
} }
if(argc > 1) if (argc > 1)
name = argv[1]; name = argv[1];
else else
name = mboxname; name = mboxname;
@ -153,64 +150,65 @@ threadmain(int argc, char *argv[])
} }
user = getenv("user"); user = getenv("user");
if(user == nil) if (user == nil)
user = "none"; user = "none";
home = getenv("home"); home = getenv("home");
if(home == nil) if (home == nil)
home = getenv("HOME"); home = getenv("HOME");
if(home == nil) if (home == nil)
error("can't find $home"); error("can't find $home");
if(mailboxdir == nil) if (mailboxdir == nil)
mailboxdir = estrstrdup(home, "/mail"); mailboxdir = estrstrdup(home, "/mail");
if(outgoing == nil) if (outgoing == nil)
outgoing = estrstrdup(mailboxdir, "/outgoing"); outgoing = estrstrdup(mailboxdir, "/outgoing");
mbox.ctlfd = fsopen(mailfs, estrstrdup(mboxname, "/ctl"), OWRITE); mbox.ctlfd = fsopen(mailfs, estrstrdup(mboxname, "/ctl"), OWRITE);
if(mbox.ctlfd == nil) if (mbox.ctlfd == nil)
error("can't open %s: %r", estrstrdup(mboxname, "/ctl")); error("can't open %s: %r", estrstrdup(mboxname, "/ctl"));
fsname = estrdup(name); fsname = estrdup(name);
if(newdir && argc > 0){ if (newdir && argc > 0) {
s = emalloc(5+strlen(mailboxdir)+strlen(mboxname)+strlen(name)+10+1); s = emalloc(
for(i=0; i<10; i++){ 5 + strlen(mailboxdir) + strlen(mboxname) + strlen(name) + 10 + 1);
for (i = 0; i < 10; i++) {
sprint(s, "open %s/%s %s", mailboxdir, mboxname, fsname); sprint(s, "open %s/%s %s", mailboxdir, mboxname, fsname);
if(fswrite(mbox.ctlfd, s, strlen(s)) >= 0) if (fswrite(mbox.ctlfd, s, strlen(s)) >= 0)
break; break;
err[0] = '\0'; err[0] = '\0';
errstr(err, sizeof err); errstr(err, sizeof err);
if(strstr(err, "mbox name in use") == nil) if (strstr(err, "mbox name in use") == nil)
error("can't create directory %s for mail: %s", name, err); error("can't create directory %s for mail: %s", name, err);
free(fsname); free(fsname);
fsname = emalloc(strlen(name)+10); fsname = emalloc(strlen(name) + 10);
sprint(fsname, "%s-%d", name, i); sprint(fsname, "%s-%d", name, i);
} }
if(i == 10) if (i == 10)
error("can't open %s/%s: %r", mailboxdir, mboxname); error("can't open %s/%s: %r", mailboxdir, mboxname);
free(s); free(s);
} }
s = estrstrdup(fsname, "/"); s = estrstrdup(fsname, "/");
mbox.name = estrstrdup(maildir, s); mbox.name = estrstrdup(maildir, s);
mbox.level= 0; mbox.level = 0;
readmbox(&mbox, maildir, s); readmbox(&mbox, maildir, s);
home = getenv("home"); home = getenv("home");
if(home == nil) if (home == nil)
home = "/"; home = "/";
wbox = newwindow(); wbox = newwindow();
winname(wbox, mbox.name); winname(wbox, mbox.name);
wintagwrite(wbox, "Put Mail Delmesg ", 3+1+4+1+7+1); wintagwrite(wbox, "Put Mail Delmesg ", 3 + 1 + 4 + 1 + 7 + 1);
threadcreate(mainctl, wbox, STACK); threadcreate(mainctl, wbox, STACK);
fmtstrinit(&fmt); fmtstrinit(&fmt);
fmtprint(&fmt, "Mail"); fmtprint(&fmt, "Mail");
if(shortmenu) if (shortmenu)
fmtprint(&fmt, " -%c", "sS"[shortmenu-1]); fmtprint(&fmt, " -%c", "sS"[shortmenu - 1]);
if(outgoing) if (outgoing)
fmtprint(&fmt, " -o %s", outgoing); fmtprint(&fmt, " -o %s", outgoing);
fmtprint(&fmt, " %s", name); fmtprint(&fmt, " %s", name);
cmd = fmtstrflush(&fmt); cmd = fmtstrflush(&fmt);
if(cmd == nil) if (cmd == nil)
sysfatal("out of memory"); sysfatal("out of memory");
winsetdump(wbox, "/acme/mail", cmd); winsetdump(wbox, "/acme/mail", cmd);
mbox.w = wbox; mbox.w = wbox;
@ -218,16 +216,16 @@ threadmain(int argc, char *argv[])
mesgmenu(wbox, &mbox); mesgmenu(wbox, &mbox);
winclean(wbox); winclean(wbox);
/* wctlfd = open("/dev/wctl", OWRITE|OCEXEC); /* for acme window */ /* wctlfd = open("/dev/wctl", OWRITE|OCEXEC); /* for acme window */
wctlfd = -1; wctlfd = -1;
cplumb = chancreate(sizeof(Plumbmsg*), 0); cplumb = chancreate(sizeof(Plumbmsg*), 0);
cplumbshow = chancreate(sizeof(Plumbmsg*), 0); cplumbshow = chancreate(sizeof(Plumbmsg*), 0);
if(strcmp(name, "mbox") == 0){ if (strcmp(name, "mbox") == 0) {
/* /*
* Avoid creating multiple windows to send mail by only accepting * Avoid creating multiple windows to send mail by only accepting
* sendmail plumb messages if we're reading the main mailbox. * sendmail plumb messages if we're reading the main mailbox.
*/ */
plumbsendmailfd = plumbopenfid("sendmail", OREAD|OCEXEC); plumbsendmailfd = plumbopenfid("sendmail", OREAD | OCEXEC);
cplumbsend = chancreate(sizeof(Plumbmsg*), 0); cplumbsend = chancreate(sizeof(Plumbmsg*), 0);
proccreate(plumbsendproc, nil, STACK); proccreate(plumbsendproc, nil, STACK);
threadcreate(plumbsendthread, nil, STACK); threadcreate(plumbsendthread, nil, STACK);
@ -241,120 +239,106 @@ threadmain(int argc, char *argv[])
plumbthread(); plumbthread();
} }
void void plumbproc(void* v) {
plumbproc(void* v) Plumbmsg* m;
{
Plumbmsg *m;
threadsetname("plumbproc"); threadsetname("plumbproc");
for(;;){ for (;;) {
m = plumbrecvfid(plumbseemailfd); m = plumbrecvfid(plumbseemailfd);
sendp(cplumb, m); sendp(cplumb, m);
if(m == nil) if (m == nil)
threadexits(nil); threadexits(nil);
} }
} }
void void plumbshowproc(void* v) {
plumbshowproc(void* v) Plumbmsg* m;
{
Plumbmsg *m;
threadsetname("plumbshowproc"); threadsetname("plumbshowproc");
for(;;){ for (;;) {
m = plumbrecvfid(plumbshowmailfd); m = plumbrecvfid(plumbshowmailfd);
sendp(cplumbshow, m); sendp(cplumbshow, m);
if(m == nil) if (m == nil)
threadexits(nil); threadexits(nil);
} }
} }
void void plumbsendproc(void* v) {
plumbsendproc(void* v) Plumbmsg* m;
{
Plumbmsg *m;
threadsetname("plumbsendproc"); threadsetname("plumbsendproc");
for(;;){ for (;;) {
m = plumbrecvfid(plumbsendmailfd); m = plumbrecvfid(plumbsendmailfd);
sendp(cplumbsend, m); sendp(cplumbsend, m);
if(m == nil) if (m == nil)
threadexits(nil); threadexits(nil);
} }
} }
void void newmesg(char* name, char* digest) {
newmesg(char *name, char *digest) Dir* d;
{
Dir *d;
if(strncmp(name, mbox.name, strlen(mbox.name)) != 0) if (strncmp(name, mbox.name, strlen(mbox.name)) != 0)
return; /* message is about another mailbox */ return; /* message is about another mailbox */
if(mesglookupfile(&mbox, name, digest) != nil) if (mesglookupfile(&mbox, name, digest) != nil)
return; return;
if(strncmp(name, "Mail/", 5) == 0) if (strncmp(name, "Mail/", 5) == 0)
name += 5; name += 5;
d = fsdirstat(mailfs, name); d = fsdirstat(mailfs, name);
if(d == nil) if (d == nil)
return; return;
if(mesgadd(&mbox, mbox.name, d, digest)) if (mesgadd(&mbox, mbox.name, d, digest))
mesgmenunew(wbox, &mbox); mesgmenunew(wbox, &mbox);
free(d); free(d);
} }
void void showmesg(char* name, char* digest) {
showmesg(char *name, char *digest) char* n;
{ char* mb;
char *n;
char *mb;
mb = mbox.name; mb = mbox.name;
if(strncmp(name, mb, strlen(mb)) != 0) if (strncmp(name, mb, strlen(mb)) != 0)
return; /* message is about another mailbox */ return; /* message is about another mailbox */
n = estrdup(name+strlen(mb)); n = estrdup(name + strlen(mb));
if(n[strlen(n)-1] != '/') if (n[strlen(n) - 1] != '/')
n = egrow(n, "/", nil); n = egrow(n, "/", nil);
mesgopen(&mbox, mbox.name, name+strlen(mb), nil, 1, digest); mesgopen(&mbox, mbox.name, name + strlen(mb), nil, 1, digest);
free(n); free(n);
} }
void void delmesg(char* name, char* digest, int dodel, char* save) {
delmesg(char *name, char *digest, int dodel, char *save) Message* m;
{
Message *m;
m = mesglookupfile(&mbox, name, digest); m = mesglookupfile(&mbox, name, digest);
if(m != nil){ if (m != nil) {
if(save) if (save)
mesgcommand(m, estrstrdup("Save ", save)); mesgcommand(m, estrstrdup("Save ", save));
if(dodel) if (dodel)
mesgmenumarkdel(wbox, &mbox, m, 1); mesgmenumarkdel(wbox, &mbox, m, 1);
else{ else {
/* notification came from plumber - message is gone */ /* notification came from plumber - message is gone */
mesgmenudel(wbox, &mbox, m); mesgmenudel(wbox, &mbox, m);
if(!m->opened) if (!m->opened)
mesgdel(&mbox, m); mesgdel(&mbox, m);
} }
} }
} }
void void plumbthread(void) {
plumbthread(void) Plumbmsg* m;
{ Plumbattr* a;
Plumbmsg *m;
Plumbattr *a;
char *type, *digest; char *type, *digest;
threadsetname("plumbthread"); threadsetname("plumbthread");
while((m = recvp(cplumb)) != nil){ while ((m = recvp(cplumb)) != nil) {
a = m->attr; a = m->attr;
digest = plumblookup(a, "digest"); digest = plumblookup(a, "digest");
type = plumblookup(a, "mailtype"); type = plumblookup(a, "mailtype");
if(type == nil) if (type == nil)
fprint(2, "Mail: plumb message with no mailtype attribute\n"); fprint(2, "Mail: plumb message with no mailtype attribute\n");
else if(strcmp(type, "new") == 0) else if (strcmp(type, "new") == 0)
newmesg(m->data, digest); newmesg(m->data, digest);
else if(strcmp(type, "delete") == 0) else if (strcmp(type, "delete") == 0)
delmesg(m->data, digest, 0, nil); delmesg(m->data, digest, 0, nil);
else else
fprint(2, "Mail: unknown plumb attribute %s\n", type); fprint(2, "Mail: unknown plumb attribute %s\n", type);
@ -363,116 +347,111 @@ plumbthread(void)
threadexits(nil); threadexits(nil);
} }
void void plumbshowthread(void* v) {
plumbshowthread(void *v) Plumbmsg* m;
{
Plumbmsg *m;
USED(v); USED(v);
threadsetname("plumbshowthread"); threadsetname("plumbshowthread");
while((m = recvp(cplumbshow)) != nil){ while ((m = recvp(cplumbshow)) != nil) {
showmesg(m->data, plumblookup(m->attr, "digest")); showmesg(m->data, plumblookup(m->attr, "digest"));
plumbfree(m); plumbfree(m);
} }
threadexits(nil); threadexits(nil);
} }
void void plumbsendthread(void* v) {
plumbsendthread(void *v) Plumbmsg* m;
{
Plumbmsg *m;
USED(v); USED(v);
threadsetname("plumbsendthread"); threadsetname("plumbsendthread");
while((m = recvp(cplumbsend)) != nil){ while ((m = recvp(cplumbsend)) != nil) {
mkreply(nil, "Mail", m->data, m->attr, nil); mkreply(nil, "Mail", m->data, m->attr, nil);
plumbfree(m); plumbfree(m);
} }
threadexits(nil); threadexits(nil);
} }
int int mboxcommand(Window* w, char* s) {
mboxcommand(Window *w, char *s)
{
char *args[10], **targs, *save; char *args[10], **targs, *save;
Window *sbox; Window* sbox;
Message *m, *next; Message *m, *next;
int ok, nargs, i, j; int ok, nargs, i, j;
CFid *searchfd; CFid* searchfd;
char buf[128], *res; char buf[128], *res;
nargs = tokenize(s, args, nelem(args)); nargs = tokenize(s, args, nelem(args));
if(nargs == 0) if (nargs == 0)
return 0; return 0;
if(strcmp(args[0], "Mail") == 0){ if (strcmp(args[0], "Mail") == 0) {
if(nargs == 1) if (nargs == 1)
mkreply(nil, "Mail", "", nil, nil); mkreply(nil, "Mail", "", nil, nil);
else else
mkreply(nil, "Mail", args[1], nil, nil); mkreply(nil, "Mail", args[1], nil, nil);
return 1; return 1;
} }
if(strcmp(s, "Del") == 0){ if (strcmp(s, "Del") == 0) {
if(mbox.dirty){ if (mbox.dirty) {
mbox.dirty = 0; mbox.dirty = 0;
fprint(2, "mail: mailbox not written\n"); fprint(2, "mail: mailbox not written\n");
return 1; return 1;
} }
if(w != mbox.w){ if (w != mbox.w) {
windel(w, 1); windel(w, 1);
return 1; return 1;
} }
ok = 1; ok = 1;
for(m=mbox.head; m!=nil; m=next){ for (m = mbox.head; m != nil; m = next) {
next = m->next; next = m->next;
if(m->w){ if (m->w) {
if(windel(m->w, 0)) if (windel(m->w, 0))
m->w = nil; m->w = nil;
else else
ok = 0; ok = 0;
} }
} }
for(m=replies.head; m!=nil; m=next){ for (m = replies.head; m != nil; m = next) {
next = m->next; next = m->next;
if(m->w){ if (m->w) {
if(windel(m->w, 0)) if (windel(m->w, 0))
m->w = nil; m->w = nil;
else else
ok = 0; ok = 0;
} }
} }
if(ok){ if (ok) {
windel(w, 1); windel(w, 1);
removeupasfs(); removeupasfs();
threadexitsall(nil); threadexitsall(nil);
} }
return 1; return 1;
} }
if(strcmp(s, "Put") == 0){ if (strcmp(s, "Put") == 0) {
rewritembox(wbox, &mbox); rewritembox(wbox, &mbox);
return 1; return 1;
} }
if(strcmp(s, "Get") == 0){ if (strcmp(s, "Get") == 0) {
fswrite(mbox.ctlfd, "refresh", 7); fswrite(mbox.ctlfd, "refresh", 7);
return 1; return 1;
} }
if(strcmp(s, "Delmesg") == 0){ if (strcmp(s, "Delmesg") == 0) {
save = nil; save = nil;
if(nargs > 1) if (nargs > 1)
save = args[1]; save = args[1];
s = winselection(w); s = winselection(w);
if(s == nil) if (s == nil)
return 1; return 1;
nargs = 1; nargs = 1;
for(i=0; s[i]; i++) for (i = 0; s[i]; i++)
if(s[i] == '\n') if (s[i] == '\n')
nargs++; nargs++;
targs = emalloc(nargs*sizeof(char*)); /* could be too many for a local array */ targs =
emalloc(nargs * sizeof(char*)); /* could be too many for a local array */
nargs = getfields(s, targs, nargs, 1, "\n"); nargs = getfields(s, targs, nargs, 1, "\n");
for(i=0; i<nargs; i++){ for (i = 0; i < nargs; i++) {
if(!isdigit(targs[i][0])) if (!isdigit(targs[i][0]))
continue; continue;
j = atoi(targs[i]); /* easy way to parse the number! */ j = atoi(targs[i]); /* easy way to parse the number! */
if(j == 0) if (j == 0)
continue; continue;
snprint(buf, sizeof buf, "%s%d", mbox.name, j); snprint(buf, sizeof buf, "%s%d", mbox.name, j);
delmesg(buf, nil, 1, save); delmesg(buf, nil, 1, save);
@ -481,20 +460,20 @@ mboxcommand(Window *w, char *s)
free(targs); free(targs);
return 1; return 1;
} }
if(strcmp(s, "Search") == 0){ if (strcmp(s, "Search") == 0) {
if(nargs <= 1) if (nargs <= 1)
return 1; return 1;
s = estrstrdup(mboxname, "/search"); s = estrstrdup(mboxname, "/search");
searchfd = fsopen(mailfs, s, ORDWR); searchfd = fsopen(mailfs, s, ORDWR);
if(searchfd == nil) if (searchfd == nil)
return 1; return 1;
save = estrdup(args[1]); save = estrdup(args[1]);
for(i=2; i<nargs; i++) for (i = 2; i < nargs; i++)
save = eappend(save, " ", args[i]); save = eappend(save, " ", args[i]);
fswrite(searchfd, save, strlen(save)); fswrite(searchfd, save, strlen(save));
fsseek(searchfd, 0, 0); fsseek(searchfd, 0, 0);
j = fsread(searchfd, buf, sizeof buf - 1); j = fsread(searchfd, buf, sizeof buf - 1);
if(j == 0){ if (j == 0) {
fprint(2, "[%s] search %s: no results found\n", mboxname, save); fprint(2, "[%s] search %s: no results found\n", mboxname, save);
fsclose(searchfd); fsclose(searchfd);
free(save); free(save);
@ -504,7 +483,7 @@ mboxcommand(Window *w, char *s)
buf[j] = '\0'; buf[j] = '\0';
res = estrdup(buf); res = estrdup(buf);
j = fsread(searchfd, buf, sizeof buf - 1); j = fsread(searchfd, buf, sizeof buf - 1);
for(; j != 0; j = fsread(searchfd, buf, sizeof buf - 1), buf[j] = '\0') for (; j != 0; j = fsread(searchfd, buf, sizeof buf - 1), buf[j] = '\0')
res = eappend(res, "", buf); res = eappend(res, "", buf);
fsclose(searchfd); fsclose(searchfd);
@ -517,16 +496,18 @@ mboxcommand(Window *w, char *s)
/* show results in reverse order */ /* show results in reverse order */
m = mbox.tail; m = mbox.tail;
save = nil; save = nil;
for(s=strrchr(res, ' '); s!=nil || save!=res; s=strrchr(res, ' ')){ for (s = strrchr(res, ' '); s != nil || save != res;
if(s != nil){ s = strrchr(res, ' ')) {
save = s+1; if (s != nil) {
save = s + 1;
*s = '\0'; *s = '\0';
} } else
else save = res; save = res;
save = estrstrdup(save, "/"); save = estrstrdup(save, "/");
for(; m && strcmp(save, m->name) != 0; m=m->prev); for (; m && strcmp(save, m->name) != 0; m = m->prev)
;
free(save); free(save);
if(m == nil) if (m == nil)
break; break;
fsprint(sbox->body, "%s%s\n", m->name, info(m, 0, 0)); fsprint(sbox->body, "%s%s\n", m->name, info(m, 0, 0));
m = m->prev; m = m->prev;
@ -539,10 +520,8 @@ mboxcommand(Window *w, char *s)
return 0; return 0;
} }
void void mainctl(void* v) {
mainctl(void *v) Window* w;
{
Window *w;
Event *e, *e2, *eq, *ea; Event *e, *e2, *eq, *ea;
int na, nopen; int na, nopen;
char *s, *t, *buf; char *s, *t, *buf;
@ -551,9 +530,9 @@ mainctl(void *v)
winincref(w); winincref(w);
proccreate(wineventproc, w, STACK); proccreate(wineventproc, w, STACK);
for(;;){ for (;;) {
e = recvp(w->cevent); e = recvp(w->cevent);
switch(e->c1){ switch (e->c1) {
default: default:
Unknown: Unknown:
print("unknown message %c%c\n", e->c1, e->c2); print("unknown message %c%c\n", e->c1, e->c2);
@ -569,32 +548,32 @@ mainctl(void *v)
break; break;
case 'M': case 'M':
switch(e->c2){ switch (e->c2) {
case 'x': case 'x':
case 'X': case 'X':
ea = nil; ea = nil;
e2 = nil; e2 = nil;
if(e->flag & 2) if (e->flag & 2)
e2 = recvp(w->cevent); e2 = recvp(w->cevent);
if(e->flag & 8){ if (e->flag & 8) {
ea = recvp(w->cevent); ea = recvp(w->cevent);
na = ea->nb; na = ea->nb;
recvp(w->cevent); recvp(w->cevent);
}else } else
na = 0; na = 0;
s = e->b; s = e->b;
/* if it's a known command, do it */ /* if it's a known command, do it */
if((e->flag&2) && e->nb==0) if ((e->flag & 2) && e->nb == 0)
s = e2->b; s = e2->b;
if(na){ if (na) {
t = emalloc(strlen(s)+1+na+1); t = emalloc(strlen(s) + 1 + na + 1);
sprint(t, "%s %s", s, ea->b); sprint(t, "%s %s", s, ea->b);
s = t; s = t;
} }
/* if it's a long message, it can't be for us anyway */ /* if it's a long message, it can't be for us anyway */
if(!mboxcommand(w, s)) /* send it back */ if (!mboxcommand(w, s)) /* send it back */
winwriteevent(w, e); winwriteevent(w, e);
if(na) if (na)
free(s); free(s);
break; break;
@ -602,29 +581,29 @@ mainctl(void *v)
case 'L': case 'L':
buf = nil; buf = nil;
eq = e; eq = e;
if(e->flag & 2){ if (e->flag & 2) {
e2 = recvp(w->cevent); e2 = recvp(w->cevent);
eq = e2; eq = e2;
} }
s = eq->b; s = eq->b;
if(eq->q1>eq->q0 && eq->nb==0){ if (eq->q1 > eq->q0 && eq->nb == 0) {
buf = emalloc((eq->q1-eq->q0)*UTFmax+1); buf = emalloc((eq->q1 - eq->q0) * UTFmax + 1);
winread(w, eq->q0, eq->q1, buf); winread(w, eq->q0, eq->q1, buf);
s = buf; s = buf;
} }
nopen = 0; nopen = 0;
do{ do {
/* skip 'deleted' string if present' */ /* skip 'deleted' string if present' */
if(strncmp(s, deleted, strlen(deleted)) == 0) if (strncmp(s, deleted, strlen(deleted)) == 0)
s += strlen(deleted); s += strlen(deleted);
/* skip mail box name if present */ /* skip mail box name if present */
if(strncmp(s, mbox.name, strlen(mbox.name)) == 0) if (strncmp(s, mbox.name, strlen(mbox.name)) == 0)
s += strlen(mbox.name); s += strlen(mbox.name);
nopen += mesgopen(&mbox, mbox.name, s, nil, 0, nil); nopen += mesgopen(&mbox, mbox.name, s, nil, 0, nil);
while(*s!='\0' && *s++!='\n') while (*s != '\0' && *s++ != '\n')
; ;
}while(*s); } while (*s);
if(nopen == 0) /* send it back */ if (nopen == 0) /* send it back */
winwriteevent(w, e); winwriteevent(w, e);
free(buf); free(buf);
break; break;
@ -641,4 +620,3 @@ mainctl(void *v)
} }
} }
} }

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

View file

@ -9,56 +9,56 @@
static int replyid; static int replyid;
int int quote(Message* m, CFid* fid, char* dir, char* quotetext) {
quote(Message *m, CFid *fid, char *dir, char *quotetext)
{
char *body, *type; char *body, *type;
int i, n, nlines; int i, n, nlines;
char **lines; char** lines;
if(quotetext){ if (quotetext) {
body = quotetext; body = quotetext;
n = strlen(body); n = strlen(body);
type = nil; type = nil;
}else{ } else {
/* look for first textual component to quote */ /* look for first textual component to quote */
type = readfile(dir, "type", &n); type = readfile(dir, "type", &n);
if(type == nil){ if (type == nil) {
print("no type in %s\n", dir); print("no type in %s\n", dir);
return 0; return 0;
} }
if(strncmp(type, "multipart/", 10)==0 || strncmp(type, "message/", 8)==0){ if (
strncmp(type, "multipart/", 10) == 0 ||
strncmp(type, "message/", 8) == 0) {
dir = estrstrdup(dir, "1/"); dir = estrstrdup(dir, "1/");
if(quote(m, fid, dir, nil)){ if (quote(m, fid, dir, nil)) {
free(type); free(type);
free(dir); free(dir);
return 1; return 1;
} }
free(dir); free(dir);
} }
if(strncmp(type, "text", 4) != 0){ if (strncmp(type, "text", 4) != 0) {
free(type); free(type);
return 0; return 0;
} }
body = readbody(m->type, dir, &n); body = readbody(m->type, dir, &n);
if(body == nil) if (body == nil)
return 0; return 0;
} }
nlines = 0; nlines = 0;
for(i=0; i<n; i++) for (i = 0; i < n; i++)
if(body[i] == '\n') if (body[i] == '\n')
nlines++; nlines++;
nlines++; nlines++;
lines = emalloc(nlines*sizeof(char*)); lines = emalloc(nlines * sizeof(char*));
nlines = getfields(body, lines, nlines, 0, "\n"); nlines = getfields(body, lines, nlines, 0, "\n");
/* delete leading and trailing blank lines */ /* delete leading and trailing blank lines */
i = 0; i = 0;
while(i<nlines && lines[i][0]=='\0') while (i < nlines && lines[i][0] == '\0')
i++; i++;
while(i<nlines && lines[nlines-1][0]=='\0') while (i < nlines && lines[nlines - 1][0] == '\0')
nlines--; nlines--;
while(i < nlines){ while (i < nlines) {
fsprint(fid, ">%s%s\n", lines[i][0]=='>'? "" : " ", lines[i]); fsprint(fid, ">%s%s\n", lines[i][0] == '>' ? "" : " ", lines[i]);
i++; i++;
} }
free(lines); free(lines);
@ -67,21 +67,20 @@ quote(Message *m, CFid *fid, char *dir, char *quotetext)
return 1; return 1;
} }
void void mkreply(
mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext) Message* m, char* label, char* to, Plumbattr* attr, char* quotetext) {
{
char buf[100]; char buf[100];
CFid *fd; CFid* fd;
Message *r; Message* r;
char *dir, *t; char *dir, *t;
int quotereply; int quotereply;
Plumbattr *a; Plumbattr* a;
quotereply = (label[0] == 'Q'); quotereply = (label[0] == 'Q');
if(quotereply && m && m->replywinid > 0){ if (quotereply && m && m->replywinid > 0) {
snprint(buf, sizeof buf, "%d/body", m->replywinid); snprint(buf, sizeof buf, "%d/body", m->replywinid);
if((fd = fsopen(acmefs, buf, OWRITE)) != nil){ if ((fd = fsopen(acmefs, buf, OWRITE)) != nil) {
dir = estrstrdup(mbox.name, m->name); dir = estrstrdup(mbox.name, m->name);
quote(m, fd, dir, quotetext); quote(m, fd, dir, quotetext);
free(dir); free(dir);
@ -91,67 +90,69 @@ mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext)
r = emalloc(sizeof(Message)); r = emalloc(sizeof(Message));
r->isreply = 1; r->isreply = 1;
if(m != nil) if (m != nil)
r->replyname = estrdup(m->name); r->replyname = estrdup(m->name);
r->next = replies.head; r->next = replies.head;
r->prev = nil; r->prev = nil;
if(replies.head != nil) if (replies.head != nil)
replies.head->prev = r; replies.head->prev = r;
replies.head = r; replies.head = r;
if(replies.tail == nil) if (replies.tail == nil)
replies.tail = r; replies.tail = r;
r->name = emalloc(strlen(mbox.name)+strlen(label)+10); r->name = emalloc(strlen(mbox.name) + strlen(label) + 10);
sprint(r->name, "%s%s%d", mbox.name, label, ++replyid); sprint(r->name, "%s%s%d", mbox.name, label, ++replyid);
r->w = newwindow(); r->w = newwindow();
if(m) if (m)
m->replywinid = r->w->id; m->replywinid = r->w->id;
winname(r->w, r->name); winname(r->w, r->name);
ctlprint(r->w->ctl, "cleartag"); ctlprint(r->w->ctl, "cleartag");
wintagwrite(r->w, "fmt Look Post Undo", 4+5+5+4); wintagwrite(r->w, "fmt Look Post Undo", 4 + 5 + 5 + 4);
r->tagposted = 1; r->tagposted = 1;
threadcreate(mesgctl, r, STACK); threadcreate(mesgctl, r, STACK);
winopenbody(r->w, OWRITE); winopenbody(r->w, OWRITE);
if(to!=nil && to[0]!='\0') if (to != nil && to[0] != '\0')
fsprint(r->w->body, "%s\n", to); fsprint(r->w->body, "%s\n", to);
for(a=attr; a; a=a->next) for (a = attr; a; a = a->next)
fsprint(r->w->body, "%s: %s\n", a->name, a->value); fsprint(r->w->body, "%s: %s\n", a->name, a->value);
dir = nil; dir = nil;
if(m != nil){ if (m != nil) {
dir = estrstrdup(mbox.name, m->name); dir = estrstrdup(mbox.name, m->name);
if(to == nil && attr == nil){ if (to == nil && attr == nil) {
/* Reply goes to replyto; Reply all goes to From and To and CC */ /* Reply goes to replyto; Reply all goes to From and To and CC */
if(strstr(label, "all") == nil) if (strstr(label, "all") == nil)
fsprint(r->w->body, "To: %s\n", m->replyto); fsprint(r->w->body, "To: %s\n", m->replyto);
else{ /* Replyall */ else { /* Replyall */
if(strlen(m->from) > 0) if (strlen(m->from) > 0)
fsprint(r->w->body, "To: %s\n", m->from); fsprint(r->w->body, "To: %s\n", m->from);
if(strlen(m->to) > 0) if (strlen(m->to) > 0)
fsprint(r->w->body, "To: %s\n", m->to); fsprint(r->w->body, "To: %s\n", m->to);
if(strlen(m->cc) > 0) if (strlen(m->cc) > 0)
fsprint(r->w->body, "CC: %s\n", m->cc); fsprint(r->w->body, "CC: %s\n", m->cc);
} }
} }
if(strlen(m->subject) > 0){ if (strlen(m->subject) > 0) {
t = "Subject: Re: "; t = "Subject: Re: ";
if(strlen(m->subject) >= 3) if (strlen(m->subject) >= 3)
if(tolower(m->subject[0])=='r' && tolower(m->subject[1])=='e' && m->subject[2]==':') if (
tolower(m->subject[0]) == 'r' && tolower(m->subject[1]) == 'e' &&
m->subject[2] == ':')
t = "Subject: "; t = "Subject: ";
fsprint(r->w->body, "%s%s\n", t, m->subject); fsprint(r->w->body, "%s%s\n", t, m->subject);
} }
if(!quotereply){ if (!quotereply) {
fsprint(r->w->body, "Include: %sraw\n", dir); fsprint(r->w->body, "Include: %sraw\n", dir);
free(dir); free(dir);
} }
} }
fsprint(r->w->body, "\n"); fsprint(r->w->body, "\n");
if(m == nil) if (m == nil)
fsprint(r->w->body, "\n"); fsprint(r->w->body, "\n");
else if(quotereply){ else if (quotereply) {
quote(m, r->w->body, dir, quotetext); quote(m, r->w->body, dir, quotetext);
free(dir); free(dir);
} }
winclosebody(r->w); winclosebody(r->w);
if(m==nil && (to==nil || to[0]=='\0')) if (m == nil && (to == nil || to[0] == '\0'))
winselect(r->w, "0", 0); winselect(r->w, "0", 0);
else else
winselect(r->w, "$", 0); winselect(r->w, "$", 0);
@ -159,14 +160,12 @@ mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext)
windormant(r->w); windormant(r->w);
} }
void void delreply(Message* m) {
delreply(Message *m) if (m->next == nil)
{
if(m->next == nil)
replies.tail = m->prev; replies.tail = m->prev;
else else
m->next->prev = m->prev; m->next->prev = m->prev;
if(m->prev == nil) if (m->prev == nil)
replies.head = m->next; replies.head = m->next;
else else
m->prev->next = m->next; m->prev->next = m->next;
@ -174,20 +173,19 @@ delreply(Message *m)
free(m); free(m);
} }
/* copy argv to stack and free the incoming strings, so we don't leak argument vectors */ /* copy argv to stack and free the incoming strings, so we don't leak argument
void * vectors */
buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR]) void buildargv(char** inargv, char* argv[NARGS + 1], char args[NARGCHAR]) {
{
int i, n; int i, n;
char *s, *a; char *s, *a;
s = args; s = args;
for(i=0; i<NARGS; i++){ for (i = 0; i < NARGS; i++) {
a = inargv[i]; a = inargv[i];
if(a == nil) if (a == nil)
break; break;
n = strlen(a)+1; n = strlen(a) + 1;
if((s-args)+n >= NARGCHAR) /* too many characters */ if ((s - args) + n >= NARGCHAR) /* too many characters */
break; break;
argv[i] = s; argv[i] = s;
memmove(s, a, n); memmove(s, a, n);
@ -197,13 +195,11 @@ buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
argv[i] = nil; argv[i] = nil;
} }
void void execproc(void* v) {
execproc(void *v) struct Exec* e;
{
struct Exec *e;
int p[2], q[2]; int p[2], q[2];
char *prog; char* prog;
char *argv[NARGS+1], args[NARGCHAR]; char *argv[NARGS + 1], args[NARGCHAR];
int fd[3]; int fd[3];
e = v; e = v;
@ -214,7 +210,7 @@ execproc(void *v)
prog = e->prog; /* known not to be malloc'ed */ prog = e->prog; /* known not to be malloc'ed */
fd[0] = dup(p[0], -1); fd[0] = dup(p[0], -1);
if(q[0]) if (q[0])
fd[1] = dup(q[1], -1); fd[1] = dup(q[1], -1);
else else
fd[1] = dup(1, -1); fd[1] = dup(1, -1);
@ -234,76 +230,53 @@ execproc(void *v)
threadexits("can't exec"); threadexits("can't exec");
} }
enum{ enum { ATTACH, BCC, CC, FROM, INCLUDE, TO };
ATTACH,
BCC,
CC,
FROM,
INCLUDE,
TO
};
char *headers[] = { char* headers[] = {"attach:", "bcc:", "cc:", "from:", "include:", "to:", nil};
"attach:",
"bcc:",
"cc:",
"from:",
"include:",
"to:",
nil
};
int int whichheader(char* h) {
whichheader(char *h)
{
int i; int i;
for(i=0; headers[i]!=nil; i++) for (i = 0; headers[i] != nil; i++)
if(cistrcmp(h, headers[i]) == 0) if (cistrcmp(h, headers[i]) == 0)
return i; return i;
return -1; return -1;
} }
char *tolist[200]; char* tolist[200];
char *cclist[200]; char* cclist[200];
char *bcclist[200]; char* bcclist[200];
int ncc, nbcc, nto; int ncc, nbcc, nto;
char *attlist[200]; char* attlist[200];
char included[200]; char included[200];
int int addressed(char* name) {
addressed(char *name)
{
int i; int i;
for(i=0; i<nto; i++) for (i = 0; i < nto; i++)
if(strcmp(name, tolist[i]) == 0) if (strcmp(name, tolist[i]) == 0)
return 1; return 1;
for(i=0; i<ncc; i++) for (i = 0; i < ncc; i++)
if(strcmp(name, cclist[i]) == 0) if (strcmp(name, cclist[i]) == 0)
return 1; return 1;
for(i=0; i<nbcc; i++) for (i = 0; i < nbcc; i++)
if(strcmp(name, bcclist[i]) == 0) if (strcmp(name, bcclist[i]) == 0)
return 1; return 1;
return 0; return 0;
} }
char* char* skipbl(char* s, char* e) {
skipbl(char *s, char *e) while (s < e) {
{ if (*s != ' ' && *s != '\t' && *s != ',')
while(s < e){
if(*s!=' ' && *s!='\t' && *s!=',')
break; break;
s++; s++;
} }
return s; return s;
} }
char* char* findbl(char* s, char* e) {
findbl(char *s, char *e) while (s < e) {
{ if (*s == ' ' || *s == '\t' || *s == ',')
while(s < e){
if(*s==' ' || *s=='\t' || *s==',')
break; break;
s++; s++;
} }
@ -311,75 +284,70 @@ findbl(char *s, char *e)
} }
/* /*
* comma-separate possibly blank-separated strings in line; e points before newline * comma-separate possibly blank-separated strings in line; e points before
* newline
*/ */
void void commas(char* s, char* e) {
commas(char *s, char *e) char* t;
{
char *t;
/* may have initial blanks */ /* may have initial blanks */
s = skipbl(s, e); s = skipbl(s, e);
while(s < e){ while (s < e) {
s = findbl(s, e); s = findbl(s, e);
if(s == e) if (s == e)
break; break;
t = skipbl(s, e); t = skipbl(s, e);
if(t == e) /* no more words */ if (t == e) /* no more words */
break; break;
/* patch comma */ /* patch comma */
*s++ = ','; *s++ = ',';
while(s < t) while (s < t)
*s++ = ' '; *s++ = ' ';
} }
} }
int int print2(int fd, int ofd, char* fmt, ...) {
print2(int fd, int ofd, char *fmt, ...)
{
int m, n; int m, n;
char *s; char* s;
va_list arg; va_list arg;
va_start(arg, fmt); va_start(arg, fmt);
s = vsmprint(fmt, arg); s = vsmprint(fmt, arg);
va_end(arg); va_end(arg);
if(s == nil) if (s == nil)
return -1; return -1;
m = strlen(s); m = strlen(s);
n = write(fd, s, m); n = write(fd, s, m);
if(ofd > 0) if (ofd > 0)
write(ofd, s, m); write(ofd, s, m);
return n; return n;
} }
void void write2(int fd, int ofd, char* buf, int n, int nofrom) {
write2(int fd, int ofd, char *buf, int n, int nofrom)
{
char *from, *p; char *from, *p;
int m; int m;
write(fd, buf, n); write(fd, buf, n);
if(ofd <= 0) if (ofd <= 0)
return; return;
if(nofrom == 0){ if (nofrom == 0) {
write(ofd, buf, n); write(ofd, buf, n);
return; return;
} }
/* need to escape leading From lines to avoid corrupting 'outgoing' mailbox */ /* need to escape leading From lines to avoid corrupting 'outgoing' mailbox */
for(p=buf; *p; p+=m){ for (p = buf; *p; p += m) {
from = cistrstr(p, "from"); from = cistrstr(p, "from");
if(from == nil) if (from == nil)
m = n; m = n;
else else
m = from - p; m = from - p;
if(m > 0) if (m > 0)
write(ofd, p, m); write(ofd, p, m);
if(from){ if (from) {
if(p==buf || from[-1]=='\n') if (p == buf || from[-1] == '\n')
write(ofd, " ", 1); /* escape with space if From is at start of line */ write(ofd, " ", 1); /* escape with space if From is at start of line */
write(ofd, from, 4); write(ofd, from, 4);
m += 4; m += 4;
@ -388,13 +356,11 @@ write2(int fd, int ofd, char *buf, int n, int nofrom)
} }
} }
void void mesgsend(Message* m) {
mesgsend(Message *m)
{
char *s, *body, *to; char *s, *body, *to;
int i, j, h, n, natt, p[2]; int i, j, h, n, natt, p[2];
struct Exec *e; struct Exec* e;
Channel *sync; Channel* sync;
int first, nfld, delit, ofd; int first, nfld, delit, ofd;
char *copy, *fld[100], *now; char *copy, *fld[100], *now;
@ -406,83 +372,83 @@ mesgsend(Message *m)
nbcc = 0; nbcc = 0;
first = 1; first = 1;
to = body; to = body;
for(;;){ for (;;) {
for(s=to; *s!='\n'; s++) for (s = to; *s != '\n'; s++)
if(*s == '\0'){ if (*s == '\0') {
free(body); free(body);
return; return;
} }
if(s++ == to) /* blank line */ if (s++ == to) /* blank line */
break; break;
/* make copy of line to tokenize */ /* make copy of line to tokenize */
copy = emalloc(s-to); copy = emalloc(s - to);
memmove(copy, to, s-to); memmove(copy, to, s - to);
copy[s-to-1] = '\0'; copy[s - to - 1] = '\0';
nfld = tokenizec(copy, fld, nelem(fld), ", \t"); nfld = tokenizec(copy, fld, nelem(fld), ", \t");
if(nfld == 0){ if (nfld == 0) {
free(copy); free(copy);
break; break;
} }
n -= s-to; n -= s - to;
switch(h = whichheader(fld[0])){ switch (h = whichheader(fld[0])) {
case TO: case TO:
case FROM: case FROM:
delit = 1; delit = 1;
commas(to+strlen(fld[0]), s-1); commas(to + strlen(fld[0]), s - 1);
for(i=1; i<nfld && nto<nelem(tolist); i++) for (i = 1; i < nfld && nto < nelem(tolist); i++)
if(!addressed(fld[i])) if (!addressed(fld[i]))
tolist[nto++] = estrdup(fld[i]); tolist[nto++] = estrdup(fld[i]);
break; break;
case BCC: case BCC:
delit = 1; delit = 1;
commas(to+strlen(fld[0]), s-1); commas(to + strlen(fld[0]), s - 1);
for(i=1; i<nfld && nbcc<nelem(bcclist); i++) for (i = 1; i < nfld && nbcc < nelem(bcclist); i++)
if(!addressed(fld[i])) if (!addressed(fld[i]))
bcclist[nbcc++] = estrdup(fld[i]); bcclist[nbcc++] = estrdup(fld[i]);
break; break;
case CC: case CC:
delit = 1; delit = 1;
commas(to+strlen(fld[0]), s-1); commas(to + strlen(fld[0]), s - 1);
for(i=1; i<nfld && ncc<nelem(cclist); i++) for (i = 1; i < nfld && ncc < nelem(cclist); i++)
if(!addressed(fld[i])) if (!addressed(fld[i]))
cclist[ncc++] = estrdup(fld[i]); cclist[ncc++] = estrdup(fld[i]);
break; break;
case ATTACH: case ATTACH:
case INCLUDE: case INCLUDE:
delit = 1; delit = 1;
for(i=1; i<nfld && natt<nelem(attlist); i++){ for (i = 1; i < nfld && natt < nelem(attlist); i++) {
attlist[natt] = estrdup(fld[i]); attlist[natt] = estrdup(fld[i]);
included[natt++] = (h == INCLUDE); included[natt++] = (h == INCLUDE);
} }
break; break;
default: default:
if(first){ if (first) {
delit = 1; delit = 1;
for(i=0; i<nfld && nto<nelem(tolist); i++) for (i = 0; i < nfld && nto < nelem(tolist); i++)
tolist[nto++] = estrdup(fld[i]); tolist[nto++] = estrdup(fld[i]);
}else /* ignore it */ } else /* ignore it */
delit = 0; delit = 0;
break; break;
} }
if(delit){ if (delit) {
/* delete line from body */ /* delete line from body */
memmove(to, s, n+1); memmove(to, s, n + 1);
}else } else
to = s; to = s;
free(copy); free(copy);
first = 0; first = 0;
} }
ofd = open(outgoing, OWRITE|OCEXEC); /* no error check necessary */ ofd = open(outgoing, OWRITE | OCEXEC); /* no error check necessary */
if(ofd > 0){ if (ofd > 0) {
/* From dhog Fri Aug 24 22:13:00 EDT 2001 */ /* From dhog Fri Aug 24 22:13:00 EDT 2001 */
now = ctime(time(0)); now = ctime(time(0));
seek(ofd, 0, 2); seek(ofd, 0, 2);
fprint(ofd, "From %s %s", user, now); fprint(ofd, "From %s %s", user, now);
fprint(ofd, "From: %s\n", user); fprint(ofd, "From: %s\n", user);
fprint(ofd, "Date: %s", now); fprint(ofd, "Date: %s", now);
for(i=0; i<natt; i++) for (i = 0; i < natt; i++)
if(included[i]) if (included[i])
fprint(ofd, "Include: %s\n", attlist[i]); fprint(ofd, "Include: %s\n", attlist[i]);
else else
fprint(ofd, "Attach: %s\n", attlist[i]); fprint(ofd, "Attach: %s\n", attlist[i]);
@ -492,21 +458,21 @@ mesgsend(Message *m)
} }
e = emalloc(sizeof(struct Exec)); e = emalloc(sizeof(struct Exec));
if(pipe(p) < 0) if (pipe(p) < 0)
error("can't create pipe: %r"); error("can't create pipe: %r");
e->p[0] = p[0]; e->p[0] = p[0];
e->p[1] = p[1]; e->p[1] = p[1];
e->prog = unsharp("#9/bin/upas/marshal"); e->prog = unsharp("#9/bin/upas/marshal");
e->argv = emalloc((1+1+2+4*natt+1)*sizeof(char*)); e->argv = emalloc((1 + 1 + 2 + 4 * natt + 1) * sizeof(char*));
e->argv[0] = estrdup("marshal"); e->argv[0] = estrdup("marshal");
e->argv[1] = estrdup("-8"); e->argv[1] = estrdup("-8");
j = 2; j = 2;
if(m->replyname){ if (m->replyname) {
e->argv[j++] = estrdup("-R"); e->argv[j++] = estrdup("-R");
e->argv[j++] = estrstrdup(mbox.name, m->replyname); e->argv[j++] = estrstrdup(mbox.name, m->replyname);
} }
for(i=0; i<natt; i++){ for (i = 0; i < natt; i++) {
if(included[i]) if (included[i])
e->argv[j++] = estrdup("-A"); e->argv[j++] = estrdup("-A");
else else
e->argv[j++] = estrdup("-a"); e->argv[j++] = estrdup("-a");
@ -519,55 +485,55 @@ mesgsend(Message *m)
/* close(p[0]); */ /* close(p[0]); */
/* using marshal -8, so generate rfc822 headers */ /* using marshal -8, so generate rfc822 headers */
if(nto > 0){ if (nto > 0) {
print2(p[1], ofd, "To: "); print2(p[1], ofd, "To: ");
for(i=0; i<nto-1; i++) for (i = 0; i < nto - 1; i++)
print2(p[1], ofd, "%s, ", tolist[i]); print2(p[1], ofd, "%s, ", tolist[i]);
print2(p[1], ofd, "%s\n", tolist[i]); print2(p[1], ofd, "%s\n", tolist[i]);
} }
if(ncc > 0){ if (ncc > 0) {
print2(p[1], ofd, "CC: "); print2(p[1], ofd, "CC: ");
for(i=0; i<ncc-1; i++) for (i = 0; i < ncc - 1; i++)
print2(p[1], ofd, "%s, ", cclist[i]); print2(p[1], ofd, "%s, ", cclist[i]);
print2(p[1], ofd, "%s\n", cclist[i]); print2(p[1], ofd, "%s\n", cclist[i]);
} }
if(nbcc > 0){ if (nbcc > 0) {
print2(p[1], ofd, "BCC: "); print2(p[1], ofd, "BCC: ");
for(i=0; i<nbcc-1; i++) for (i = 0; i < nbcc - 1; i++)
print2(p[1], ofd, "%s, ", bcclist[i]); print2(p[1], ofd, "%s, ", bcclist[i]);
print2(p[1], ofd, "%s\n", bcclist[i]); print2(p[1], ofd, "%s\n", bcclist[i]);
} }
i = strlen(body); i = strlen(body);
if(i > 0) if (i > 0)
write2(p[1], ofd, body, i, 1); write2(p[1], ofd, body, i, 1);
/* guarantee a blank line, to ensure attachments are separated from body */ /* guarantee a blank line, to ensure attachments are separated from body */
if(i==0 || body[i-1]!='\n') if (i == 0 || body[i - 1] != '\n')
write2(p[1], ofd, "\n\n", 2, 0); write2(p[1], ofd, "\n\n", 2, 0);
else if(i>1 && body[i-2]!='\n') else if (i > 1 && body[i - 2] != '\n')
write2(p[1], ofd, "\n", 1, 0); write2(p[1], ofd, "\n", 1, 0);
/* these look like pseudo-attachments in the "outgoing" box */ /* these look like pseudo-attachments in the "outgoing" box */
if(ofd>0 && natt>0){ if (ofd > 0 && natt > 0) {
for(i=0; i<natt; i++) for (i = 0; i < natt; i++)
if(included[i]) if (included[i])
fprint(ofd, "=====> Include: %s\n", attlist[i]); fprint(ofd, "=====> Include: %s\n", attlist[i]);
else else
fprint(ofd, "=====> Attach: %s\n", attlist[i]); fprint(ofd, "=====> Attach: %s\n", attlist[i]);
} }
if(ofd > 0) if (ofd > 0)
write(ofd, "\n", 1); write(ofd, "\n", 1);
for(i=0; i<natt; i++) for (i = 0; i < natt; i++)
free(attlist[i]); free(attlist[i]);
close(ofd); close(ofd);
close(p[1]); close(p[1]);
free(body); free(body);
if(m->replyname != nil) if (m->replyname != nil)
mesgmenumark(mbox.w, m->replyname, "\t[replied]"); mesgmenumark(mbox.w, m->replyname, "\t[replied]");
if(m->name[0] == '/') if (m->name[0] == '/')
s = estrdup(m->name); s = estrdup(m->name);
else else
s = estrstrdup(mbox.name, m->name); s = estrstrdup(mbox.name, m->name);

Binary file not shown.

View file

@ -6,59 +6,49 @@
#include <9pclient.h> #include <9pclient.h>
#include "dat.h" #include "dat.h"
void* void* emalloc(uint n) {
emalloc(uint n) void* p;
{
void *p;
p = malloc(n); p = malloc(n);
if(p == nil) if (p == nil)
error("can't malloc: %r"); error("can't malloc: %r");
memset(p, 0, n); memset(p, 0, n);
setmalloctag(p, getcallerpc(&n)); setmalloctag(p, getcallerpc(&n));
return p; return p;
} }
void* void* erealloc(void* p, uint n) {
erealloc(void *p, uint n)
{
p = realloc(p, n); p = realloc(p, n);
if(p == nil) if (p == nil)
error("can't realloc: %r"); error("can't realloc: %r");
setmalloctag(p, getcallerpc(&n)); setmalloctag(p, getcallerpc(&n));
return p; return p;
} }
char* char* estrdup(char* s) {
estrdup(char *s) char* t;
{
char *t;
t = emalloc(strlen(s)+1); t = emalloc(strlen(s) + 1);
strcpy(t, s); strcpy(t, s);
return t; return t;
} }
char* char* estrstrdup(char* s, char* t) {
estrstrdup(char *s, char *t) char* u;
{
char *u;
u = emalloc(strlen(s)+strlen(t)+1); u = emalloc(strlen(s) + strlen(t) + 1);
strcpy(u, s); strcpy(u, s);
strcat(u, t); strcat(u, t);
return u; return u;
} }
char* char* eappend(char* s, char* sep, char* t) {
eappend(char *s, char *sep, char *t) char* u;
{
char *u;
if(t == nil) if (t == nil)
u = estrstrdup(s, sep); u = estrstrdup(s, sep);
else{ else {
u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1); u = emalloc(strlen(s) + strlen(sep) + strlen(t) + 1);
strcpy(u, s); strcpy(u, s);
strcat(u, sep); strcat(u, sep);
strcat(u, t); strcat(u, t);
@ -67,17 +57,13 @@ eappend(char *s, char *sep, char *t)
return u; return u;
} }
char* char* egrow(char* s, char* sep, char* t) {
egrow(char *s, char *sep, char *t)
{
s = eappend(s, sep, t); s = eappend(s, sep, t);
free(t); free(t);
return s; return s;
} }
void void error(char* fmt, ...) {
error(char *fmt, ...)
{
Fmt f; Fmt f;
char buf[64]; char buf[64];
va_list arg; va_list arg;
@ -92,16 +78,13 @@ error(char *fmt, ...)
threadexitsall(fmt); threadexitsall(fmt);
} }
void void ctlprint(CFid* fd, char* fmt, ...) {
ctlprint(CFid *fd, char *fmt, ...)
{
int n; int n;
va_list arg; va_list arg;
va_start(arg, fmt); va_start(arg, fmt);
n = fsvprint(fd, fmt, arg); n = fsvprint(fd, fmt, arg);
va_end(arg); va_end(arg);
if(n <= 0) if (n <= 0)
error("control file write error: %r"); error("control file write error: %r");
} }

Binary file not shown.

View file

@ -6,15 +6,13 @@
#include <9pclient.h> #include <9pclient.h>
#include "dat.h" #include "dat.h"
Window* Window* newwindow(void) {
newwindow(void)
{
char buf[12]; char buf[12];
Window *w; Window* w;
w = emalloc(sizeof(Window)); w = emalloc(sizeof(Window));
w->ctl = fsopen(acmefs, "new/ctl", ORDWR|OCEXEC); w->ctl = fsopen(acmefs, "new/ctl", ORDWR | OCEXEC);
if(w->ctl == nil || fsread(w->ctl, buf, 12)!=12) if (w->ctl == nil || fsread(w->ctl, buf, 12) != 12)
error("can't open window ctl file: %r"); error("can't open window ctl file: %r");
w->id = atoi(buf); w->id = atoi(buf);
@ -27,19 +25,15 @@ newwindow(void)
return w; return w;
} }
void void winincref(Window* w) {
winincref(Window *w)
{
qlock(&w->lk); qlock(&w->lk);
++w->ref; ++w->ref;
qunlock(&w->lk); qunlock(&w->lk);
} }
void void windecref(Window* w) {
windecref(Window *w)
{
qlock(&w->lk); qlock(&w->lk);
if(--w->ref > 0){ if (--w->ref > 0) {
qunlock(&w->lk); qunlock(&w->lk);
return; return;
} }
@ -48,119 +42,98 @@ windecref(Window *w)
free(w); free(w);
} }
void void winsetdump(Window* w, char* dir, char* cmd) {
winsetdump(Window *w, char *dir, char *cmd) if (dir != nil)
{
if(dir != nil)
ctlprint(w->ctl, "dumpdir %s\n", dir); ctlprint(w->ctl, "dumpdir %s\n", dir);
if(cmd != nil) if (cmd != nil)
ctlprint(w->ctl, "dump %s\n", cmd); ctlprint(w->ctl, "dump %s\n", cmd);
} }
void void wineventproc(void* v) {
wineventproc(void *v) Window* w;
{
Window *w;
int i; int i;
w = v; w = v;
for(i=0; ; i++){ for (i = 0;; i++) {
if(i >= NEVENT) if (i >= NEVENT)
i = 0; i = 0;
wingetevent(w, &w->e[i]); wingetevent(w, &w->e[i]);
sendp(w->cevent, &w->e[i]); sendp(w->cevent, &w->e[i]);
} }
} }
static CFid* static CFid* winopenfile1(Window* w, char* f, int m) {
winopenfile1(Window *w, char *f, int m)
{
char buf[64]; char buf[64];
CFid* fd; CFid* fd;
sprint(buf, "%d/%s", w->id, f); sprint(buf, "%d/%s", w->id, f);
fd = fsopen(acmefs, buf, m|OCEXEC); fd = fsopen(acmefs, buf, m | OCEXEC);
if(fd == nil) if (fd == nil)
error("can't open window file %s: %r", f); error("can't open window file %s: %r", f);
return fd; return fd;
} }
CFid* CFid* winopenfile(Window* w, char* f) { return winopenfile1(w, f, ORDWR); }
winopenfile(Window *w, char *f)
{
return winopenfile1(w, f, ORDWR);
}
void void wintagwrite(Window* w, char* s, int n) {
wintagwrite(Window *w, char *s, int n)
{
CFid* fid; CFid* fid;
fid = winopenfile(w, "tag"); fid = winopenfile(w, "tag");
if(fswrite(fid, s, n) != n) if (fswrite(fid, s, n) != n)
error("tag write: %r"); error("tag write: %r");
fsclose(fid); fsclose(fid);
} }
void void winname(Window* w, char* s) {
winname(Window *w, char *s)
{
int len; int len;
char *ns, *sp; char *ns, *sp;
Rune r = L''; /* visible space */ Rune r = L''; /* visible space */
len = 0; len = 0;
ns = emalloc(strlen(s)*runelen(r) + 1); ns = emalloc(strlen(s) * runelen(r) + 1);
for(sp = s; *sp != '\0'; sp++, len++){ for (sp = s; *sp != '\0'; sp++, len++) {
if(isspace(*sp)){ if (isspace(*sp)) {
len += runetochar(ns+len, &r)-1; len += runetochar(ns + len, &r) - 1;
continue; continue;
} }
*(ns+len) = *sp; *(ns + len) = *sp;
} }
ctlprint(w->ctl, "name %s\n", ns); ctlprint(w->ctl, "name %s\n", ns);
free(ns); free(ns);
return; return;
} }
void void winopenbody(Window* w, int mode) {
winopenbody(Window *w, int mode)
{
char buf[256]; char buf[256];
CFid* fid; CFid* fid;
sprint(buf, "%d/body", w->id); sprint(buf, "%d/body", w->id);
fid = fsopen(acmefs, buf, mode|OCEXEC); fid = fsopen(acmefs, buf, mode | OCEXEC);
w->body = fid; w->body = fid;
if(w->body == nil) if (w->body == nil)
error("can't open window body file: %r"); error("can't open window body file: %r");
} }
void void winclosebody(Window* w) {
winclosebody(Window *w) if (w->body != nil) {
{
if(w->body != nil){
fsclose(w->body); fsclose(w->body);
w->body = nil; w->body = nil;
} }
} }
void void winwritebody(Window* w, char* s, int n) {
winwritebody(Window *w, char *s, int n) if (w->body == nil)
{
if(w->body == nil)
winopenbody(w, OWRITE); winopenbody(w, OWRITE);
if(fswrite(w->body, s, n) != n) if (fswrite(w->body, s, n) != n)
error("write error to window: %r"); error("write error to window: %r");
} }
int int wingetec(Window* w) {
wingetec(Window *w) if (w->nbuf == 0) {
{
if(w->nbuf == 0){
w->nbuf = fsread(w->event, w->buf, sizeof w->buf); w->nbuf = fsread(w->event, w->buf, sizeof w->buf);
if(w->nbuf <= 0){ if (w->nbuf <= 0) {
/* probably because window has exited, and only called by wineventproc, so just shut down */ /* probably because window has exited, and only called by wineventproc, so
* just shut down */
windecref(w); windecref(w);
threadexits(nil); threadexits(nil);
} }
@ -170,30 +143,26 @@ wingetec(Window *w)
return *w->bufp++; return *w->bufp++;
} }
int int wingeten(Window* w) {
wingeten(Window *w)
{
int n, c; int n, c;
n = 0; n = 0;
while('0'<=(c=wingetec(w)) && c<='9') while ('0' <= (c = wingetec(w)) && c <= '9')
n = n*10+(c-'0'); n = n * 10 + (c - '0');
if(c != ' ') if (c != ' ')
error("event number syntax"); error("event number syntax");
return n; return n;
} }
int int wingeter(Window* w, char* buf, int* nb) {
wingeter(Window *w, char *buf, int *nb)
{
Rune r; Rune r;
int n; int n;
r = wingetec(w); r = wingetec(w);
buf[0] = r; buf[0] = r;
n = 1; n = 1;
if(r >= Runeself) { if (r >= Runeself) {
while(!fullrune(buf, n)) while (!fullrune(buf, n))
buf[n++] = wingetec(w); buf[n++] = wingetec(w);
chartorune(&r, buf); chartorune(&r, buf);
} }
@ -201,9 +170,7 @@ wingeter(Window *w, char *buf, int *nb)
return r; return r;
} }
void void wingetevent(Window* w, Event* e) {
wingetevent(Window *w, Event *e)
{
int i, nb; int i, nb;
e->c1 = wingetec(w); e->c1 = wingetec(w);
@ -212,49 +179,47 @@ wingetevent(Window *w, Event *e)
e->q1 = wingeten(w); e->q1 = wingeten(w);
e->flag = wingeten(w); e->flag = wingeten(w);
e->nr = wingeten(w); e->nr = wingeten(w);
if(e->nr > EVENTSIZE) if (e->nr > EVENTSIZE)
error("event string too long"); error("event string too long");
e->nb = 0; e->nb = 0;
for(i=0; i<e->nr; i++){ for (i = 0; i < e->nr; i++) {
e->r[i] = wingeter(w, e->b+e->nb, &nb); e->r[i] = wingeter(w, e->b + e->nb, &nb);
e->nb += nb; e->nb += nb;
} }
e->r[e->nr] = 0; e->r[e->nr] = 0;
e->b[e->nb] = 0; e->b[e->nb] = 0;
if(wingetec(w) != '\n') if (wingetec(w) != '\n')
error("event syntax error"); error("event syntax error");
} }
void void winwriteevent(Window* w, Event* e) {
winwriteevent(Window *w, Event *e)
{
fsprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); fsprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
} }
void void winread(Window* w, uint q0, uint q1, char* data) {
winread(Window *w, uint q0, uint q1, char *data)
{
int m, n, nr; int m, n, nr;
char buf[256]; char buf[256];
if(w->addr == nil) if (w->addr == nil)
w->addr = winopenfile(w, "addr"); w->addr = winopenfile(w, "addr");
if(w->data == nil) if (w->data == nil)
w->data = winopenfile(w, "data"); w->data = winopenfile(w, "data");
m = q0; m = q0;
while(m < q1){ while (m < q1) {
n = sprint(buf, "#%d", m); n = sprint(buf, "#%d", m);
if(fswrite(w->addr, buf, n) != n) if (fswrite(w->addr, buf, n) != n)
error("error writing addr: %r"); error("error writing addr: %r");
n = fsread(w->data, buf, sizeof buf); n = fsread(w->data, buf, sizeof buf);
if(n <= 0) if (n <= 0)
error("reading data: %r"); error("reading data: %r");
nr = utfnlen(buf, n); nr = utfnlen(buf, n);
while(m+nr >q1){ while (m + nr > q1) {
do; while(n>0 && (buf[--n]&0xC0)==0x80); do
;
while (n > 0 && (buf[--n] & 0xC0) == 0x80);
--nr; --nr;
} }
if(n == 0) if (n == 0)
break; break;
memmove(data, buf, n); memmove(data, buf, n);
data += n; data += n;
@ -263,30 +228,25 @@ winread(Window *w, uint q0, uint q1, char *data)
} }
} }
void void windormant(Window* w) {
windormant(Window *w) if (w->addr != nil) {
{
if(w->addr != nil){
fsclose(w->addr); fsclose(w->addr);
w->addr = nil; w->addr = nil;
} }
if(w->body != nil){ if (w->body != nil) {
fsclose(w->body); fsclose(w->body);
w->body = nil; w->body = nil;
} }
if(w->data != nil){ if (w->data != nil) {
fsclose(w->data); fsclose(w->data);
w->data = nil; w->data = nil;
} }
} }
int windel(Window* w, int sure) {
int if (sure)
windel(Window *w, int sure)
{
if(sure)
fswrite(w->ctl, "delete\n", 7); fswrite(w->ctl, "delete\n", 7);
else if(fswrite(w->ctl, "del\n", 4) != 4) else if (fswrite(w->ctl, "del\n", 4) != 4)
return 0; return 0;
/* event proc will die due to read error from event file */ /* event proc will die due to read error from event file */
windormant(w); windormant(w);
@ -295,54 +255,47 @@ windel(Window *w, int sure)
return 1; return 1;
} }
void void winclean(Window* w) { ctlprint(w->ctl, "clean\n"); }
winclean(Window *w)
{
ctlprint(w->ctl, "clean\n");
}
int int winsetaddr(Window* w, char* addr, int errok) {
winsetaddr(Window *w, char *addr, int errok) if (w->addr == nil)
{
if(w->addr == nil)
w->addr = winopenfile(w, "addr"); w->addr = winopenfile(w, "addr");
if(fswrite(w->addr, addr, strlen(addr)) < 0){ if (fswrite(w->addr, addr, strlen(addr)) < 0) {
if(!errok) if (!errok)
error("error writing addr(%s): %r", addr); error("error writing addr(%s): %r", addr);
return 0; return 0;
} }
return 1; return 1;
} }
int int winselect(Window* w, char* addr, int errok) {
winselect(Window *w, char *addr, int errok) if (winsetaddr(w, addr, errok)) {
{
if(winsetaddr(w, addr, errok)){
ctlprint(w->ctl, "dot=addr\n"); ctlprint(w->ctl, "dot=addr\n");
return 1; return 1;
} }
return 0; return 0;
} }
char* char* winreadbody(
winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */ Window* w,
int* np) /* can't use readfile because acme doesn't report the length */
{ {
char *s; char* s;
int m, na, n; int m, na, n;
if(w->body != nil) if (w->body != nil)
winclosebody(w); winclosebody(w);
winopenbody(w, OREAD); winopenbody(w, OREAD);
s = nil; s = nil;
na = 0; na = 0;
n = 0; n = 0;
for(;;){ for (;;) {
if(na < n+512){ if (na < n + 512) {
na += 1024; na += 1024;
s = realloc(s, na+1); s = realloc(s, na + 1);
} }
m = fsread(w->body, s+n, na-n); m = fsread(w->body, s + n, na - n);
if(m <= 0) if (m <= 0)
break; break;
n += m; n += m;
} }
@ -352,25 +305,23 @@ winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't repor
return s; return s;
} }
char* char* winselection(Window* w) {
winselection(Window *w)
{
int m, n; int m, n;
char *buf; char* buf;
char tmp[256]; char tmp[256];
CFid* fid; CFid* fid;
fid = winopenfile1(w, "rdsel", OREAD); fid = winopenfile1(w, "rdsel", OREAD);
if(fid == nil) if (fid == nil)
error("can't open rdsel: %r"); error("can't open rdsel: %r");
n = 0; n = 0;
buf = nil; buf = nil;
for(;;){ for (;;) {
m = fsread(fid, tmp, sizeof tmp); m = fsread(fid, tmp, sizeof tmp);
if(m <= 0) if (m <= 0)
break; break;
buf = erealloc(buf, n+m+1); buf = erealloc(buf, n + m + 1);
memmove(buf+n, tmp, m); memmove(buf + n, tmp, m);
n += m; n += m;
buf[n] = '\0'; buf[n] = '\0';
} }

Binary file not shown.

459
regx.c
View file

@ -13,39 +13,37 @@
#include "fns.h" #include "fns.h"
Rangeset sel; Rangeset sel;
Rune *lastregexp; Rune* lastregexp;
/* /*
* Machine Information * Machine Information
*/ */
typedef struct Inst Inst; typedef struct Inst Inst;
struct Inst struct Inst {
{
uint type; /* < OPERATOR ==> literal, otherwise action */ uint type; /* < OPERATOR ==> literal, otherwise action */
union { union {
int sid; int sid;
int subid; int subid;
int class; int class;
Inst *other; Inst* other;
Inst *right; Inst* right;
} u; } u;
union{ union {
Inst *left; Inst* left;
Inst *next; Inst* next;
} u1; } u1;
}; };
#define NPROG 1024 #define NPROG 1024
Inst program[NPROG]; Inst program[NPROG];
Inst *progp; Inst* progp;
Inst *startinst; /* First inst. of program; might not be program[0] */ Inst* startinst; /* First inst. of program; might not be program[0] */
Inst *bstartinst; /* same for backwards machine */ Inst* bstartinst; /* same for backwards machine */
Channel *rechan; /* chan(Inst*) */ Channel* rechan; /* chan(Inst*) */
typedef struct Ilist Ilist; typedef struct Ilist Ilist;
struct Ilist struct Ilist {
{ Inst* inst; /* Instruction of the thread */
Inst *inst; /* Instruction of the thread */
Rangeset se; Rangeset se;
uint startp; /* first char of match */ uint startp; /* first char of match */
}; };
@ -53,7 +51,7 @@ struct Ilist
#define NLIST 127 #define NLIST 127
Ilist *tl, *nl; /* This list, next list */ Ilist *tl, *nl; /* This list, next list */
Ilist list[2][NLIST+1]; /* +1 for trailing null */ Ilist list[2][NLIST + 1]; /* +1 for trailing null */
static Rangeset sempty; static Rangeset sempty;
/* /*
@ -63,21 +61,21 @@ static Rangeset sempty;
* 0x20000xx are tokens, i.e. operands for operators * 0x20000xx are tokens, i.e. operands for operators
*/ */
#define OPERATOR 0x1000000 /* Bit set in all operators */ #define OPERATOR 0x1000000 /* Bit set in all operators */
#define START (OPERATOR+0) /* Start, used for marker on stack */ #define START (OPERATOR + 0) /* Start, used for marker on stack */
#define RBRA (OPERATOR+1) /* Right bracket, ) */ #define RBRA (OPERATOR + 1) /* Right bracket, ) */
#define LBRA (OPERATOR+2) /* Left bracket, ( */ #define LBRA (OPERATOR + 2) /* Left bracket, ( */
#define OR (OPERATOR+3) /* Alternation, | */ #define OR (OPERATOR + 3) /* Alternation, | */
#define CAT (OPERATOR+4) /* Concatentation, implicit operator */ #define CAT (OPERATOR + 4) /* Concatentation, implicit operator */
#define STAR (OPERATOR+5) /* Closure, * */ #define STAR (OPERATOR + 5) /* Closure, * */
#define PLUS (OPERATOR+6) /* a+ == aa* */ #define PLUS (OPERATOR + 6) /* a+ == aa* */
#define QUEST (OPERATOR+7) /* a? == a|nothing, i.e. 0 or 1 a's */ #define QUEST (OPERATOR + 7) /* a? == a|nothing, i.e. 0 or 1 a's */
#define ANY 0x2000000 /* Any character but newline, . */ #define ANY 0x2000000 /* Any character but newline, . */
#define NOP (ANY+1) /* No operation, internal use only */ #define NOP (ANY + 1) /* No operation, internal use only */
#define BOL (ANY+2) /* Beginning of line, ^ */ #define BOL (ANY + 2) /* Beginning of line, ^ */
#define EOL (ANY+3) /* End of line, $ */ #define EOL (ANY + 3) /* End of line, $ */
#define CCLASS (ANY+4) /* Character class, [] */ #define CCLASS (ANY + 4) /* Character class, [] */
#define NCCLASS (ANY+5) /* Negated character class, [^] */ #define NCCLASS (ANY + 5) /* Negated character class, [^] */
#define END (ANY+0x77) /* Terminate: match found */ #define END (ANY + 0x77) /* Terminate: match found */
#define ISATOR OPERATOR #define ISATOR OPERATOR
#define ISAND ANY #define ISAND ANY
@ -88,36 +86,35 @@ static Rangeset sempty;
* Parser Information * Parser Information
*/ */
typedef struct Node Node; typedef struct Node Node;
struct Node struct Node {
{ Inst* first;
Inst *first; Inst* last;
Inst *last;
}; };
#define NSTACK 20 #define NSTACK 20
Node andstack[NSTACK]; Node andstack[NSTACK];
Node *andp; Node* andp;
int atorstack[NSTACK]; int atorstack[NSTACK];
int *atorp; int* atorp;
int lastwasand; /* Last token was operand */ int lastwasand; /* Last token was operand */
int cursubid; int cursubid;
int subidstack[NSTACK]; int subidstack[NSTACK];
int *subidp; int* subidp;
int backwards; int backwards;
int nbra; int nbra;
Rune *exprp; /* pointer to next character in source expression */ Rune* exprp; /* pointer to next character in source expression */
#define DCLASS 10 /* allocation increment */ #define DCLASS 10 /* allocation increment */
int nclass; /* number active */ int nclass; /* number active */
int Nclass; /* high water mark */ int Nclass; /* high water mark */
Rune **class; Rune** class;
int negateclass; int negateclass;
int addinst(Ilist *l, Inst *inst, Rangeset *sep); int addinst(Ilist* l, Inst* inst, Rangeset* sep);
void newmatch(Rangeset*); void newmatch(Rangeset*);
void bnewmatch(Rangeset*); void bnewmatch(Rangeset*);
void pushand(Inst*, Inst*); void pushand(Inst*, Inst*);
void pushator(int); void pushator(int);
Node *popand(int); Node* popand(int);
int popator(void); int popator(void);
void startlex(Rune*); void startlex(Rune*);
int lex(void); int lex(void);
@ -127,27 +124,21 @@ void evaluntil(int);
void optimize(Inst*); void optimize(Inst*);
void bldcclass(void); void bldcclass(void);
void void rxinit(void) {
rxinit(void)
{
rechan = chancreate(sizeof(Inst*), 0); rechan = chancreate(sizeof(Inst*), 0);
chansetname(rechan, "rechan"); chansetname(rechan, "rechan");
lastregexp = runemalloc(1); lastregexp = runemalloc(1);
} }
void void regerror(char* e) {
regerror(char *e)
{
lastregexp[0] = 0; lastregexp[0] = 0;
warning(nil, "regexp: %s\n", e); warning(nil, "regexp: %s\n", e);
sendp(rechan, nil); sendp(rechan, nil);
threadexits(nil); threadexits(nil);
} }
Inst * Inst* newinst(int t) {
newinst(int t) if (progp >= &program[NPROG])
{
if(progp >= &program[NPROG])
regerror("expression too long"); regerror("expression too long");
progp->type = t; progp->type = t;
progp->u1.left = nil; progp->u1.left = nil;
@ -155,11 +146,9 @@ newinst(int t)
return progp++; return progp++;
} }
void void realcompile(void* arg) {
realcompile(void *arg)
{
int token; int token;
Rune *s; Rune* s;
threadsetname("regcomp"); threadsetname("regcomp");
s = arg; s = arg;
@ -170,9 +159,9 @@ realcompile(void *arg)
cursubid = 0; cursubid = 0;
lastwasand = FALSE; lastwasand = FALSE;
/* Start with a low priority operator to prime parser */ /* Start with a low priority operator to prime parser */
pushator(START-1); pushator(START - 1);
while((token=lex()) != END){ while ((token = lex()) != END) {
if((token&ISATOR) == OPERATOR) if ((token & ISATOR) == OPERATOR)
operator(token); operator(token);
else else
operand(token); operand(token);
@ -182,7 +171,7 @@ realcompile(void *arg)
/* Force END */ /* Force END */
operand(END); operand(END);
evaluntil(START); evaluntil(START);
if(nbra) if (nbra)
regerror("unmatched `('"); regerror("unmatched `('");
--andp; /* points to first and only operand */ --andp; /* points to first and only operand */
sendp(rechan, andp->first); sendp(rechan, andp->first);
@ -190,17 +179,15 @@ realcompile(void *arg)
} }
/* r is null terminated */ /* r is null terminated */
int int rxcompile(Rune* r) {
rxcompile(Rune *r)
{
int i, nr; int i, nr;
Inst *oprogp; Inst* oprogp;
nr = runestrlen(r)+1; nr = runestrlen(r) + 1;
if(runeeq(lastregexp, runestrlen(lastregexp)+1, r, nr)==TRUE) if (runeeq(lastregexp, runestrlen(lastregexp) + 1, r, nr) == TRUE)
return TRUE; return TRUE;
lastregexp[0] = 0; lastregexp[0] = 0;
for(i=0; i<nclass; i++) for (i = 0; i < nclass; i++)
free(class[i]); free(class[i]);
nclass = 0; nclass = 0;
progp = program; progp = program;
@ -208,14 +195,14 @@ rxcompile(Rune *r)
bstartinst = nil; bstartinst = nil;
threadcreate(realcompile, r, STACK); threadcreate(realcompile, r, STACK);
startinst = recvp(rechan); startinst = recvp(rechan);
if(startinst == nil) if (startinst == nil)
return FALSE; return FALSE;
optimize(program); optimize(program);
oprogp = progp; oprogp = progp;
backwards = TRUE; backwards = TRUE;
threadcreate(realcompile, r, STACK); threadcreate(realcompile, r, STACK);
bstartinst = recvp(rechan); bstartinst = recvp(rechan);
if(bstartinst == nil) if (bstartinst == nil)
return FALSE; return FALSE;
optimize(oprogp); optimize(oprogp);
lastregexp = runerealloc(lastregexp, nr); lastregexp = runerealloc(lastregexp, nr);
@ -223,94 +210,80 @@ rxcompile(Rune *r)
return TRUE; return TRUE;
} }
void void operand(int t) {
operand(int t) Inst* i;
{ if (lastwasand)
Inst *i;
if(lastwasand)
operator(CAT); /* catenate is implicit */ operator(CAT); /* catenate is implicit */
i = newinst(t); i = newinst(t);
if(t == CCLASS){ if (t == CCLASS) {
if(negateclass) if (negateclass)
i->type = NCCLASS; /* UGH */ i->type = NCCLASS; /* UGH */
i->u.class = nclass-1; /* UGH */ i->u.class = nclass - 1; /* UGH */
} }
pushand(i, i); pushand(i, i);
lastwasand = TRUE; lastwasand = TRUE;
} }
void void operator(int t) {
operator(int t) if (t == RBRA && --nbra < 0)
{
if(t==RBRA && --nbra<0)
regerror("unmatched `)'"); regerror("unmatched `)'");
if(t==LBRA){ if (t == LBRA) {
cursubid++; /* silently ignored */ cursubid++; /* silently ignored */
nbra++; nbra++;
if(lastwasand) if (lastwasand)
operator(CAT); operator(CAT);
}else } else
evaluntil(t); evaluntil(t);
if(t!=RBRA) if (t != RBRA)
pushator(t); pushator(t);
lastwasand = FALSE; lastwasand = FALSE;
if(t==STAR || t==QUEST || t==PLUS || t==RBRA) if (t == STAR || t == QUEST || t == PLUS || t == RBRA)
lastwasand = TRUE; /* these look like operands */ lastwasand = TRUE; /* these look like operands */
} }
void void pushand(Inst* f, Inst* l) {
pushand(Inst *f, Inst *l) if (andp >= &andstack[NSTACK])
{
if(andp >= &andstack[NSTACK])
error("operand stack overflow"); error("operand stack overflow");
andp->first = f; andp->first = f;
andp->last = l; andp->last = l;
andp++; andp++;
} }
void void pushator(int t) {
pushator(int t) if (atorp >= &atorstack[NSTACK])
{
if(atorp >= &atorstack[NSTACK])
error("operator stack overflow"); error("operator stack overflow");
*atorp++=t; *atorp++ = t;
if(cursubid >= NRange) if (cursubid >= NRange)
*subidp++= -1; *subidp++ = -1;
else else
*subidp++=cursubid; *subidp++ = cursubid;
} }
Node * Node* popand(int op) {
popand(int op)
{
char buf[64]; char buf[64];
if(andp <= &andstack[0]) if (andp <= &andstack[0])
if(op){ if (op) {
sprint(buf, "missing operand for %c", op); sprint(buf, "missing operand for %c", op);
regerror(buf); regerror(buf);
}else } else
regerror("malformed regexp"); regerror("malformed regexp");
return --andp; return --andp;
} }
int int popator() {
popator() if (atorp <= &atorstack[0])
{
if(atorp <= &atorstack[0])
error("operator stack underflow"); error("operator stack underflow");
--subidp; --subidp;
return *--atorp; return *--atorp;
} }
void void evaluntil(int pri) {
evaluntil(int pri)
{
Node *op1, *op2, *t; Node *op1, *op2, *t;
Inst *inst1, *inst2; Inst *inst1, *inst2;
while(pri==RBRA || atorp[-1]>=pri){ while (pri == RBRA || atorp[-1] >= pri) {
switch(popator()){ switch (popator()) {
case LBRA: case LBRA:
op1 = popand('('); op1 = popand('(');
inst2 = newinst(RBRA); inst2 = newinst(RBRA);
@ -338,7 +311,7 @@ evaluntil(int pri)
case CAT: case CAT:
op2 = popand(0); op2 = popand(0);
op1 = popand(0); op1 = popand(0);
if(backwards && op2->first->type!=END){ if (backwards && op2->first->type != END) {
t = op1; t = op1;
op1 = op2; op1 = op2;
op2 = t; op2 = t;
@ -373,38 +346,31 @@ evaluntil(int pri)
} }
} }
void optimize(Inst* start) {
void
optimize(Inst *start)
{
Inst *inst, *target; Inst *inst, *target;
for(inst=start; inst->type!=END; inst++){ for (inst = start; inst->type != END; inst++) {
target = inst->u1.next; target = inst->u1.next;
while(target->type == NOP) while (target->type == NOP)
target = target->u1.next; target = target->u1.next;
inst->u1.next = target; inst->u1.next = target;
} }
} }
void void startlex(Rune* s) {
startlex(Rune *s)
{
exprp = s; exprp = s;
nbra = 0; nbra = 0;
} }
int lex(void) {
int
lex(void){
int c; int c;
c = *exprp++; c = *exprp++;
switch(c){ switch (c) {
case '\\': case '\\':
if(*exprp) if (*exprp)
if((c= *exprp++)=='n') if ((c = *exprp++) == 'n')
c='\n'; c = '\n';
break; break;
case 0: case 0:
c = END; c = END;
@ -445,79 +411,73 @@ lex(void){
return c; return c;
} }
int int nextrec(void) {
nextrec(void) if (exprp[0] == 0 || (exprp[0] == '\\' && exprp[1] == 0))
{
if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0))
regerror("malformed `[]'"); regerror("malformed `[]'");
if(exprp[0] == '\\'){ if (exprp[0] == '\\') {
exprp++; exprp++;
if(*exprp=='n'){ if (*exprp == 'n') {
exprp++; exprp++;
return '\n'; return '\n';
} }
return *exprp++|QUOTED; return *exprp++ | QUOTED;
} }
return *exprp++; return *exprp++;
} }
void void bldcclass(void) {
bldcclass(void)
{
int c1, c2, n, na; int c1, c2, n, na;
Rune *classp; Rune* classp;
classp = runemalloc(DCLASS); classp = runemalloc(DCLASS);
n = 0; n = 0;
na = DCLASS; na = DCLASS;
/* we have already seen the '[' */ /* we have already seen the '[' */
if(*exprp == '^'){ if (*exprp == '^') {
classp[n++] = '\n'; /* don't match newline in negate case */ classp[n++] = '\n'; /* don't match newline in negate case */
negateclass = TRUE; negateclass = TRUE;
exprp++; exprp++;
}else } else
negateclass = FALSE; negateclass = FALSE;
while((c1 = nextrec()) != ']'){ while ((c1 = nextrec()) != ']') {
if(c1 == '-'){ if (c1 == '-') {
Error: Error:
free(classp); free(classp);
regerror("malformed `[]'"); regerror("malformed `[]'");
} }
if(n+4 >= na){ /* 3 runes plus NUL */ if (n + 4 >= na) { /* 3 runes plus NUL */
na += DCLASS; na += DCLASS;
classp = runerealloc(classp, na); classp = runerealloc(classp, na);
} }
if(*exprp == '-'){ if (*exprp == '-') {
exprp++; /* eat '-' */ exprp++; /* eat '-' */
if((c2 = nextrec()) == ']') if ((c2 = nextrec()) == ']')
goto Error; goto Error;
classp[n+0] = Runemax; classp[n + 0] = Runemax;
classp[n+1] = c1; classp[n + 1] = c1;
classp[n+2] = c2; classp[n + 2] = c2;
n += 3; n += 3;
}else } else
classp[n++] = c1 & ~QUOTED; classp[n++] = c1 & ~QUOTED;
} }
classp[n] = 0; classp[n] = 0;
if(nclass == Nclass){ if (nclass == Nclass) {
Nclass += DCLASS; Nclass += DCLASS;
class = realloc(class, Nclass*sizeof(Rune*)); class = realloc(class, Nclass * sizeof(Rune*));
} }
class[nclass++] = classp; class[nclass++] = classp;
} }
int int classmatch(int classno, int c, int negate) {
classmatch(int classno, int c, int negate) Rune* p;
{
Rune *p;
p = class[classno]; p = class[classno];
while(*p){ while (*p) {
if(*p == Runemax){ if (*p == Runemax) {
if(p[1]<=c && c<=p[2]) if (p[1] <= c && c <= p[2])
return !negate; return !negate;
p += 3; p += 3;
}else if(*p++ == c) } else if (*p++ == c)
return !negate; return !negate;
} }
return negate; return negate;
@ -528,37 +488,29 @@ classmatch(int classno, int c, int negate)
* *l must be pending when addinst called; if *l has been looked * *l must be pending when addinst called; if *l has been looked
* at already, the optimization is a bug. * at already, the optimization is a bug.
*/ */
int int addinst(Ilist* l, Inst* inst, Rangeset* sep) {
addinst(Ilist *l, Inst *inst, Rangeset *sep) Ilist* p;
{
Ilist *p;
for(p = l; p->inst; p++){ for (p = l; p->inst; p++) {
if(p->inst==inst){ if (p->inst == inst) {
if((sep)->r[0].q0 < p->se.r[0].q0) if ((sep)->r[0].q0 < p->se.r[0].q0)
p->se= *sep; /* this would be bug */ p->se = *sep; /* this would be bug */
return 0; /* It's already there */ return 0; /* It's already there */
} }
} }
p->inst = inst; p->inst = inst;
p->se= *sep; p->se = *sep;
(p+1)->inst = nil; (p + 1)->inst = nil;
return 1; return 1;
} }
int int rxnull(void) { return startinst == nil || bstartinst == nil; }
rxnull(void)
{
return startinst==nil || bstartinst==nil;
}
/* either t!=nil or r!=nil, and we match the string in the appropriate place */ /* either t!=nil or r!=nil, and we match the string in the appropriate place */
int int rxexecute(Text* t, Rune* r, uint startp, uint eof, Rangeset* rp) {
rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
{
int flag; int flag;
Inst *inst; Inst* inst;
Ilist *tlp; Ilist* tlp;
uint p; uint p;
int nnl, ntl; int nnl, ntl;
int nc, c; int nc, c;
@ -570,24 +522,24 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
startchar = 0; startchar = 0;
wrapped = 0; wrapped = 0;
nnl = 0; nnl = 0;
if(startinst->type<OPERATOR) if (startinst->type < OPERATOR)
startchar = startinst->type; startchar = startinst->type;
list[0][0].inst = list[1][0].inst = nil; list[0][0].inst = list[1][0].inst = nil;
sel.r[0].q0 = -1; sel.r[0].q0 = -1;
if(t != nil) if (t != nil)
nc = t->file->b.nc; nc = t->file->b.nc;
else else
nc = runestrlen(r); nc = runestrlen(r);
/* Execute machine once for each character */ /* Execute machine once for each character */
for(;;p++){ for (;; p++) {
doloop: doloop:
if(p>=eof || p>=nc){ if (p >= eof || p >= nc) {
switch(wrapped++){ switch (wrapped++) {
case 0: /* let loop run one more click */ case 0: /* let loop run one more click */
case 2: case 2:
break; break;
case 1: /* expired; wrap to beginning */ case 1: /* expired; wrap to beginning */
if(sel.r[0].q0>=0 || eof!=Infinity) if (sel.r[0].q0 >= 0 || eof != Infinity)
goto Return; goto Return;
list[0][0].inst = list[1][0].inst = nil; list[0][0].inst = list[1][0].inst = nil;
p = 0; p = 0;
@ -596,27 +548,27 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
goto Return; goto Return;
} }
c = 0; c = 0;
}else{ } else {
if(((wrapped && p>=startp) || sel.r[0].q0>0) && nnl==0) if (((wrapped && p >= startp) || sel.r[0].q0 > 0) && nnl == 0)
break; break;
if(t != nil) if (t != nil)
c = textreadc(t, p); c = textreadc(t, p);
else else
c = r[p]; c = r[p];
} }
/* fast check for first char */ /* fast check for first char */
if(startchar && nnl==0 && c!=startchar) if (startchar && nnl == 0 && c != startchar)
continue; continue;
tl = list[flag]; tl = list[flag];
nl = list[flag^=1]; nl = list[flag ^= 1];
nl->inst = nil; nl->inst = nil;
ntl = nnl; ntl = nnl;
nnl = 0; nnl = 0;
if(sel.r[0].q0<0 && (!wrapped || p<startp || startp==eof)){ if (sel.r[0].q0 < 0 && (!wrapped || p < startp || startp == eof)) {
/* Add first instruction to this list */ /* Add first instruction to this list */
sempty.r[0].q0 = p; sempty.r[0].q0 = p;
if(addinst(tl, startinst, &sempty)) if (addinst(tl, startinst, &sempty))
if(++ntl >= NLIST){ if (++ntl >= NLIST) {
Overflow: Overflow:
warning(nil, "regexp list overflow\n"); warning(nil, "regexp list overflow\n");
sel.r[0].q0 = -1; sel.r[0].q0 = -1;
@ -624,54 +576,56 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
} }
} }
/* Execute machine until this list is empty */ /* Execute machine until this list is empty */
for(tlp = tl; inst = tlp->inst; tlp++){ /* assignment = */ for (tlp = tl; inst = tlp->inst; tlp++) { /* assignment = */
Switchstmt: Switchstmt:
switch(inst->type){ switch (inst->type) {
default: /* regular character */ default: /* regular character */
if(inst->type==c){ if (inst->type == c) {
Addinst: Addinst:
if(addinst(nl, inst->u1.next, &tlp->se)) if (addinst(nl, inst->u1.next, &tlp->se))
if(++nnl >= NLIST) if (++nnl >= NLIST)
goto Overflow; goto Overflow;
} }
break; break;
case LBRA: case LBRA:
if(inst->u.subid>=0) if (inst->u.subid >= 0)
tlp->se.r[inst->u.subid].q0 = p; tlp->se.r[inst->u.subid].q0 = p;
inst = inst->u1.next; inst = inst->u1.next;
goto Switchstmt; goto Switchstmt;
case RBRA: case RBRA:
if(inst->u.subid>=0) if (inst->u.subid >= 0)
tlp->se.r[inst->u.subid].q1 = p; tlp->se.r[inst->u.subid].q1 = p;
inst = inst->u1.next; inst = inst->u1.next;
goto Switchstmt; goto Switchstmt;
case ANY: case ANY:
if(c!='\n') if (c != '\n')
goto Addinst; goto Addinst;
break; break;
case BOL: case BOL:
if(p==0 || (t!=nil && textreadc(t, p-1)=='\n') || (r!=nil && r[p-1]=='\n')){ if (
p == 0 || (t != nil && textreadc(t, p - 1) == '\n') ||
(r != nil && r[p - 1] == '\n')) {
Step: Step:
inst = inst->u1.next; inst = inst->u1.next;
goto Switchstmt; goto Switchstmt;
} }
break; break;
case EOL: case EOL:
if(c == '\n') if (c == '\n')
goto Step; goto Step;
break; break;
case CCLASS: case CCLASS:
if(c>=0 && classmatch(inst->u.class, c, 0)) if (c >= 0 && classmatch(inst->u.class, c, 0))
goto Addinst; goto Addinst;
break; break;
case NCCLASS: case NCCLASS:
if(c>=0 && classmatch(inst->u.class, c, 1)) if (c >= 0 && classmatch(inst->u.class, c, 1))
goto Addinst; goto Addinst;
break; break;
case OR: case OR:
/* evaluate right choice later */ /* evaluate right choice later */
if(addinst(tlp, inst->u.right, &tlp->se)) if (addinst(tlp, inst->u.right, &tlp->se))
if(++ntl >= NLIST) if (++ntl >= NLIST)
goto Overflow; goto Overflow;
/* efficiency: advance and re-evaluate */ /* efficiency: advance and re-evaluate */
inst = inst->u1.left; inst = inst->u1.left;
@ -683,25 +637,22 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
} }
} }
} }
Return: Return:
*rp = sel; *rp = sel;
return sel.r[0].q0 >= 0; return sel.r[0].q0 >= 0;
} }
void void newmatch(Rangeset* sp) {
newmatch(Rangeset *sp) if (
{ sel.r[0].q0 < 0 || sp->r[0].q0 < sel.r[0].q0 ||
if(sel.r[0].q0<0 || sp->r[0].q0<sel.r[0].q0 || (sp->r[0].q0 == sel.r[0].q0 && sp->r[0].q1 > sel.r[0].q1))
(sp->r[0].q0==sel.r[0].q0 && sp->r[0].q1>sel.r[0].q1))
sel = *sp; sel = *sp;
} }
int int rxbexecute(Text* t, uint startp, Rangeset* rp) {
rxbexecute(Text *t, uint startp, Rangeset *rp)
{
int flag; int flag;
Inst *inst; Inst* inst;
Ilist *tlp; Ilist* tlp;
int p; int p;
int nnl, ntl; int nnl, ntl;
int c; int c;
@ -713,20 +664,20 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
wrapped = 0; wrapped = 0;
p = startp; p = startp;
startchar = 0; startchar = 0;
if(bstartinst->type<OPERATOR) if (bstartinst->type < OPERATOR)
startchar = bstartinst->type; startchar = bstartinst->type;
list[0][0].inst = list[1][0].inst = nil; list[0][0].inst = list[1][0].inst = nil;
sel.r[0].q0= -1; sel.r[0].q0 = -1;
/* Execute machine once for each character, including terminal NUL */ /* Execute machine once for each character, including terminal NUL */
for(;;--p){ for (;; --p) {
doloop: doloop:
if(p <= 0){ if (p <= 0) {
switch(wrapped++){ switch (wrapped++) {
case 0: /* let loop run one more click */ case 0: /* let loop run one more click */
case 2: case 2:
break; break;
case 1: /* expired; wrap to end */ case 1: /* expired; wrap to end */
if(sel.r[0].q0>=0) if (sel.r[0].q0 >= 0)
goto Return; goto Return;
list[0][0].inst = list[1][0].inst = nil; list[0][0].inst = list[1][0].inst = nil;
p = t->file->b.nc; p = t->file->b.nc;
@ -736,25 +687,25 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
goto Return; goto Return;
} }
c = 0; c = 0;
}else{ } else {
if(((wrapped && p<=startp) || sel.r[0].q0>0) && nnl==0) if (((wrapped && p <= startp) || sel.r[0].q0 > 0) && nnl == 0)
break; break;
c = textreadc(t, p-1); c = textreadc(t, p - 1);
} }
/* fast check for first char */ /* fast check for first char */
if(startchar && nnl==0 && c!=startchar) if (startchar && nnl == 0 && c != startchar)
continue; continue;
tl = list[flag]; tl = list[flag];
nl = list[flag^=1]; nl = list[flag ^= 1];
nl->inst = nil; nl->inst = nil;
ntl = nnl; ntl = nnl;
nnl = 0; nnl = 0;
if(sel.r[0].q0<0 && (!wrapped || p>startp)){ if (sel.r[0].q0 < 0 && (!wrapped || p > startp)) {
/* Add first instruction to this list */ /* Add first instruction to this list */
/* the minus is so the optimizations in addinst work */ /* the minus is so the optimizations in addinst work */
sempty.r[0].q0 = -p; sempty.r[0].q0 = -p;
if(addinst(tl, bstartinst, &sempty)) if (addinst(tl, bstartinst, &sempty))
if(++ntl >= NLIST){ if (++ntl >= NLIST) {
Overflow: Overflow:
warning(nil, "regexp list overflow\n"); warning(nil, "regexp list overflow\n");
sel.r[0].q0 = -1; sel.r[0].q0 = -1;
@ -762,54 +713,54 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
} }
} }
/* Execute machine until this list is empty */ /* Execute machine until this list is empty */
for(tlp = tl; inst = tlp->inst; tlp++){ /* assignment = */ for (tlp = tl; inst = tlp->inst; tlp++) { /* assignment = */
Switchstmt: Switchstmt:
switch(inst->type){ switch (inst->type) {
default: /* regular character */ default: /* regular character */
if(inst->type == c){ if (inst->type == c) {
Addinst: Addinst:
if(addinst(nl, inst->u1.next, &tlp->se)) if (addinst(nl, inst->u1.next, &tlp->se))
if(++nnl >= NLIST) if (++nnl >= NLIST)
goto Overflow; goto Overflow;
} }
break; break;
case LBRA: case LBRA:
if(inst->u.subid>=0) if (inst->u.subid >= 0)
tlp->se.r[inst->u.subid].q0 = p; tlp->se.r[inst->u.subid].q0 = p;
inst = inst->u1.next; inst = inst->u1.next;
goto Switchstmt; goto Switchstmt;
case RBRA: case RBRA:
if(inst->u.subid >= 0) if (inst->u.subid >= 0)
tlp->se.r[inst->u.subid].q1 = p; tlp->se.r[inst->u.subid].q1 = p;
inst = inst->u1.next; inst = inst->u1.next;
goto Switchstmt; goto Switchstmt;
case ANY: case ANY:
if(c != '\n') if (c != '\n')
goto Addinst; goto Addinst;
break; break;
case BOL: case BOL:
if(c=='\n' || p==0){ if (c == '\n' || p == 0) {
Step: Step:
inst = inst->u1.next; inst = inst->u1.next;
goto Switchstmt; goto Switchstmt;
} }
break; break;
case EOL: case EOL:
if(p<t->file->b.nc && textreadc(t, p)=='\n') if (p < t->file->b.nc && textreadc(t, p) == '\n')
goto Step; goto Step;
break; break;
case CCLASS: case CCLASS:
if(c>0 && classmatch(inst->u.class, c, 0)) if (c > 0 && classmatch(inst->u.class, c, 0))
goto Addinst; goto Addinst;
break; break;
case NCCLASS: case NCCLASS:
if(c>0 && classmatch(inst->u.class, c, 1)) if (c > 0 && classmatch(inst->u.class, c, 1))
goto Addinst; goto Addinst;
break; break;
case OR: case OR:
/* evaluate right choice later */ /* evaluate right choice later */
if(addinst(tl, inst->u.right, &tlp->se)) if (addinst(tl, inst->u.right, &tlp->se))
if(++ntl >= NLIST) if (++ntl >= NLIST)
goto Overflow; goto Overflow;
/* efficiency: advance and re-evaluate */ /* efficiency: advance and re-evaluate */
inst = inst->u1.left; inst = inst->u1.left;
@ -822,18 +773,18 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
} }
} }
} }
Return: Return:
*rp = sel; *rp = sel;
return sel.r[0].q0 >= 0; return sel.r[0].q0 >= 0;
} }
void void bnewmatch(Rangeset* sp) {
bnewmatch(Rangeset *sp)
{
int i; int i;
if(sel.r[0].q0<0 || sp->r[0].q0>sel.r[0].q1 || (sp->r[0].q0==sel.r[0].q1 && sp->r[0].q1<sel.r[0].q0)) if (
for(i = 0; i<NRange; i++){ /* note the reversal; q0<=q1 */ sel.r[0].q0 < 0 || sp->r[0].q0 > sel.r[0].q1 ||
(sp->r[0].q0 == sel.r[0].q1 && sp->r[0].q1 < sel.r[0].q0))
for (i = 0; i < NRange; i++) { /* note the reversal; q0<=q1 */
sel.r[i].q0 = sp->r[i].q1; sel.r[i].q0 = sp->r[i].q1;
sel.r[i].q1 = sp->r[i].q0; sel.r[i].q1 = sp->r[i].q0;
} }

646
rows.c

File diff suppressed because it is too large Load diff

114
scrl.c
View file

@ -12,77 +12,73 @@
#include "dat.h" #include "dat.h"
#include "fns.h" #include "fns.h"
static Image *scrtmp; static Image* scrtmp;
static static Rectangle scrpos(Rectangle r, uint p0, uint p1, uint tot) {
Rectangle
scrpos(Rectangle r, uint p0, uint p1, uint tot)
{
Rectangle q; Rectangle q;
int h; int h;
q = r; q = r;
h = q.max.y-q.min.y; h = q.max.y - q.min.y;
if(tot == 0) if (tot == 0)
return q; return q;
if(tot > 1024*1024){ if (tot > 1024 * 1024) {
tot>>=10; tot >>= 10;
p0>>=10; p0 >>= 10;
p1>>=10; p1 >>= 10;
} }
if(p0 > 0) if (p0 > 0)
q.min.y += h*p0/tot; q.min.y += h * p0 / tot;
if(p1 < tot) if (p1 < tot)
q.max.y -= h*(tot-p1)/tot; q.max.y -= h * (tot - p1) / tot;
if(q.max.y < q.min.y+2){ if (q.max.y < q.min.y + 2) {
if(q.min.y+2 <= r.max.y) if (q.min.y + 2 <= r.max.y)
q.max.y = q.min.y+2; q.max.y = q.min.y + 2;
else else
q.min.y = q.max.y-2; q.min.y = q.max.y - 2;
} }
return q; return q;
} }
void void scrlresize(void) {
scrlresize(void)
{
freeimage(scrtmp); freeimage(scrtmp);
scrtmp = allocimage(display, Rect(0, 0, 32, screen->r.max.y), screen->chan, 0, DNofill); scrtmp = allocimage(
if(scrtmp == nil) display,
Rect(0, 0, 32, screen->r.max.y),
screen->chan,
0,
DNofill);
if (scrtmp == nil)
error("scroll alloc"); error("scroll alloc");
} }
void void textscrdraw(Text* t) {
textscrdraw(Text *t)
{
Rectangle r, r1, r2; Rectangle r, r1, r2;
Image *b; Image* b;
if(t->w==nil || t!=&t->w->body) if (t->w == nil || t != &t->w->body)
return; return;
if(scrtmp == nil) if (scrtmp == nil)
scrlresize(); scrlresize();
r = t->scrollr; r = t->scrollr;
b = scrtmp; b = scrtmp;
r1 = r; r1 = r;
r1.min.x = 0; r1.min.x = 0;
r1.max.x = Dx(r); r1.max.x = Dx(r);
r2 = scrpos(r1, t->org, t->org+t->fr.nchars, t->file->b.nc); r2 = scrpos(r1, t->org, t->org + t->fr.nchars, t->file->b.nc);
if(!eqrect(r2, t->lastsr)){ if (!eqrect(r2, t->lastsr)) {
t->lastsr = r2; t->lastsr = r2;
draw(b, r1, t->fr.cols[BORD], nil, ZP); draw(b, r1, t->fr.cols[BORD], nil, ZP);
draw(b, r2, t->fr.cols[BACK], nil, ZP); draw(b, r2, t->fr.cols[BACK], nil, ZP);
r2.min.x = r2.max.x-1; r2.min.x = r2.max.x - 1;
draw(b, r2, t->fr.cols[BORD], nil, ZP); draw(b, r2, t->fr.cols[BORD], nil, ZP);
draw(t->fr.b, r, b, nil, Pt(0, r1.min.y)); draw(t->fr.b, r, b, nil, Pt(0, r1.min.y));
/*flushimage(display, 1); // BUG? */ /*flushimage(display, 1); // BUG? */
} }
} }
void void scrsleep(uint dt) {
scrsleep(uint dt) Timer* timer;
{
Timer *timer;
static Alt alts[3]; static Alt alts[3];
timer = timerstart(dt); timer = timerstart(dt);
@ -93,8 +89,8 @@ scrsleep(uint dt)
alts[1].v = &mousectl->m; alts[1].v = &mousectl->m;
alts[1].op = CHANRCV; alts[1].op = CHANRCV;
alts[2].op = CHANEND; alts[2].op = CHANEND;
for(;;) for (;;)
switch(alt(alts)){ switch (alt(alts)) {
case 0: case 0:
timerstop(timer); timerstop(timer);
return; return;
@ -104,56 +100,54 @@ scrsleep(uint dt)
} }
} }
void void textscroll(Text* t, int but) {
textscroll(Text *t, int but)
{
uint p0, oldp0; uint p0, oldp0;
Rectangle s; Rectangle s;
int x, y, my, h, first; int x, y, my, h, first;
s = insetrect(t->scrollr, 1); s = insetrect(t->scrollr, 1);
h = s.max.y-s.min.y; h = s.max.y - s.min.y;
x = (s.min.x+s.max.x)/2; x = (s.min.x + s.max.x) / 2;
oldp0 = ~0; oldp0 = ~0;
first = TRUE; first = TRUE;
do{ do {
flushimage(display, 1); flushimage(display, 1);
my = mouse->xy.y; my = mouse->xy.y;
if(my < s.min.y) if (my < s.min.y)
my = s.min.y; my = s.min.y;
if(my >= s.max.y) if (my >= s.max.y)
my = s.max.y; my = s.max.y;
if(!eqpt(mouse->xy, Pt(x, my))){ if (!eqpt(mouse->xy, Pt(x, my))) {
moveto(mousectl, Pt(x, my)); moveto(mousectl, Pt(x, my));
readmouse(mousectl); /* absorb event generated by moveto() */ readmouse(mousectl); /* absorb event generated by moveto() */
} }
if(but == 2){ if (but == 2) {
y = my; y = my;
p0 = (vlong)t->file->b.nc*(y-s.min.y)/h; p0 = (vlong)t->file->b.nc * (y - s.min.y) / h;
if(p0 >= t->q1) if (p0 >= t->q1)
p0 = textbacknl(t, p0, 2); p0 = textbacknl(t, p0, 2);
if(oldp0 != p0) if (oldp0 != p0)
textsetorigin(t, p0, FALSE); textsetorigin(t, p0, FALSE);
oldp0 = p0; oldp0 = p0;
readmouse(mousectl); readmouse(mousectl);
continue; continue;
} }
if(but == 1) if (but == 1)
p0 = textbacknl(t, t->org, (my-s.min.y)/t->fr.font->height); p0 = textbacknl(t, t->org, (my - s.min.y) / t->fr.font->height);
else else
p0 = t->org+frcharofpt(&t->fr, Pt(s.max.x, my)); p0 = t->org + frcharofpt(&t->fr, Pt(s.max.x, my));
if(oldp0 != p0) if (oldp0 != p0)
textsetorigin(t, p0, TRUE); textsetorigin(t, p0, TRUE);
oldp0 = p0; oldp0 = p0;
/* debounce */ /* debounce */
if(first){ if (first) {
flushimage(display, 1); flushimage(display, 1);
sleep(200); sleep(200);
nbrecv(mousectl->c, &mousectl->m); nbrecv(mousectl->c, &mousectl->m);
first = FALSE; first = FALSE;
} }
scrsleep(80); scrsleep(80);
}while(mouse->buttons & (1<<(but-1))); } while (mouse->buttons & (1 << (but - 1)));
while(mouse->buttons) while (mouse->buttons)
readmouse(mousectl); readmouse(mousectl);
} }

1138
text.c

File diff suppressed because it is too large Load diff

69
time.c
View file

@ -13,32 +13,18 @@
#include "fns.h" #include "fns.h"
static Channel* ctimer; /* chan(Timer*)[100] */ static Channel* ctimer; /* chan(Timer*)[100] */
static Timer *timer; static Timer* timer;
static static uint msec(void) { return nsec() / 1000000; }
uint
msec(void)
{
return nsec()/1000000;
}
void void timerstop(Timer* t) {
timerstop(Timer *t)
{
t->next = timer; t->next = timer;
timer = t; timer = t;
} }
void void timercancel(Timer* t) { t->cancel = TRUE; }
timercancel(Timer *t)
{
t->cancel = TRUE;
}
static static void timerproc(void* v) {
void
timerproc(void *v)
{
int i, nt, na, dt, del; int i, nt, na, dt, del;
Timer **t, *x; Timer **t, *x;
uint old, new; uint old, new;
@ -50,68 +36,65 @@ timerproc(void *v)
na = 0; na = 0;
nt = 0; nt = 0;
old = msec(); old = msec();
for(;;){ for (;;) {
sleep(10); /* longer sleeps here delay recv on ctimer, but 10ms should not be noticeable */ sleep(10); /* longer sleeps here delay recv on ctimer, but 10ms should not
be noticeable */
new = msec(); new = msec();
dt = new-old; dt = new - old;
old = new; old = new;
if(dt < 0) /* timer wrapped; go around, losing a tick */ if (dt < 0) /* timer wrapped; go around, losing a tick */
continue; continue;
for(i=0; i<nt; i++){ for (i = 0; i < nt; i++) {
x = t[i]; x = t[i];
x->dt -= dt; x->dt -= dt;
del = FALSE; del = FALSE;
if(x->cancel){ if (x->cancel) {
timerstop(x); timerstop(x);
del = TRUE; del = TRUE;
}else if(x->dt <= 0){ } else if (x->dt <= 0) {
/* /*
* avoid possible deadlock if client is * avoid possible deadlock if client is
* now sending on ctimer * now sending on ctimer
*/ */
if(nbsendul(x->c, 0) > 0) if (nbsendul(x->c, 0) > 0)
del = TRUE; del = TRUE;
} }
if(del){ if (del) {
memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]); memmove(&t[i], &t[i + 1], (nt - i - 1) * sizeof t[0]);
--nt; --nt;
--i; --i;
} }
} }
if(nt == 0){ if (nt == 0) {
x = recvp(ctimer); x = recvp(ctimer);
gotit: gotit:
if(nt == na){ if (nt == na) {
na += 10; na += 10;
t = realloc(t, na*sizeof(Timer*)); t = realloc(t, na * sizeof(Timer*));
if(t == nil) if (t == nil)
error("timer realloc failed"); error("timer realloc failed");
} }
t[nt++] = x; t[nt++] = x;
old = msec(); old = msec();
} }
if(nbrecv(ctimer, &x) > 0) if (nbrecv(ctimer, &x) > 0)
goto gotit; goto gotit;
} }
} }
void void timerinit(void) {
timerinit(void)
{
ctimer = chancreate(sizeof(Timer*), 100); ctimer = chancreate(sizeof(Timer*), 100);
chansetname(ctimer, "ctimer"); chansetname(ctimer, "ctimer");
proccreate(timerproc, nil, STACK); proccreate(timerproc, nil, STACK);
} }
Timer* Timer* timerstart(int dt) {
timerstart(int dt) Timer* t;
{
Timer *t;
t = timer; t = timer;
if(t) if (t)
timer = timer->next; timer = timer->next;
else{ else {
t = emalloc(sizeof(Timer)); t = emalloc(sizeof(Timer));
t->c = chancreate(sizeof(int), 0); t->c = chancreate(sizeof(int), 0);
chansetname(t->c, "tc%p", t->c); chansetname(t->c, "tc%p", t->c);

305
util.c
View file

@ -13,11 +13,9 @@
#include "fns.h" #include "fns.h"
static Point prevmouse; static Point prevmouse;
static Window *mousew; static Window* mousew;
Range Range range(int q0, int q1) {
range(int q0, int q1)
{
Range r; Range r;
r.q0 = q0; r.q0 = q0;
@ -25,9 +23,7 @@ range(int q0, int q1)
return r; return r;
} }
Runestr Runestr runestr(Rune* r, uint n) {
runestr(Rune *r, uint n)
{
Runestr rs; Runestr rs;
rs.r = r; rs.r = r;
@ -35,11 +31,9 @@ runestr(Rune *r, uint n)
return rs; return rs;
} }
void void cvttorunes(char* p, int n, Rune* r, int* nb, int* nr, int* nulls) {
cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls) uchar* q;
{ Rune* s;
uchar *q;
Rune *s;
int j, w; int j, w;
/* /*
@ -51,80 +45,74 @@ cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
*/ */
q = (uchar*)p; q = (uchar*)p;
s = r; s = r;
for(j=0; j<n; j+=w){ for (j = 0; j < n; j += w) {
if(*q < Runeself){ if (*q < Runeself) {
w = 1; w = 1;
*s = *q++; *s = *q++;
}else{ } else {
w = chartorune(s, (char*)q); w = chartorune(s, (char*)q);
q += w; q += w;
} }
if(*s) if (*s)
s++; s++;
else if(nulls) else if (nulls)
*nulls = TRUE; *nulls = TRUE;
} }
*nb = (char*)q-p; *nb = (char*)q - p;
*nr = s-r; *nr = s - r;
} }
void void error(char* s) {
error(char *s)
{
fprint(2, "acme: %s: %r\n", s); fprint(2, "acme: %s: %r\n", s);
threadexitsall(nil); threadexitsall(nil);
} }
Window* Window* errorwin1(Rune* dir, int ndir, Rune** incl, int nincl) {
errorwin1(Rune *dir, int ndir, Rune **incl, int nincl) Window* w;
{ Rune* r;
Window *w;
Rune *r;
int i, n; int i, n;
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 }; static Rune Lpluserrors[] = {'+', 'E', 'r', 'r', 'o', 'r', 's', 0};
r = runemalloc(ndir+8); r = runemalloc(ndir + 8);
if((n = ndir) != 0){ if ((n = ndir) != 0) {
runemove(r, dir, ndir); runemove(r, dir, ndir);
r[n++] = L'/'; r[n++] = L'/';
} }
runemove(r+n, Lpluserrors, 7); runemove(r + n, Lpluserrors, 7);
n += 7; n += 7;
w = lookfile(r, n); w = lookfile(r, n);
if(w == nil){ if (w == nil) {
if(row.ncol == 0) if (row.ncol == 0)
if(rowadd(&row, nil, -1) == nil) if (rowadd(&row, nil, -1) == nil)
error("can't create column to make error window"); error("can't create column to make error window");
w = coladd(row.col[row.ncol-1], nil, nil, -1); w = coladd(row.col[row.ncol - 1], nil, nil, -1);
w->filemenu = FALSE; w->filemenu = FALSE;
winsetname(w, r, n); winsetname(w, r, n);
xfidlog(w, "new"); xfidlog(w, "new");
} }
free(r); free(r);
for(i=nincl; --i>=0; ){ for (i = nincl; --i >= 0;) {
n = runestrlen(incl[i]); n = runestrlen(incl[i]);
r = runemalloc(n); r = runemalloc(n);
runemove(r, incl[i], n); runemove(r, incl[i], n);
winaddincl(w, r, n); winaddincl(w, r, n);
} }
for(i=0; i<NINDENT; i++) for (i = 0; i < NINDENT; i++)
w->indent[i] = globalindent[i]; w->indent[i] = globalindent[i];
return w; return w;
} }
/* make new window, if necessary; return with it locked */ /* make new window, if necessary; return with it locked */
Window* Window* errorwin(Mntdir* md, int owner) {
errorwin(Mntdir *md, int owner) Window* w;
{
Window *w;
for(;;){ for (;;) {
if(md == nil) if (md == nil)
w = errorwin1(nil, 0, nil, 0); w = errorwin1(nil, 0, nil, 0);
else else
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl); w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
winlock(w, owner); winlock(w, owner);
if(w->col != nil) if (w->col != nil)
break; break;
/* window was deleted too fast */ /* window was deleted too fast */
winunlock(w); winunlock(w);
@ -137,37 +125,35 @@ errorwin(Mntdir *md, int owner)
* It will be unlocked and returned window * It will be unlocked and returned window
* will be locked in its place. * will be locked in its place.
*/ */
Window* Window* errorwinforwin(Window* w) {
errorwinforwin(Window *w)
{
int i, n, nincl, owner; int i, n, nincl, owner;
Rune **incl; Rune** incl;
Runestr dir; Runestr dir;
Text *t; Text* t;
t = &w->body; t = &w->body;
dir = dirname(t, nil, 0); dir = dirname(t, nil, 0);
if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ if (dir.nr == 1 && dir.r[0] == '.') { /* sigh */
free(dir.r); free(dir.r);
dir.r = nil; dir.r = nil;
dir.nr = 0; dir.nr = 0;
} }
incl = nil; incl = nil;
nincl = w->nincl; nincl = w->nincl;
if(nincl > 0){ if (nincl > 0) {
incl = emalloc(nincl*sizeof(Rune*)); incl = emalloc(nincl * sizeof(Rune*));
for(i=0; i<nincl; i++){ for (i = 0; i < nincl; i++) {
n = runestrlen(w->incl[i]); n = runestrlen(w->incl[i]);
incl[i] = runemalloc(n+1); incl[i] = runemalloc(n + 1);
runemove(incl[i], w->incl[i], n); runemove(incl[i], w->incl[i], n);
} }
} }
owner = w->owner; owner = w->owner;
winunlock(w); winunlock(w);
for(;;){ for (;;) {
w = errorwin1(dir.r, dir.nr, incl, nincl); w = errorwin1(dir.r, dir.nr, incl, nincl);
winlock(w, owner); winlock(w, owner);
if(w->col != nil) if (w->col != nil)
break; break;
/* window deleted too fast */ /* window deleted too fast */
winunlock(w); winunlock(w);
@ -177,22 +163,19 @@ errorwinforwin(Window *w)
typedef struct Warning Warning; typedef struct Warning Warning;
struct Warning{ struct Warning {
Mntdir *md; Mntdir* md;
Buffer buf; Buffer buf;
Warning *next; Warning* next;
}; };
static Warning *warnings; static Warning* warnings;
static static void addwarningtext(Mntdir* md, Rune* r, int nr) {
void Warning* warn;
addwarningtext(Mntdir *md, Rune *r, int nr)
{
Warning *warn;
for(warn = warnings; warn; warn=warn->next){ for (warn = warnings; warn; warn = warn->next) {
if(warn->md == md){ if (warn->md == md) {
bufinsert(&warn->buf, warn->buf.nc, r, nr); bufinsert(&warn->buf, warn->buf.nc, r, nr);
return; return;
} }
@ -200,7 +183,7 @@ addwarningtext(Mntdir *md, Rune *r, int nr)
warn = emalloc(sizeof(Warning)); warn = emalloc(sizeof(Warning));
warn->next = warnings; warn->next = warnings;
warn->md = md; warn->md = md;
if(md) if (md)
fsysincid(md); fsysincid(md);
warnings = warn; warnings = warn;
bufinsert(&warn->buf, 0, r, nr); bufinsert(&warn->buf, 0, r, nr);
@ -208,20 +191,18 @@ addwarningtext(Mntdir *md, Rune *r, int nr)
} }
/* called while row is locked */ /* called while row is locked */
void void flushwarnings(void) {
flushwarnings(void)
{
Warning *warn, *next; Warning *warn, *next;
Window *w; Window* w;
Text *t; Text* t;
int owner, nr, q0, n; int owner, nr, q0, n;
Rune *r; Rune* r;
for(warn=warnings; warn; warn=next) { for (warn = warnings; warn; warn = next) {
w = errorwin(warn->md, 'E'); w = errorwin(warn->md, 'E');
t = &w->body; t = &w->body;
owner = w->owner; owner = w->owner;
if(owner == 0) if (owner == 0)
w->owner = 'E'; w->owner = 'E';
wincommit(w, t); wincommit(w, t);
/* /*
@ -234,9 +215,9 @@ flushwarnings(void)
*/ */
r = fbufalloc(); r = fbufalloc();
q0 = t->file->b.nc; q0 = t->file->b.nc;
for(n = 0; n < warn->buf.nc; n += nr){ for (n = 0; n < warn->buf.nc; n += nr) {
nr = warn->buf.nc - n; nr = warn->buf.nc - n;
if(nr > RBUFSIZE) if (nr > RBUFSIZE)
nr = RBUFSIZE; nr = RBUFSIZE;
bufread(&warn->buf, n, r, nr); bufread(&warn->buf, n, r, nr);
textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr); textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
@ -250,117 +231,95 @@ flushwarnings(void)
winunlock(w); winunlock(w);
bufclose(&warn->buf); bufclose(&warn->buf);
next = warn->next; next = warn->next;
if(warn->md) if (warn->md)
fsysdelid(warn->md); fsysdelid(warn->md);
free(warn); free(warn);
} }
warnings = nil; warnings = nil;
} }
void void warning(Mntdir* md, char* s, ...) {
warning(Mntdir *md, char *s, ...) Rune* r;
{
Rune *r;
va_list arg; va_list arg;
va_start(arg, s); va_start(arg, s);
r = runevsmprint(s, arg); r = runevsmprint(s, arg);
va_end(arg); va_end(arg);
if(r == nil) if (r == nil)
error("runevsmprint failed"); error("runevsmprint failed");
addwarningtext(md, r, runestrlen(r)); addwarningtext(md, r, runestrlen(r));
free(r); free(r);
} }
int int runeeq(Rune* s1, uint n1, Rune* s2, uint n2) {
runeeq(Rune *s1, uint n1, Rune *s2, uint n2) if (n1 != n2)
{
if(n1 != n2)
return FALSE; return FALSE;
return memcmp(s1, s2, n1*sizeof(Rune)) == 0; return memcmp(s1, s2, n1 * sizeof(Rune)) == 0;
} }
uint uint min(uint a, uint b) {
min(uint a, uint b) if (a < b)
{
if(a < b)
return a; return a;
return b; return b;
} }
uint uint max(uint a, uint b) {
max(uint a, uint b) if (a > b)
{
if(a > b)
return a; return a;
return b; return b;
} }
char* char* runetobyte(Rune* r, int n) {
runetobyte(Rune *r, int n) char* s;
{
char *s;
if(r == nil) if (r == nil)
return nil; return nil;
s = emalloc(n*UTFmax+1); s = emalloc(n * UTFmax + 1);
setmalloctag(s, getcallerpc(&r)); setmalloctag(s, getcallerpc(&r));
snprint(s, n*UTFmax+1, "%.*S", n, r); snprint(s, n * UTFmax + 1, "%.*S", n, r);
return s; return s;
} }
Rune* Rune* bytetorune(char* s, int* ip) {
bytetorune(char *s, int *ip) Rune* r;
{
Rune *r;
int nb, nr; int nb, nr;
nb = strlen(s); nb = strlen(s);
r = runemalloc(nb+1); r = runemalloc(nb + 1);
cvttorunes(s, nb, r, &nb, &nr, nil); cvttorunes(s, nb, r, &nb, &nr, nil);
r[nr] = '\0'; r[nr] = '\0';
*ip = nr; *ip = nr;
return r; return r;
} }
int int isalnum(Rune c) {
isalnum(Rune c)
{
/* /*
* Hard to get absolutely right. Use what we know about ASCII * Hard to get absolutely right. Use what we know about ASCII
* and assume anything above the Latin control characters is * and assume anything above the Latin control characters is
* potentially an alphanumeric. * potentially an alphanumeric.
*/ */
if(c <= ' ') if (c <= ' ')
return FALSE; return FALSE;
if(0x7F<=c && c<=0xA0) if (0x7F <= c && c <= 0xA0)
return FALSE; return FALSE;
if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) if (utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
return FALSE; return FALSE;
return TRUE; return TRUE;
} }
int int rgetc(void* v, uint n) { return ((Rune*)v)[n]; }
rgetc(void *v, uint n)
{
return ((Rune*)v)[n];
}
int int tgetc(void* a, uint n) {
tgetc(void *a, uint n) Text* t;
{
Text *t;
t = a; t = a;
if(n >= t->file->b.nc) if (n >= t->file->b.nc)
return 0; return 0;
return textreadc(t, n); return textreadc(t, n);
} }
Rune* Rune* skipbl(Rune* r, int n, int* np) {
skipbl(Rune *r, int n, int *np) while (n > 0 && (*r == ' ' || *r == '\t' || *r == '\n')) {
{
while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){
--n; --n;
r++; r++;
} }
@ -368,10 +327,8 @@ skipbl(Rune *r, int n, int *np)
return r; return r;
} }
Rune* Rune* findbl(Rune* r, int n, int* np) {
findbl(Rune *r, int n, int *np) while (n > 0 && *r != ' ' && *r != '\t' && *r != '\n') {
{
while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
--n; --n;
r++; r++;
} }
@ -379,20 +336,16 @@ findbl(Rune *r, int n, int *np)
return r; return r;
} }
void void savemouse(Window* w) {
savemouse(Window *w)
{
prevmouse = mouse->xy; prevmouse = mouse->xy;
mousew = w; mousew = w;
} }
int int restoremouse(Window* w) {
restoremouse(Window *w)
{
int did; int did;
did = 0; did = 0;
if(mousew!=nil && mousew==w) { if (mousew != nil && mousew == w) {
moveto(mousectl, prevmouse); moveto(mousectl, prevmouse);
did = 1; did = 1;
} }
@ -400,42 +353,32 @@ restoremouse(Window *w)
return did; return did;
} }
void void clearmouse() { mousew = nil; }
clearmouse()
{
mousew = nil;
}
char* char* estrdup(char* s) {
estrdup(char *s) char* t;
{
char *t;
t = strdup(s); t = strdup(s);
if(t == nil) if (t == nil)
error("strdup failed"); error("strdup failed");
setmalloctag(t, getcallerpc(&s)); setmalloctag(t, getcallerpc(&s));
return t; return t;
} }
void* void* emalloc(uint n) {
emalloc(uint n) void* p;
{
void *p;
p = malloc(n); p = malloc(n);
if(p == nil) if (p == nil)
error("malloc failed"); error("malloc failed");
setmalloctag(p, getcallerpc(&n)); setmalloctag(p, getcallerpc(&n));
memset(p, 0, n); memset(p, 0, n);
return p; return p;
} }
void* void* erealloc(void* p, uint n) {
erealloc(void *p, uint n)
{
p = realloc(p, n); p = realloc(p, n);
if(p == nil) if (p == nil)
error("realloc failed"); error("realloc failed");
setmalloctag(p, getcallerpc(&n)); setmalloctag(p, getcallerpc(&n));
return p; return p;
@ -444,53 +387,53 @@ erealloc(void *p, uint n)
/* /*
* Heuristic city. * Heuristic city.
*/ */
Window* Window* makenewwindow(Text* t) {
makenewwindow(Text *t) Column* c;
{
Column *c;
Window *w, *bigw, *emptyw; Window *w, *bigw, *emptyw;
Text *emptyb; Text* emptyb;
int i, y, el; int i, y, el;
if(activecol) if (activecol)
c = activecol; c = activecol;
else if(seltext && seltext->col) else if (seltext && seltext->col)
c = seltext->col; c = seltext->col;
else if(t && t->col) else if (t && t->col)
c = t->col; c = t->col;
else{ else {
if(row.ncol==0 && rowadd(&row, nil, -1)==nil) if (row.ncol == 0 && rowadd(&row, nil, -1) == nil)
error("can't make column"); error("can't make column");
c = row.col[row.ncol-1]; c = row.col[row.ncol - 1];
} }
activecol = c; activecol = c;
if(t==nil || t->w==nil || c->nw==0) if (t == nil || t->w == nil || c->nw == 0)
return coladd(c, nil, nil, -1); return coladd(c, nil, nil, -1);
/* find biggest window and biggest blank spot */ /* find biggest window and biggest blank spot */
emptyw = c->w[0]; emptyw = c->w[0];
bigw = emptyw; bigw = emptyw;
for(i=1; i<c->nw; i++){ for (i = 1; i < c->nw; i++) {
w = c->w[i]; w = c->w[i];
/* use >= to choose one near bottom of screen */ /* use >= to choose one near bottom of screen */
if(w->body.fr.maxlines >= bigw->body.fr.maxlines) if (w->body.fr.maxlines >= bigw->body.fr.maxlines)
bigw = w; bigw = w;
if(w->body.fr.maxlines-w->body.fr.nlines >= emptyw->body.fr.maxlines-emptyw->body.fr.nlines) if (
w->body.fr.maxlines - w->body.fr.nlines >=
emptyw->body.fr.maxlines - emptyw->body.fr.nlines)
emptyw = w; emptyw = w;
} }
emptyb = &emptyw->body; emptyb = &emptyw->body;
el = emptyb->fr.maxlines-emptyb->fr.nlines; el = emptyb->fr.maxlines - emptyb->fr.nlines;
/* if empty space is big, use it */ /* if empty space is big, use it */
if(el>15 || (el>3 && el>(bigw->body.fr.maxlines-1)/2)) if (el > 15 || (el > 3 && el > (bigw->body.fr.maxlines - 1) / 2))
y = emptyb->fr.r.min.y+emptyb->fr.nlines*font->height; y = emptyb->fr.r.min.y + emptyb->fr.nlines * font->height;
else{ else {
/* if this window is in column and isn't much smaller, split it */ /* if this window is in column and isn't much smaller, split it */
if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3) if (t->col == c && Dy(t->w->r) > 2 * Dy(bigw->r) / 3)
bigw = t->w; bigw = t->w;
y = (bigw->r.min.y + bigw->r.max.y)/2; y = (bigw->r.min.y + bigw->r.max.y) / 2;
} }
w = coladd(c, nil, nil, y); w = coladd(c, nil, nil, y);
if(w->body.fr.maxlines < 2) if (w->body.fr.maxlines < 2)
colgrow(w->col, w, 1); colgrow(w->col, w, 1);
return w; return w;
} }

501
wind.c
View file

@ -14,13 +14,11 @@
int winid; int winid;
void void wininit(Window* w, Window* clone, Rectangle r) {
wininit(Window *w, Window *clone, Rectangle r)
{
Rectangle r1, br; Rectangle r1, br;
File *f; File* f;
Reffont *rf; Reffont* rf;
Rune *rp; Rune* rp;
int nc, i; int nc, i;
w->tag.w = w; w->tag.w = w;
@ -29,7 +27,7 @@ wininit(Window *w, Window *clone, Rectangle r)
w->body.w = w; w->body.w = w;
w->id = ++winid; w->id = ++winid;
incref(&w->ref); incref(&w->ref);
if(globalincref) if (globalincref)
incref(&w->ref); incref(&w->ref);
w->ctlfid = ~0; w->ctlfid = ~0;
w->utflastqid = -1; w->utflastqid = -1;
@ -37,14 +35,14 @@ wininit(Window *w, Window *clone, Rectangle r)
w->tagtop = r; w->tagtop = r;
w->tagtop.max.y = r.min.y + font->height; w->tagtop.max.y = r.min.y + font->height;
r1.max.y = r1.min.y + w->taglines*font->height; r1.max.y = r1.min.y + w->taglines * font->height;
incref(&reffont.ref); incref(&reffont.ref);
f = fileaddtext(nil, &w->tag); f = fileaddtext(nil, &w->tag);
textinit(&w->tag, f, r1, &reffont, tagcols); textinit(&w->tag, f, r1, &reffont, tagcols);
w->tag.what = Tag; w->tag.what = Tag;
/* tag is a copy of the contents, not a tracked image */ /* tag is a copy of the contents, not a tracked image */
if(clone){ if (clone) {
textdelete(&w->tag, 0, w->tag.file->b.nc, TRUE); textdelete(&w->tag, 0, w->tag.file->b.nc, TRUE);
nc = clone->tag.file->b.nc; nc = clone->tag.file->b.nc;
rp = runemalloc(nc); rp = runemalloc(nc);
@ -55,22 +53,22 @@ wininit(Window *w, Window *clone, Rectangle r)
textsetselect(&w->tag, nc, nc); textsetselect(&w->tag, nc, nc);
} }
r1 = r; r1 = r;
r1.min.y += w->taglines*font->height + 1; r1.min.y += w->taglines * font->height + 1;
if(r1.max.y < r1.min.y) if (r1.max.y < r1.min.y)
r1.max.y = r1.min.y; r1.max.y = r1.min.y;
f = nil; f = nil;
if(clone){ if (clone) {
f = clone->body.file; f = clone->body.file;
w->body.org = clone->body.org; w->body.org = clone->body.org;
w->isscratch = clone->isscratch; w->isscratch = clone->isscratch;
rf = rfget(FALSE, FALSE, FALSE, clone->body.reffont->f->name); rf = rfget(FALSE, FALSE, FALSE, clone->body.reffont->f->name);
}else } else
rf = rfget(FALSE, FALSE, FALSE, nil); rf = rfget(FALSE, FALSE, FALSE, nil);
f = fileaddtext(f, &w->body); f = fileaddtext(f, &w->body);
w->body.what = Body; w->body.what = Body;
textinit(&w->body, f, r1, rf, textcols); textinit(&w->body, f, r1, rf, textcols);
r1.min.y -= 1; r1.min.y -= 1;
r1.max.y = r1.min.y+1; r1.max.y = r1.min.y + 1;
draw(screen, r1, tagcols[BORD], nil, ZP); draw(screen, r1, tagcols[BORD], nil, ZP);
textscrdraw(&w->body); textscrdraw(&w->body);
w->r = r; w->r = r;
@ -80,11 +78,11 @@ wininit(Window *w, Window *clone, Rectangle r)
draw(screen, br, button, nil, button->r.min); draw(screen, br, button, nil, button->r.min);
w->filemenu = TRUE; w->filemenu = TRUE;
w->maxlines = w->body.fr.maxlines; w->maxlines = w->body.fr.maxlines;
for(i=0; i<NINDENT; i++) for (i = 0; i < NINDENT; i++)
w->indent[i] = globalindent[i]; w->indent[i] = globalindent[i];
if(clone){ if (clone) {
w->dirty = clone->dirty; w->dirty = clone->dirty;
for(i=0; i<NINDENT; i++) for (i = 0; i < NINDENT; i++)
w->indent[i] = clone->indent[i]; w->indent[i] = clone->indent[i];
textsetselect(&w->body, clone->body.q0, clone->body.q1); textsetselect(&w->body, clone->body.q0, clone->body.q1);
winsettag(w); winsettag(w);
@ -94,14 +92,12 @@ wininit(Window *w, Window *clone, Rectangle r)
/* /*
* Draw the appropriate button. * Draw the appropriate button.
*/ */
void void windrawbutton(Window* w) {
windrawbutton(Window *w) Image* b;
{
Image *b;
Rectangle br; Rectangle br;
b = button; b = button;
if(!w->isdir && !w->isscratch && (w->body.file->mod || w->body.ncache)) if (!w->isdir && !w->isscratch && (w->body.file->mod || w->body.ncache))
b = modbutton; b = modbutton;
br.min = w->tag.scrollr.min; br.min = w->tag.scrollr.min;
br.max.x = br.min.x + Dx(b->r); br.max.x = br.min.x + Dx(b->r);
@ -109,46 +105,42 @@ windrawbutton(Window *w)
draw(screen, br, b, nil, b->r.min); draw(screen, br, b, nil, b->r.min);
} }
int int delrunepos(Window* w) {
delrunepos(Window *w)
{
int n; int n;
Rune rune; Rune rune;
for(n=0; n<w->tag.file->b.nc; n++) { for (n = 0; n < w->tag.file->b.nc; n++) {
bufread(&w->tag.file->b, n, &rune, 1); bufread(&w->tag.file->b, n, &rune, 1);
if(rune == ' ') if (rune == ' ')
break; break;
} }
n += 2; n += 2;
if(n >= w->tag.file->b.nc) if (n >= w->tag.file->b.nc)
return -1; return -1;
return n; return n;
} }
void void movetodel(Window* w) {
movetodel(Window *w)
{
int n; int n;
n = delrunepos(w); n = delrunepos(w);
if(n < 0) if (n < 0)
return; return;
moveto(mousectl, addpt(frptofchar(&w->tag.fr, n), Pt(4, w->tag.fr.font->height-4))); moveto(
mousectl,
addpt(frptofchar(&w->tag.fr, n), Pt(4, w->tag.fr.font->height - 4)));
} }
/* /*
* Compute number of tag lines required * Compute number of tag lines required
* to display entire tag text. * to display entire tag text.
*/ */
int int wintaglines(Window* w, Rectangle r) {
wintaglines(Window *w, Rectangle r)
{
int n; int n;
Rune rune; Rune rune;
Point p; Point p;
if(!w->tagexpand && !w->showdel) if (!w->tagexpand && !w->showdel)
return 1; return 1;
w->showdel = FALSE; w->showdel = FALSE;
w->tag.fr.noredraw = 1; w->tag.fr.noredraw = 1;
@ -156,34 +148,32 @@ wintaglines(Window *w, Rectangle r)
w->tag.fr.noredraw = 0; w->tag.fr.noredraw = 0;
w->tagsafe = FALSE; w->tagsafe = FALSE;
if(!w->tagexpand) { if (!w->tagexpand) {
/* use just as many lines as needed to show the Del */ /* use just as many lines as needed to show the Del */
n = delrunepos(w); n = delrunepos(w);
if(n < 0) if (n < 0)
return 1; return 1;
p = subpt(frptofchar(&w->tag.fr, n), w->tag.fr.r.min); p = subpt(frptofchar(&w->tag.fr, n), w->tag.fr.r.min);
return 1 + p.y / w->tag.fr.font->height; return 1 + p.y / w->tag.fr.font->height;
} }
/* can't use more than we have */ /* can't use more than we have */
if(w->tag.fr.nlines >= w->tag.fr.maxlines) if (w->tag.fr.nlines >= w->tag.fr.maxlines)
return w->tag.fr.maxlines; return w->tag.fr.maxlines;
/* if tag ends with \n, include empty line at end for typing */ /* if tag ends with \n, include empty line at end for typing */
n = w->tag.fr.nlines; n = w->tag.fr.nlines;
if(w->tag.file->b.nc > 0){ if (w->tag.file->b.nc > 0) {
bufread(&w->tag.file->b, w->tag.file->b.nc-1, &rune, 1); bufread(&w->tag.file->b, w->tag.file->b.nc - 1, &rune, 1);
if(rune == '\n') if (rune == '\n')
n++; n++;
} }
if(n == 0) if (n == 0)
n = 1; n = 1;
return n; return n;
} }
int int winresize(Window* w, Rectangle r, int safe, int keepextra) {
winresize(Window *w, Rectangle r, int safe, int keepextra)
{
int oy, y, mouseintag, mouseinbody; int oy, y, mouseintag, mouseinbody;
Point p; Point p;
Rectangle r1; Rectangle r1;
@ -193,36 +183,36 @@ winresize(Window *w, Rectangle r, int safe, int keepextra)
/* tagtop is first line of tag */ /* tagtop is first line of tag */
w->tagtop = r; w->tagtop = r;
w->tagtop.max.y = r.min.y+font->height; w->tagtop.max.y = r.min.y + font->height;
r1 = r; r1 = r;
r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height); r1.max.y = min(r.max.y, r1.min.y + w->taglines * font->height);
/* If needed, recompute number of lines in tag. */ /* If needed, recompute number of lines in tag. */
if(!safe || !w->tagsafe || !eqrect(w->tag.all, r1)){ if (!safe || !w->tagsafe || !eqrect(w->tag.all, r1)) {
w->taglines = wintaglines(w, r); w->taglines = wintaglines(w, r);
r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height); r1.max.y = min(r.max.y, r1.min.y + w->taglines * font->height);
} }
/* If needed, resize & redraw tag. */ /* If needed, resize & redraw tag. */
y = r1.max.y; y = r1.max.y;
if(!safe || !w->tagsafe || !eqrect(w->tag.all, r1)){ if (!safe || !w->tagsafe || !eqrect(w->tag.all, r1)) {
textresize(&w->tag, r1, TRUE); textresize(&w->tag, r1, TRUE);
y = w->tag.fr.r.max.y; y = w->tag.fr.r.max.y;
windrawbutton(w); windrawbutton(w);
w->tagsafe = TRUE; w->tagsafe = TRUE;
/* If mouse is in tag, pull up as tag closes. */ /* If mouse is in tag, pull up as tag closes. */
if(mouseintag && !ptinrect(mouse->xy, w->tag.all)){ if (mouseintag && !ptinrect(mouse->xy, w->tag.all)) {
p = mouse->xy; p = mouse->xy;
p.y = w->tag.all.max.y-3; p.y = w->tag.all.max.y - 3;
moveto(mousectl, p); moveto(mousectl, p);
} }
/* If mouse is in body, push down as tag expands. */ /* If mouse is in body, push down as tag expands. */
if(mouseinbody && ptinrect(mouse->xy, w->tag.all)){ if (mouseinbody && ptinrect(mouse->xy, w->tag.all)) {
p = mouse->xy; p = mouse->xy;
p.y = w->tag.all.max.y+3; p.y = w->tag.all.max.y + 3;
moveto(mousectl, p); moveto(mousectl, p);
} }
} }
@ -230,16 +220,16 @@ winresize(Window *w, Rectangle r, int safe, int keepextra)
/* If needed, resize & redraw body. */ /* If needed, resize & redraw body. */
r1 = r; r1 = r;
r1.min.y = y; r1.min.y = y;
if(!safe || !eqrect(w->body.all, r1)){ if (!safe || !eqrect(w->body.all, r1)) {
oy = y; oy = y;
if(y+1+w->body.fr.font->height <= r.max.y){ /* room for one line */ if (y + 1 + w->body.fr.font->height <= r.max.y) { /* room for one line */
r1.min.y = y; r1.min.y = y;
r1.max.y = y+1; r1.max.y = y + 1;
draw(screen, r1, tagcols[BORD], nil, ZP); draw(screen, r1, tagcols[BORD], nil, ZP);
y++; y++;
r1.min.y = min(y, r.max.y); r1.min.y = min(y, r.max.y);
r1.max.y = r.max.y; r1.max.y = r.max.y;
}else{ } else {
r1.min.y = y; r1.min.y = y;
r1.max.y = y; r1.max.y = y;
} }
@ -253,30 +243,24 @@ winresize(Window *w, Rectangle r, int safe, int keepextra)
return w->r.max.y; return w->r.max.y;
} }
void void winlock1(Window* w, int owner) {
winlock1(Window *w, int owner)
{
incref(&w->ref); incref(&w->ref);
qlock(&w->lk); qlock(&w->lk);
w->owner = owner; w->owner = owner;
} }
void void winlock(Window* w, int owner) {
winlock(Window *w, int owner)
{
int i; int i;
File *f; File* f;
f = w->body.file; f = w->body.file;
for(i=0; i<f->ntext; i++) for (i = 0; i < f->ntext; i++)
winlock1(f->text[i]->w, owner); winlock1(f->text[i]->w, owner);
} }
void void winunlock(Window* w) {
winunlock(Window *w)
{
int i; int i;
File *f; File* f;
/* /*
* subtle: loop runs backwards to avoid tripping over * subtle: loop runs backwards to avoid tripping over
@ -284,7 +268,7 @@ winunlock(Window *w)
* on the last iteration of the loop. * on the last iteration of the loop.
*/ */
f = w->body.file; f = w->body.file;
for(i=f->ntext-1; i>=0; i--){ for (i = f->ntext - 1; i >= 0; i--) {
w = f->text[i]->w; w = f->text[i]->w;
w->owner = 0; w->owner = 0;
qunlock(&w->lk); qunlock(&w->lk);
@ -292,21 +276,18 @@ winunlock(Window *w)
} }
} }
void void winmousebut(Window* w) {
winmousebut(Window *w) moveto(
{ mousectl,
moveto(mousectl, addpt(w->tag.scrollr.min, addpt(w->tag.scrollr.min, divpt(Pt(Dx(w->tag.scrollr), font->height), 2)));
divpt(Pt(Dx(w->tag.scrollr), font->height), 2)));
} }
void void windirfree(Window* w) {
windirfree(Window *w)
{
int i; int i;
Dirlist *dl; Dirlist* dl;
if(w->isdir){ if (w->isdir) {
for(i=0; i<w->ndl; i++){ for (i = 0; i < w->ndl; i++) {
dl = w->dlp[i]; dl = w->dlp[i];
free(dl->r); free(dl->r);
free(dl); free(dl);
@ -317,19 +298,17 @@ windirfree(Window *w)
w->ndl = 0; w->ndl = 0;
} }
void void winclose(Window* w) {
winclose(Window *w)
{
int i; int i;
if(decref(&w->ref) == 0){ if (decref(&w->ref) == 0) {
xfidlog(w, "del"); xfidlog(w, "del");
windirfree(w); windirfree(w);
textclose(&w->tag); textclose(&w->tag);
textclose(&w->body); textclose(&w->body);
if(activewin == w) if (activewin == w)
activewin = nil; activewin = nil;
for(i=0; i<w->nincl; i++) for (i = 0; i < w->nincl; i++)
free(w->incl[i]); free(w->incl[i]);
free(w->incl); free(w->incl);
free(w->events); free(w->events);
@ -337,13 +316,11 @@ winclose(Window *w)
} }
} }
void void windelete(Window* w) {
windelete(Window *w) Xfid* x;
{
Xfid *x;
x = w->eventx; x = w->eventx;
if(x){ if (x) {
w->nevents = 0; w->nevents = 0;
free(w->events); free(w->events);
w->events = nil; w->events = nil;
@ -352,164 +329,183 @@ windelete(Window *w)
} }
} }
void void winundo(Window* w, int isundo) {
winundo(Window *w, int isundo) Text* body;
{
Text *body;
int i; int i;
File *f; File* f;
Window *v; Window* v;
w->utflastqid = -1; w->utflastqid = -1;
body = &w->body; body = &w->body;
fileundo(body->file, isundo, &body->q0, &body->q1); fileundo(body->file, isundo, &body->q0, &body->q1);
textshow(body, body->q0, body->q1, 1); textshow(body, body->q0, body->q1, 1);
f = body->file; f = body->file;
for(i=0; i<f->ntext; i++){ for (i = 0; i < f->ntext; i++) {
v = f->text[i]->w; v = f->text[i]->w;
v->dirty = (f->seq != v->putseq); v->dirty = (f->seq != v->putseq);
if(v != w){ if (v != w) {
v->body.q0 = v->body.fr.p0+v->body.org; v->body.q0 = v->body.fr.p0 + v->body.org;
v->body.q1 = v->body.fr.p1+v->body.org; v->body.q1 = v->body.fr.p1 + v->body.org;
} }
} }
winsettag(w); winsettag(w);
} }
void void winsetname(Window* w, Rune* name, int n) {
winsetname(Window *w, Rune *name, int n) Text* t;
{ Window* v;
Text *t;
Window *v;
int i; int i;
static Rune Lslashguide[] = { '/', 'g', 'u', 'i', 'd', 'e', 0 }; static Rune Lslashguide[] = {'/', 'g', 'u', 'i', 'd', 'e', 0};
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 }; static Rune Lpluserrors[] = {'+', 'E', 'r', 'r', 'o', 'r', 's', 0};
t = &w->body; t = &w->body;
if(runeeq(t->file->name, t->file->nname, name, n) == TRUE) if (runeeq(t->file->name, t->file->nname, name, n) == TRUE)
return; return;
w->isscratch = FALSE; w->isscratch = FALSE;
if(n>=6 && runeeq(Lslashguide, 6, name+(n-6), 6)) if (n >= 6 && runeeq(Lslashguide, 6, name + (n - 6), 6))
w->isscratch = TRUE; w->isscratch = TRUE;
else if(n>=7 && runeeq(Lpluserrors, 7, name+(n-7), 7)) else if (n >= 7 && runeeq(Lpluserrors, 7, name + (n - 7), 7))
w->isscratch = TRUE; w->isscratch = TRUE;
filesetname(t->file, name, n); filesetname(t->file, name, n);
for(i=0; i<t->file->ntext; i++){ for (i = 0; i < t->file->ntext; i++) {
v = t->file->text[i]->w; v = t->file->text[i]->w;
winsettag(v); winsettag(v);
v->isscratch = w->isscratch; v->isscratch = w->isscratch;
} }
} }
void void wintype(Window* w, Text* t, Rune r) {
wintype(Window *w, Text *t, Rune r)
{
int i; int i;
texttype(t, r); texttype(t, r);
if(t->what == Body) if (t->what == Body)
for(i=0; i<t->file->ntext; i++) for (i = 0; i < t->file->ntext; i++)
textscrdraw(t->file->text[i]); textscrdraw(t->file->text[i]);
winsettag(w); winsettag(w);
} }
void void wincleartag(Window* w) {
wincleartag(Window *w)
{
int i, n; int i, n;
Rune *r; Rune* r;
/* w must be committed */ /* w must be committed */
n = w->tag.file->b.nc; n = w->tag.file->b.nc;
r = runemalloc(n); r = parsetag(w, &i);
bufread(&w->tag.file->b, 0, r, n); for (; i < n; i++)
for(i=0; i<n; i++) if (r[i] == '|')
if(r[i]==' ' || r[i]=='\t')
break; break;
for(; i<n; i++) if (i == n)
if(r[i] == '|')
break;
if(i == n)
return; return;
i++; i++;
textdelete(&w->tag, i, n, TRUE); textdelete(&w->tag, i, n, TRUE);
free(r); free(r);
w->tag.file->mod = FALSE; w->tag.file->mod = FALSE;
if(w->tag.q0 > i) if (w->tag.q0 > i)
w->tag.q0 = i; w->tag.q0 = i;
if(w->tag.q1 > i) if (w->tag.q1 > i)
w->tag.q1 = i; w->tag.q1 = i;
textsetselect(&w->tag, w->tag.q0, w->tag.q1); textsetselect(&w->tag, w->tag.q0, w->tag.q1);
} }
void Rune* parsetag(Window* w, int* len) {
winsettag1(Window *w) static Rune Ldelsnarf[] =
{ {' ', 'D', 'e', 'l', ' ', 'S', 'n', 'a', 'r', 'f', 0};
int i, j, k, n, bar, dirty, resize; static Rune Lspacepipe[] = {' ', '|', 0};
Rune *new, *old, *r; static Rune Ltabpipe[] = {' ', '|', 0};
uint q0, q1; int i;
static Rune Ldelsnarf[] = { ' ', 'D', 'e', 'l', ' ', Rune *r, *p, *pipe;
'S', 'n', 'a', 'r', 'f', 0 };
static Rune Lundo[] = { ' ', 'U', 'n', 'd', 'o', 0 };
static Rune Lredo[] = { ' ', 'R', 'e', 'd', 'o', 0 };
static Rune Lget[] = { ' ', 'G', 'e', 't', 0 };
static Rune Lput[] = { ' ', 'P', 'u', 't', 0 };
static Rune Llook[] = { ' ', 'L', 'o', 'o', 'k', ' ', 0 };
static Rune Lpipe[] = { ' ', '|', 0 };
/* there are races that get us here with stuff in the tag cache, so we take extra care to sync it */ r = runemalloc(w->tag.file->b.nc + 1);
if(w->tag.ncache!=0 || w->tag.file->mod) bufread(&w->tag.file->b, 0, r, w->tag.file->b.nc);
wincommit(w, &w->tag); /* check file name; also guarantees we can modify tag contents */ r[w->tag.file->b.nc] = '\0';
old = runemalloc(w->tag.file->b.nc+1);
bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc); for (i = 0; i < w->tag.file->b.nc; i++)
old[w->tag.file->b.nc] = '\0'; if (r[i] == ' ' || r[i] == '\t')
for(i=0; i<w->tag.file->b.nc; i++)
if(old[i]==' ' || old[i]=='\t')
break; break;
if(runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE){
/*
* " |" or "\t|" ends left half of tag
* If we find " Del Snarf" in the left half of the tag
* (before the pipe), that ends the file name.
*/
pipe = runestrstr(r, Lspacepipe);
if ((p = runestrstr(r, Ltabpipe)) != nil && (pipe == nil || p < pipe))
pipe = p;
if ((p = runestrstr(r, Ldelsnarf)) != nil && (pipe == nil || p < pipe))
i = p - r;
else {
for (i = 0; i < w->tag.file->b.nc; i++)
if (r[i] == ' ' || r[i] == '\t')
break;
}
*len = i;
return r;
}
void winsettag1(Window* w) {
int i, j, k, n, bar, dirty, resize;
Rune* new, *old, *r;
uint q0, q1;
static Rune Ldelsnarf[] =
{' ', 'D', 'e', 'l', ' ', 'S', 'n', 'a', 'r', 'f', 0};
static Rune Lundo[] = {' ', 'U', 'n', 'd', 'o', 0};
static Rune Lredo[] = {' ', 'R', 'e', 'd', 'o', 0};
static Rune Lget[] = {' ', 'G', 'e', 't', 0};
static Rune Lput[] = {' ', 'P', 'u', 't', 0};
static Rune Llook[] = {' ', 'L', 'o', 'o', 'k', ' ', 0};
static Rune Lpipe[] = {' ', '|', 0};
/* there are races that get us here with stuff in the tag cache, so we take
* extra care to sync it */
if (w->tag.ncache != 0 || w->tag.file->mod)
wincommit(w, &w->tag); /* check file name; also guarantees we can modify tag
contents */
old = parsetag(w, &i);
if (runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE) {
textdelete(&w->tag, 0, i, TRUE); textdelete(&w->tag, 0, i, TRUE);
textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE); textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE);
free(old); free(old);
old = runemalloc(w->tag.file->b.nc+1); old = runemalloc(w->tag.file->b.nc + 1);
bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc); bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc);
old[w->tag.file->b.nc] = '\0'; old[w->tag.file->b.nc] = '\0';
} }
/* compute the text for the whole tag, replacing current only if it differs */ /* compute the text for the whole tag, replacing current only if it differs */
new = runemalloc(w->body.file->nname+100); new = runemalloc(w->body.file->nname + 100);
i = 0; i = 0;
runemove(new+i, w->body.file->name, w->body.file->nname); runemove(new + i, w->body.file->name, w->body.file->nname);
i += w->body.file->nname; i += w->body.file->nname;
runemove(new+i, Ldelsnarf, 10); runemove(new + i, Ldelsnarf, 10);
i += 10; i += 10;
if(w->filemenu){ if (w->filemenu) {
if(w->body.needundo || w->body.file->delta.nc>0 || w->body.ncache){ if (w->body.needundo || w->body.file->delta.nc > 0 || w->body.ncache) {
runemove(new+i, Lundo, 5); runemove(new + i, Lundo, 5);
i += 5; i += 5;
} }
if(w->body.file->epsilon.nc > 0){ if (w->body.file->epsilon.nc > 0) {
runemove(new+i, Lredo, 5); runemove(new + i, Lredo, 5);
i += 5; i += 5;
} }
dirty = w->body.file->nname && (w->body.ncache || w->body.file->seq!=w->putseq); dirty =
if(!w->isdir && dirty){ w->body.file->nname && (w->body.ncache || w->body.file->seq != w->putseq);
runemove(new+i, Lput, 4); if (!w->isdir && dirty) {
runemove(new + i, Lput, 4);
i += 4; i += 4;
} }
} }
if(w->isdir){ if (w->isdir) {
runemove(new+i, Lget, 4); runemove(new + i, Lget, 4);
i += 4; i += 4;
} }
runemove(new+i, Lpipe, 2); runemove(new + i, Lpipe, 2);
i += 2; i += 2;
r = runestrchr(old, '|'); r = runestrchr(old, '|');
if(r) if (r)
k = r-old+1; k = r - old + 1;
else{ else {
k = w->tag.file->b.nc; k = w->tag.file->b.nc;
if(w->body.file->seq == 0){ if (w->body.file->seq == 0) {
runemove(new+i, Llook, 6); runemove(new + i, Llook, 6);
i += 6; i += 6;
} }
} }
@ -517,80 +513,72 @@ winsettag1(Window *w)
/* replace tag if the new one is different */ /* replace tag if the new one is different */
resize = 0; resize = 0;
if(runeeq(new, i, old, k) == FALSE){ if (runeeq(new, i, old, k) == FALSE) {
resize = 1; resize = 1;
n = k; n = k;
if(n > i) if (n > i)
n = i; n = i;
for(j=0; j<n; j++) for (j = 0; j < n; j++)
if(old[j] != new[j]) if (old[j] != new[j])
break; break;
q0 = w->tag.q0; q0 = w->tag.q0;
q1 = w->tag.q1; q1 = w->tag.q1;
textdelete(&w->tag, j, k, TRUE); textdelete(&w->tag, j, k, TRUE);
textinsert(&w->tag, j, new+j, i-j, TRUE); textinsert(&w->tag, j, new + j, i - j, TRUE);
/* try to preserve user selection */ /* try to preserve user selection */
r = runestrchr(old, '|'); r = runestrchr(old, '|');
if(r){ if (r) {
bar = r-old; bar = r - old;
if(q0 > bar){ if (q0 > bar) {
bar = (runestrchr(new, '|')-new)-bar; bar = (runestrchr(new, '|') - new) - bar;
w->tag.q0 = q0+bar; w->tag.q0 = q0 + bar;
w->tag.q1 = q1+bar; w->tag.q1 = q1 + bar;
} }
} }
} }
free(old); free(old);
free(new); free(new);
w->tag.file->mod = FALSE; w->tag.file->mod = FALSE;
n = w->tag.file->b.nc+w->tag.ncache; n = w->tag.file->b.nc + w->tag.ncache;
if(w->tag.q0 > n) if (w->tag.q0 > n)
w->tag.q0 = n; w->tag.q0 = n;
if(w->tag.q1 > n) if (w->tag.q1 > n)
w->tag.q1 = n; w->tag.q1 = n;
textsetselect(&w->tag, w->tag.q0, w->tag.q1); textsetselect(&w->tag, w->tag.q0, w->tag.q1);
windrawbutton(w); windrawbutton(w);
if(resize){ if (resize) {
w->tagsafe = 0; w->tagsafe = 0;
winresize(w, w->r, TRUE, TRUE); winresize(w, w->r, TRUE, TRUE);
} }
} }
void void winsettag(Window* w) {
winsettag(Window *w)
{
int i; int i;
File *f; File* f;
Window *v; Window* v;
f = w->body.file; f = w->body.file;
for(i=0; i<f->ntext; i++){ for (i = 0; i < f->ntext; i++) {
v = f->text[i]->w; v = f->text[i]->w;
if(v->col->safe || v->body.fr.maxlines>0) if (v->col->safe || v->body.fr.maxlines > 0)
winsettag1(v); winsettag1(v);
} }
} }
void void wincommit(Window* w, Text* t) {
wincommit(Window *w, Text *t) Rune* r;
{
Rune *r;
int i; int i;
File *f; File* f;
textcommit(t, TRUE); textcommit(t, TRUE);
f = t->file; f = t->file;
if(f->ntext > 1) if (f->ntext > 1)
for(i=0; i<f->ntext; i++) for (i = 0; i < f->ntext; i++)
textcommit(f->text[i], FALSE); /* no-op for t */ textcommit(f->text[i], FALSE); /* no-op for t */
if(t->what == Body) if (t->what == Body)
return; return;
r = runemalloc(w->tag.file->b.nc); r = parsetag(w, &i);
bufread(&w->tag.file->b, 0, r, w->tag.file->b.nc); if (runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE) {
for(i=0; i<w->tag.file->b.nc; i++)
if(r[i]==' ' || r[i]=='\t')
break;
if(runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE){
seq++; seq++;
filemark(w->body.file); filemark(w->body.file);
w->body.file->mod = TRUE; w->body.file->mod = TRUE;
@ -601,17 +589,15 @@ wincommit(Window *w, Text *t)
free(r); free(r);
} }
void void winaddincl(Window* w, Rune* r, int n) {
winaddincl(Window *w, Rune *r, int n) char* a;
{ Dir* d;
char *a;
Dir *d;
Runestr rs; Runestr rs;
a = runetobyte(r, n); a = runetobyte(r, n);
d = dirstat(a); d = dirstat(a);
if(d == nil){ if (d == nil) {
if(a[0] == '/') if (a[0] == '/')
goto Rescue; goto Rescue;
rs = dirname(&w->body, r, n); rs = dirname(&w->body, r, n);
r = rs.r; r = rs.r;
@ -619,13 +605,13 @@ winaddincl(Window *w, Rune *r, int n)
free(a); free(a);
a = runetobyte(r, n); a = runetobyte(r, n);
d = dirstat(a); d = dirstat(a);
if(d == nil) if (d == nil)
goto Rescue; goto Rescue;
r = runerealloc(r, n+1); r = runerealloc(r, n + 1);
r[n] = 0; r[n] = 0;
} }
free(a); free(a);
if((d->qid.type&QTDIR) == 0){ if ((d->qid.type & QTDIR) == 0) {
free(d); free(d);
warning(nil, "%s: not a directory\n", a); warning(nil, "%s: not a directory\n", a);
free(r); free(r);
@ -633,9 +619,9 @@ winaddincl(Window *w, Rune *r, int n)
} }
free(d); free(d);
w->nincl++; w->nincl++;
w->incl = realloc(w->incl, w->nincl*sizeof(Rune*)); w->incl = realloc(w->incl, w->nincl * sizeof(Rune*));
memmove(w->incl+1, w->incl, (w->nincl-1)*sizeof(Rune*)); memmove(w->incl + 1, w->incl, (w->nincl - 1) * sizeof(Rune*));
w->incl[0] = runemalloc(n+1); w->incl[0] = runemalloc(n + 1);
runemove(w->incl[0], r, n); runemove(w->incl[0], r, n);
free(r); free(r);
return; return;
@ -647,18 +633,17 @@ Rescue:
return; return;
} }
int int winclean(Window* w, int conservative) {
winclean(Window *w, int conservative) if (w->isscratch || w->isdir) /* don't whine if it's a guide file, error
{ window, etc. */
if(w->isscratch || w->isdir) /* don't whine if it's a guide file, error window, etc. */
return TRUE; return TRUE;
if(!conservative && w->nopen[QWevent]>0) if (!conservative && w->nopen[QWevent] > 0)
return TRUE; return TRUE;
if(w->dirty){ if (w->dirty) {
if(w->body.file->nname) if (w->body.file->nname)
warning(nil, "%.*S modified\n", w->body.file->nname, w->body.file->name); warning(nil, "%.*S modified\n", w->body.file->nname, w->body.file->name);
else{ else {
if(w->body.file->b.nc < 100) /* don't whine if it's too small */ if (w->body.file->b.nc < 100) /* don't whine if it's too small */
return TRUE; return TRUE;
warning(nil, "unnamed file modified\n"); warning(nil, "unnamed file modified\n");
} }
@ -668,42 +653,48 @@ winclean(Window *w, int conservative)
return TRUE; return TRUE;
} }
char* char* winctlprint(Window* w, char* buf, int fonts) {
winctlprint(Window *w, char *buf, int fonts) sprint(
{ buf,
sprint(buf, "%11d %11d %11d %11d %11d ", w->id, w->tag.file->b.nc, "%11d %11d %11d %11d %11d ",
w->body.file->b.nc, w->isdir, w->dirty); w->id,
if(fonts) w->tag.file->b.nc,
return smprint("%s%11d %q %11d ", buf, Dx(w->body.fr.r), w->body.file->b.nc,
w->body.reffont->f->name, w->body.fr.maxtab); w->isdir,
w->dirty);
if (fonts)
return smprint(
"%s%11d %q %11d ",
buf,
Dx(w->body.fr.r),
w->body.reffont->f->name,
w->body.fr.maxtab);
return buf; return buf;
} }
void void winevent(Window* w, char* fmt, ...) {
winevent(Window *w, char *fmt, ...)
{
int n; int n;
char *b; char* b;
Xfid *x; Xfid* x;
va_list arg; va_list arg;
if(w->nopen[QWevent] == 0) if (w->nopen[QWevent] == 0)
return; return;
if(w->owner == 0) if (w->owner == 0)
error("no window owner"); error("no window owner");
va_start(arg, fmt); va_start(arg, fmt);
b = vsmprint(fmt, arg); b = vsmprint(fmt, arg);
va_end(arg); va_end(arg);
if(b == nil) if (b == nil)
error("vsmprint failed"); error("vsmprint failed");
n = strlen(b); n = strlen(b);
w->events = erealloc(w->events, w->nevents+1+n); w->events = erealloc(w->events, w->nevents + 1 + n);
w->events[w->nevents++] = w->owner; w->events[w->nevents++] = w->owner;
memmove(w->events+w->nevents, b, n); memmove(w->events + w->nevents, b, n);
free(b); free(b);
w->nevents += n; w->nevents += n;
x = w->eventx; x = w->eventx;
if(x){ if (x) {
w->eventx = nil; w->eventx = nil;
sendp(x->c, nil); sendp(x->c, nil);
} }

605
xfid.c

File diff suppressed because it is too large Load diff