add gitignore, clang-format, build script; merge src's patch for spaces in filenames
This commit is contained in:
parent
cf57dbe235
commit
5540d37849
38 changed files with 15300 additions and 15770 deletions
23
.clang-format
Normal file
23
.clang-format
Normal 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
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
**/*.o
|
||||
**/o.*
|
||||
acme
|
||||
|
|
506
addr.c
506
addr.c
|
@ -12,41 +12,29 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
enum
|
||||
{
|
||||
None = 0,
|
||||
Fore = '+',
|
||||
Back = '-'
|
||||
};
|
||||
enum { None = 0, Fore = '+', Back = '-' };
|
||||
|
||||
enum
|
||||
{
|
||||
Char,
|
||||
Line
|
||||
};
|
||||
enum { Char, Line };
|
||||
|
||||
int
|
||||
isaddrc(int r)
|
||||
{
|
||||
if(r && utfrune("0123456789+-/$.#,;?", r)!=nil)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
int isaddrc(int r) {
|
||||
if (r && utfrune("0123456789+-/$.#,;?", r) != nil)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* quite hard: could be almost anything but white space, but we are a little conservative,
|
||||
* aiming for regular expressions of alphanumerics and no white space
|
||||
* quite hard: could be almost anything but white space, but we are a little
|
||||
* conservative, aiming for regular expressions of alphanumerics and no white
|
||||
* space
|
||||
*/
|
||||
int
|
||||
isregexc(int r)
|
||||
{
|
||||
if(r == 0)
|
||||
return FALSE;
|
||||
if(isalnum(r))
|
||||
return TRUE;
|
||||
if(utfrune("^+-.*?#,;[]()$", r)!=nil)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
int isregexc(int r) {
|
||||
if (r == 0)
|
||||
return FALSE;
|
||||
if (isalnum(r))
|
||||
return TRUE;
|
||||
if (utfrune("^+-.*?#,;[]()$", r) != nil)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// nlcounttopos starts at q0 and advances nl lines,
|
||||
|
@ -54,242 +42,246 @@ isregexc(int r)
|
|||
// and then nr chars, being careful not to walk past
|
||||
// the end of the current line.
|
||||
// It returns the final position.
|
||||
long
|
||||
nlcounttopos(Text *t, long q0, long nl, long nr)
|
||||
{
|
||||
while(nl > 0 && q0 < t->file->b.nc) {
|
||||
if(textreadc(t, q0++) == '\n')
|
||||
nl--;
|
||||
}
|
||||
if(nl > 0)
|
||||
return q0;
|
||||
while(nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') {
|
||||
q0++;
|
||||
nr--;
|
||||
}
|
||||
return q0;
|
||||
long nlcounttopos(Text* t, long q0, long nl, long nr) {
|
||||
while (nl > 0 && q0 < t->file->b.nc) {
|
||||
if (textreadc(t, q0++) == '\n')
|
||||
nl--;
|
||||
}
|
||||
if (nl > 0)
|
||||
return q0;
|
||||
while (nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') {
|
||||
q0++;
|
||||
nr--;
|
||||
}
|
||||
return q0;
|
||||
}
|
||||
|
||||
Range
|
||||
number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp)
|
||||
{
|
||||
uint q0, q1;
|
||||
Range number(
|
||||
uint showerr, Text* t, Range r, int line, int dir, int size, int* evalp) {
|
||||
uint q0, q1;
|
||||
|
||||
if(size == Char){
|
||||
if(dir == Fore)
|
||||
line = r.q1+line;
|
||||
else if(dir == Back){
|
||||
if(r.q0==0 && line>0)
|
||||
r.q0 = t->file->b.nc;
|
||||
line = r.q0 - line;
|
||||
}
|
||||
if(line<0 || line>t->file->b.nc)
|
||||
goto Rescue;
|
||||
*evalp = TRUE;
|
||||
return range(line, line);
|
||||
}
|
||||
q0 = r.q0;
|
||||
q1 = r.q1;
|
||||
switch(dir){
|
||||
case None:
|
||||
q0 = 0;
|
||||
q1 = 0;
|
||||
Forward:
|
||||
while(line>0 && q1<t->file->b.nc)
|
||||
if(textreadc(t, q1++) == '\n' || q1==t->file->b.nc)
|
||||
if(--line > 0)
|
||||
q0 = q1;
|
||||
if(line==1 && q1==t->file->b.nc) // 6 goes to end of 5-line file
|
||||
break;
|
||||
if(line > 0)
|
||||
goto Rescue;
|
||||
break;
|
||||
case Fore:
|
||||
if(q1 > 0)
|
||||
while(q1<t->file->b.nc && textreadc(t, q1-1) != '\n')
|
||||
q1++;
|
||||
q0 = q1;
|
||||
goto Forward;
|
||||
case Back:
|
||||
if(q0 < t->file->b.nc)
|
||||
while(q0>0 && textreadc(t, q0-1)!='\n')
|
||||
q0--;
|
||||
q1 = q0;
|
||||
while(line>0 && q0>0){
|
||||
if(textreadc(t, q0-1) == '\n'){
|
||||
if(--line >= 0)
|
||||
q1 = q0;
|
||||
}
|
||||
--q0;
|
||||
}
|
||||
/* :1-1 is :0 = #0, but :1-2 is an error */
|
||||
if(line > 1)
|
||||
goto Rescue;
|
||||
while(q0>0 && textreadc(t, q0-1)!='\n')
|
||||
--q0;
|
||||
}
|
||||
*evalp = TRUE;
|
||||
return range(q0, q1);
|
||||
if (size == Char) {
|
||||
if (dir == Fore)
|
||||
line = r.q1 + line;
|
||||
else if (dir == Back) {
|
||||
if (r.q0 == 0 && line > 0)
|
||||
r.q0 = t->file->b.nc;
|
||||
line = r.q0 - line;
|
||||
}
|
||||
if (line < 0 || line > t->file->b.nc)
|
||||
goto Rescue;
|
||||
*evalp = TRUE;
|
||||
return range(line, line);
|
||||
}
|
||||
q0 = r.q0;
|
||||
q1 = r.q1;
|
||||
switch (dir) {
|
||||
case None:
|
||||
q0 = 0;
|
||||
q1 = 0;
|
||||
Forward:
|
||||
while (line > 0 && q1 < t->file->b.nc)
|
||||
if (textreadc(t, q1++) == '\n' || q1 == t->file->b.nc)
|
||||
if (--line > 0)
|
||||
q0 = q1;
|
||||
if (line == 1 && q1 == t->file->b.nc) // 6 goes to end of 5-line file
|
||||
break;
|
||||
if (line > 0)
|
||||
goto Rescue;
|
||||
break;
|
||||
case Fore:
|
||||
if (q1 > 0)
|
||||
while (q1 < t->file->b.nc && textreadc(t, q1 - 1) != '\n')
|
||||
q1++;
|
||||
q0 = q1;
|
||||
goto Forward;
|
||||
case Back:
|
||||
if (q0 < t->file->b.nc)
|
||||
while (q0 > 0 && textreadc(t, q0 - 1) != '\n')
|
||||
q0--;
|
||||
q1 = q0;
|
||||
while (line > 0 && q0 > 0) {
|
||||
if (textreadc(t, q0 - 1) == '\n') {
|
||||
if (--line >= 0)
|
||||
q1 = q0;
|
||||
}
|
||||
--q0;
|
||||
}
|
||||
/* :1-1 is :0 = #0, but :1-2 is an error */
|
||||
if (line > 1)
|
||||
goto Rescue;
|
||||
while (q0 > 0 && textreadc(t, q0 - 1) != '\n')
|
||||
--q0;
|
||||
}
|
||||
*evalp = TRUE;
|
||||
return range(q0, q1);
|
||||
|
||||
Rescue:
|
||||
if(showerr)
|
||||
warning(nil, "address out of range\n");
|
||||
*evalp = FALSE;
|
||||
return r;
|
||||
Rescue:
|
||||
if (showerr)
|
||||
warning(nil, "address out of range\n");
|
||||
*evalp = FALSE;
|
||||
return r;
|
||||
}
|
||||
|
||||
Range regexp(
|
||||
uint showerr, Text* t, Range lim, Range r, Rune* pat, int dir, int* foundp) {
|
||||
int found;
|
||||
Rangeset sel;
|
||||
int q;
|
||||
|
||||
Range
|
||||
regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
|
||||
{
|
||||
int found;
|
||||
Rangeset sel;
|
||||
int q;
|
||||
|
||||
if(pat[0] == '\0' && rxnull()){
|
||||
if(showerr)
|
||||
warning(nil, "no previous regular expression\n");
|
||||
*foundp = FALSE;
|
||||
return r;
|
||||
}
|
||||
if(pat[0] && rxcompile(pat) == FALSE){
|
||||
*foundp = FALSE;
|
||||
return r;
|
||||
}
|
||||
if(dir == Back)
|
||||
found = rxbexecute(t, r.q0, &sel);
|
||||
else{
|
||||
if(lim.q0 < 0)
|
||||
q = Infinity;
|
||||
else
|
||||
q = lim.q1;
|
||||
found = rxexecute(t, nil, r.q1, q, &sel);
|
||||
}
|
||||
if(!found && showerr)
|
||||
warning(nil, "no match for regexp\n");
|
||||
*foundp = found;
|
||||
return sel.r[0];
|
||||
if (pat[0] == '\0' && rxnull()) {
|
||||
if (showerr)
|
||||
warning(nil, "no previous regular expression\n");
|
||||
*foundp = FALSE;
|
||||
return r;
|
||||
}
|
||||
if (pat[0] && rxcompile(pat) == FALSE) {
|
||||
*foundp = FALSE;
|
||||
return r;
|
||||
}
|
||||
if (dir == Back)
|
||||
found = rxbexecute(t, r.q0, &sel);
|
||||
else {
|
||||
if (lim.q0 < 0)
|
||||
q = Infinity;
|
||||
else
|
||||
q = lim.q1;
|
||||
found = rxexecute(t, nil, r.q1, q, &sel);
|
||||
}
|
||||
if (!found && showerr)
|
||||
warning(nil, "no match for regexp\n");
|
||||
*foundp = found;
|
||||
return sel.r[0];
|
||||
}
|
||||
|
||||
Range
|
||||
address(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 prevc, c, nc, n;
|
||||
uint q;
|
||||
Rune *pat;
|
||||
Range r, nr;
|
||||
Range address(
|
||||
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 prevc, c, nc, n;
|
||||
uint q;
|
||||
Rune* pat;
|
||||
Range r, nr;
|
||||
|
||||
r = ar;
|
||||
q = q0;
|
||||
dir = None;
|
||||
size = Line;
|
||||
c = 0;
|
||||
while(q < q1){
|
||||
prevc = c;
|
||||
c = (*getc)(a, q++);
|
||||
switch(c){
|
||||
default:
|
||||
*qp = q-1;
|
||||
return r;
|
||||
case ';':
|
||||
ar = r;
|
||||
/* fall through */
|
||||
case ',':
|
||||
if(prevc == 0) /* lhs defaults to 0 */
|
||||
r.q0 = 0;
|
||||
if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
|
||||
r.q1 = t->file->b.nc;
|
||||
else{
|
||||
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
|
||||
r.q1 = nr.q1;
|
||||
}
|
||||
*qp = q;
|
||||
return r;
|
||||
case '+':
|
||||
case '-':
|
||||
if(*evalp && (prevc=='+' || prevc=='-'))
|
||||
if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
|
||||
r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */
|
||||
dir = c;
|
||||
break;
|
||||
case '.':
|
||||
case '$':
|
||||
if(q != q0+1){
|
||||
*qp = q-1;
|
||||
return r;
|
||||
}
|
||||
if(*evalp)
|
||||
if(c == '.')
|
||||
r = ar;
|
||||
else
|
||||
r = range(t->file->b.nc, t->file->b.nc);
|
||||
if(q < q1)
|
||||
dir = Fore;
|
||||
else
|
||||
dir = None;
|
||||
break;
|
||||
case '#':
|
||||
if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){
|
||||
*qp = q-1;
|
||||
return r;
|
||||
}
|
||||
size = Char;
|
||||
/* fall through */
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
n = c -'0';
|
||||
while(q<q1){
|
||||
nc = (*getc)(a, q++);
|
||||
if(nc<'0' || '9'<nc){
|
||||
q--;
|
||||
break;
|
||||
}
|
||||
n = n*10+(nc-'0');
|
||||
}
|
||||
if(*evalp)
|
||||
r = number(showerr, t, r, n, dir, size, evalp);
|
||||
dir = None;
|
||||
size = Line;
|
||||
break;
|
||||
case '?':
|
||||
dir = Back;
|
||||
/* fall through */
|
||||
case '/':
|
||||
npat = 0;
|
||||
pat = nil;
|
||||
while(q<q1){
|
||||
c = (*getc)(a, q++);
|
||||
switch(c){
|
||||
case '\n':
|
||||
--q;
|
||||
goto out;
|
||||
case '\\':
|
||||
pat = runerealloc(pat, npat+1);
|
||||
pat[npat++] = c;
|
||||
if(q == q1)
|
||||
goto out;
|
||||
c = (*getc)(a, q++);
|
||||
break;
|
||||
case '/':
|
||||
goto out;
|
||||
}
|
||||
pat = runerealloc(pat, npat+1);
|
||||
pat[npat++] = c;
|
||||
}
|
||||
out:
|
||||
pat = runerealloc(pat, npat+1);
|
||||
pat[npat] = 0;
|
||||
if(*evalp)
|
||||
r = regexp(showerr, t, lim, r, pat, dir, evalp);
|
||||
free(pat);
|
||||
dir = None;
|
||||
size = Line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(*evalp && dir != None)
|
||||
r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
|
||||
*qp = q;
|
||||
return r;
|
||||
r = ar;
|
||||
q = q0;
|
||||
dir = None;
|
||||
size = Line;
|
||||
c = 0;
|
||||
while (q < q1) {
|
||||
prevc = c;
|
||||
c = (*getc)(a, q++);
|
||||
switch (c) {
|
||||
default:
|
||||
*qp = q - 1;
|
||||
return r;
|
||||
case ';':
|
||||
ar = r;
|
||||
/* fall through */
|
||||
case ',':
|
||||
if (prevc == 0) /* lhs defaults to 0 */
|
||||
r.q0 = 0;
|
||||
if (q >= q1 && t != nil && t->file != nil) /* rhs defaults to $ */
|
||||
r.q1 = t->file->b.nc;
|
||||
else {
|
||||
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
|
||||
r.q1 = nr.q1;
|
||||
}
|
||||
*qp = q;
|
||||
return r;
|
||||
case '+':
|
||||
case '-':
|
||||
if (*evalp && (prevc == '+' || prevc == '-'))
|
||||
if ((nc = (*getc)(a, q)) != '#' && nc != '/' && nc != '?')
|
||||
r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one
|
||||
*/
|
||||
dir = c;
|
||||
break;
|
||||
case '.':
|
||||
case '$':
|
||||
if (q != q0 + 1) {
|
||||
*qp = q - 1;
|
||||
return r;
|
||||
}
|
||||
if (*evalp)
|
||||
if (c == '.')
|
||||
r = ar;
|
||||
else
|
||||
r = range(t->file->b.nc, t->file->b.nc);
|
||||
if (q < q1)
|
||||
dir = Fore;
|
||||
else
|
||||
dir = None;
|
||||
break;
|
||||
case '#':
|
||||
if (q == q1 || (c = (*getc)(a, q++)) < '0' || '9' < c) {
|
||||
*qp = q - 1;
|
||||
return r;
|
||||
}
|
||||
size = Char;
|
||||
/* fall through */
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
n = c - '0';
|
||||
while (q < q1) {
|
||||
nc = (*getc)(a, q++);
|
||||
if (nc < '0' || '9' < nc) {
|
||||
q--;
|
||||
break;
|
||||
}
|
||||
n = n * 10 + (nc - '0');
|
||||
}
|
||||
if (*evalp)
|
||||
r = number(showerr, t, r, n, dir, size, evalp);
|
||||
dir = None;
|
||||
size = Line;
|
||||
break;
|
||||
case '?':
|
||||
dir = Back;
|
||||
/* fall through */
|
||||
case '/':
|
||||
npat = 0;
|
||||
pat = nil;
|
||||
while (q < q1) {
|
||||
c = (*getc)(a, q++);
|
||||
switch (c) {
|
||||
case '\n':
|
||||
--q;
|
||||
goto out;
|
||||
case '\\':
|
||||
pat = runerealloc(pat, npat + 1);
|
||||
pat[npat++] = c;
|
||||
if (q == q1)
|
||||
goto out;
|
||||
c = (*getc)(a, q++);
|
||||
break;
|
||||
case '/':
|
||||
goto out;
|
||||
}
|
||||
pat = runerealloc(pat, npat + 1);
|
||||
pat[npat++] = c;
|
||||
}
|
||||
out:
|
||||
pat = runerealloc(pat, npat + 1);
|
||||
pat[npat] = 0;
|
||||
if (*evalp)
|
||||
r = regexp(showerr, t, lim, r, pat, dir, evalp);
|
||||
free(pat);
|
||||
dir = None;
|
||||
size = Line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*evalp && dir != None)
|
||||
r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
|
||||
*qp = q;
|
||||
return r;
|
||||
}
|
||||
|
|
506
buff.c
506
buff.c
|
@ -12,47 +12,37 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
enum
|
||||
{
|
||||
Slop = 100 /* room to grow with reallocation */
|
||||
enum {
|
||||
Slop = 100 /* room to grow with reallocation */
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
sizecache(Buffer *b, uint n)
|
||||
{
|
||||
if(n <= b->cmax)
|
||||
return;
|
||||
b->cmax = n+Slop;
|
||||
b->c = runerealloc(b->c, b->cmax);
|
||||
static void sizecache(Buffer* b, uint n) {
|
||||
if (n <= b->cmax)
|
||||
return;
|
||||
b->cmax = n + Slop;
|
||||
b->c = runerealloc(b->c, b->cmax);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
addblock(Buffer *b, uint i, uint n)
|
||||
{
|
||||
if(i > b->nbl)
|
||||
error("internal error: addblock");
|
||||
static void addblock(Buffer* b, uint i, uint n) {
|
||||
if (i > b->nbl)
|
||||
error("internal error: addblock");
|
||||
|
||||
b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]);
|
||||
if(i < b->nbl)
|
||||
memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*));
|
||||
b->bl[i] = disknewblock(disk, n);
|
||||
b->nbl++;
|
||||
b->bl = realloc(b->bl, (b->nbl + 1) * sizeof b->bl[0]);
|
||||
if (i < b->nbl)
|
||||
memmove(b->bl + i + 1, b->bl + i, (b->nbl - i) * sizeof(Block*));
|
||||
b->bl[i] = disknewblock(disk, n);
|
||||
b->nbl++;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
delblock(Buffer *b, uint i)
|
||||
{
|
||||
if(i >= b->nbl)
|
||||
error("internal error: delblock");
|
||||
static void delblock(Buffer* b, uint i) {
|
||||
if (i >= b->nbl)
|
||||
error("internal error: delblock");
|
||||
|
||||
diskrelease(disk, b->bl[i]);
|
||||
b->nbl--;
|
||||
if(i < b->nbl)
|
||||
memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*));
|
||||
b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]);
|
||||
diskrelease(disk, b->bl[i]);
|
||||
b->nbl--;
|
||||
if (i < b->nbl)
|
||||
memmove(b->bl + i, b->bl + i + 1, (b->nbl - i) * sizeof(Block*));
|
||||
b->bl = realloc(b->bl, b->nbl * sizeof b->bl[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -60,266 +50,246 @@ delblock(Buffer *b, uint i)
|
|||
* If at very end, q0 will fall on end of cache block.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
flush(Buffer *b)
|
||||
{
|
||||
if(b->cdirty || b->cnc==0){
|
||||
if(b->cnc == 0)
|
||||
delblock(b, b->cbi);
|
||||
else
|
||||
diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
|
||||
b->cdirty = FALSE;
|
||||
}
|
||||
static void flush(Buffer* b) {
|
||||
if (b->cdirty || b->cnc == 0) {
|
||||
if (b->cnc == 0)
|
||||
delblock(b, b->cbi);
|
||||
else
|
||||
diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
|
||||
b->cdirty = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
setcache(Buffer *b, uint q0)
|
||||
{
|
||||
Block **blp, *bl;
|
||||
uint i, q;
|
||||
static void setcache(Buffer* b, uint q0) {
|
||||
Block **blp, *bl;
|
||||
uint i, q;
|
||||
|
||||
if(q0 > b->nc)
|
||||
error("internal error: setcache");
|
||||
/*
|
||||
* flush and reload if q0 is not in cache.
|
||||
*/
|
||||
if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))
|
||||
return;
|
||||
/*
|
||||
* if q0 is at end of file and end of cache, continue to grow this block
|
||||
*/
|
||||
if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<Maxblock)
|
||||
return;
|
||||
flush(b);
|
||||
/* find block */
|
||||
if(q0 < b->cq){
|
||||
q = 0;
|
||||
i = 0;
|
||||
}else{
|
||||
q = b->cq;
|
||||
i = b->cbi;
|
||||
}
|
||||
blp = &b->bl[i];
|
||||
while(q+(*blp)->u.n <= q0 && q+(*blp)->u.n < b->nc){
|
||||
q += (*blp)->u.n;
|
||||
i++;
|
||||
blp++;
|
||||
if(i >= b->nbl)
|
||||
error("block not found");
|
||||
}
|
||||
bl = *blp;
|
||||
/* remember position */
|
||||
b->cbi = i;
|
||||
b->cq = q;
|
||||
sizecache(b, bl->u.n);
|
||||
b->cnc = bl->u.n;
|
||||
/*read block*/
|
||||
diskread(disk, bl, b->c, b->cnc);
|
||||
if (q0 > b->nc)
|
||||
error("internal error: setcache");
|
||||
/*
|
||||
* flush and reload if q0 is not in cache.
|
||||
*/
|
||||
if (b->nc == 0 || (b->cq <= q0 && q0 < b->cq + b->cnc))
|
||||
return;
|
||||
/*
|
||||
* if q0 is at end of file and end of cache, continue to grow this block
|
||||
*/
|
||||
if (q0 == b->nc && q0 == b->cq + b->cnc && b->cnc < Maxblock)
|
||||
return;
|
||||
flush(b);
|
||||
/* find block */
|
||||
if (q0 < b->cq) {
|
||||
q = 0;
|
||||
i = 0;
|
||||
} else {
|
||||
q = b->cq;
|
||||
i = b->cbi;
|
||||
}
|
||||
blp = &b->bl[i];
|
||||
while (q + (*blp)->u.n <= q0 && q + (*blp)->u.n < b->nc) {
|
||||
q += (*blp)->u.n;
|
||||
i++;
|
||||
blp++;
|
||||
if (i >= b->nbl)
|
||||
error("block not found");
|
||||
}
|
||||
bl = *blp;
|
||||
/* remember position */
|
||||
b->cbi = i;
|
||||
b->cq = q;
|
||||
sizecache(b, bl->u.n);
|
||||
b->cnc = bl->u.n;
|
||||
/*read block*/
|
||||
diskread(disk, bl, b->c, b->cnc);
|
||||
}
|
||||
|
||||
void
|
||||
bufinsert(Buffer *b, uint q0, Rune *s, uint n)
|
||||
{
|
||||
uint i, m, t, off;
|
||||
void bufinsert(Buffer* b, uint q0, Rune* s, uint n) {
|
||||
uint i, m, t, off;
|
||||
|
||||
if(q0 > b->nc)
|
||||
error("internal error: bufinsert");
|
||||
if (q0 > b->nc)
|
||||
error("internal error: bufinsert");
|
||||
|
||||
while(n > 0){
|
||||
setcache(b, q0);
|
||||
off = q0-b->cq;
|
||||
if(b->cnc+n <= Maxblock){
|
||||
/* Everything fits in one block. */
|
||||
t = b->cnc+n;
|
||||
m = n;
|
||||
if(b->bl == nil){ /* allocate */
|
||||
if(b->cnc != 0)
|
||||
error("internal error: bufinsert1 cnc!=0");
|
||||
addblock(b, 0, t);
|
||||
b->cbi = 0;
|
||||
}
|
||||
sizecache(b, t);
|
||||
runemove(b->c+off+m, b->c+off, b->cnc-off);
|
||||
runemove(b->c+off, s, m);
|
||||
b->cnc = t;
|
||||
goto Tail;
|
||||
}
|
||||
/*
|
||||
* We must make a new block. If q0 is at
|
||||
* the very beginning or end of this block,
|
||||
* just make a new block and fill it.
|
||||
*/
|
||||
if(q0==b->cq || q0==b->cq+b->cnc){
|
||||
if(b->cdirty)
|
||||
flush(b);
|
||||
m = min(n, Maxblock);
|
||||
if(b->bl == nil){ /* allocate */
|
||||
if(b->cnc != 0)
|
||||
error("internal error: bufinsert2 cnc!=0");
|
||||
i = 0;
|
||||
}else{
|
||||
i = b->cbi;
|
||||
if(q0 > b->cq)
|
||||
i++;
|
||||
}
|
||||
addblock(b, i, m);
|
||||
sizecache(b, m);
|
||||
runemove(b->c, s, m);
|
||||
b->cq = q0;
|
||||
b->cbi = i;
|
||||
b->cnc = m;
|
||||
goto Tail;
|
||||
}
|
||||
/*
|
||||
* Split the block; cut off the right side and
|
||||
* let go of it.
|
||||
*/
|
||||
m = b->cnc-off;
|
||||
if(m > 0){
|
||||
i = b->cbi+1;
|
||||
addblock(b, i, m);
|
||||
diskwrite(disk, &b->bl[i], b->c+off, m);
|
||||
b->cnc -= m;
|
||||
}
|
||||
/*
|
||||
* Now at end of block. Take as much input
|
||||
* as possible and tack it on end of block.
|
||||
*/
|
||||
m = min(n, Maxblock-b->cnc);
|
||||
sizecache(b, b->cnc+m);
|
||||
runemove(b->c+b->cnc, s, m);
|
||||
b->cnc += m;
|
||||
while (n > 0) {
|
||||
setcache(b, q0);
|
||||
off = q0 - b->cq;
|
||||
if (b->cnc + n <= Maxblock) {
|
||||
/* Everything fits in one block. */
|
||||
t = b->cnc + n;
|
||||
m = n;
|
||||
if (b->bl == nil) { /* allocate */
|
||||
if (b->cnc != 0)
|
||||
error("internal error: bufinsert1 cnc!=0");
|
||||
addblock(b, 0, t);
|
||||
b->cbi = 0;
|
||||
}
|
||||
sizecache(b, t);
|
||||
runemove(b->c + off + m, b->c + off, b->cnc - off);
|
||||
runemove(b->c + off, s, m);
|
||||
b->cnc = t;
|
||||
goto Tail;
|
||||
}
|
||||
/*
|
||||
* We must make a new block. If q0 is at
|
||||
* the very beginning or end of this block,
|
||||
* just make a new block and fill it.
|
||||
*/
|
||||
if (q0 == b->cq || q0 == b->cq + b->cnc) {
|
||||
if (b->cdirty)
|
||||
flush(b);
|
||||
m = min(n, Maxblock);
|
||||
if (b->bl == nil) { /* allocate */
|
||||
if (b->cnc != 0)
|
||||
error("internal error: bufinsert2 cnc!=0");
|
||||
i = 0;
|
||||
} else {
|
||||
i = b->cbi;
|
||||
if (q0 > b->cq)
|
||||
i++;
|
||||
}
|
||||
addblock(b, i, m);
|
||||
sizecache(b, m);
|
||||
runemove(b->c, s, m);
|
||||
b->cq = q0;
|
||||
b->cbi = i;
|
||||
b->cnc = m;
|
||||
goto Tail;
|
||||
}
|
||||
/*
|
||||
* Split the block; cut off the right side and
|
||||
* let go of it.
|
||||
*/
|
||||
m = b->cnc - off;
|
||||
if (m > 0) {
|
||||
i = b->cbi + 1;
|
||||
addblock(b, i, m);
|
||||
diskwrite(disk, &b->bl[i], b->c + off, m);
|
||||
b->cnc -= m;
|
||||
}
|
||||
/*
|
||||
* Now at end of block. Take as much input
|
||||
* as possible and tack it on end of block.
|
||||
*/
|
||||
m = min(n, Maxblock - b->cnc);
|
||||
sizecache(b, b->cnc + m);
|
||||
runemove(b->c + b->cnc, s, m);
|
||||
b->cnc += m;
|
||||
Tail:
|
||||
b->nc += m;
|
||||
q0 += m;
|
||||
s += m;
|
||||
n -= m;
|
||||
b->cdirty = TRUE;
|
||||
}
|
||||
b->nc += m;
|
||||
q0 += m;
|
||||
s += m;
|
||||
n -= m;
|
||||
b->cdirty = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bufdelete(Buffer *b, uint q0, uint q1)
|
||||
{
|
||||
uint m, n, off;
|
||||
void bufdelete(Buffer* b, uint q0, uint q1) {
|
||||
uint m, n, off;
|
||||
|
||||
if(!(q0<=q1 && q0<=b->nc && q1<=b->nc))
|
||||
error("internal error: bufdelete");
|
||||
while(q1 > q0){
|
||||
setcache(b, q0);
|
||||
off = q0-b->cq;
|
||||
if(q1 > b->cq+b->cnc)
|
||||
n = b->cnc - off;
|
||||
else
|
||||
n = q1-q0;
|
||||
m = b->cnc - (off+n);
|
||||
if(m > 0)
|
||||
runemove(b->c+off, b->c+off+n, m);
|
||||
b->cnc -= n;
|
||||
b->cdirty = TRUE;
|
||||
q1 -= n;
|
||||
b->nc -= n;
|
||||
}
|
||||
if (!(q0 <= q1 && q0 <= b->nc && q1 <= b->nc))
|
||||
error("internal error: bufdelete");
|
||||
while (q1 > q0) {
|
||||
setcache(b, q0);
|
||||
off = q0 - b->cq;
|
||||
if (q1 > b->cq + b->cnc)
|
||||
n = b->cnc - off;
|
||||
else
|
||||
n = q1 - q0;
|
||||
m = b->cnc - (off + n);
|
||||
if (m > 0)
|
||||
runemove(b->c + off, b->c + off + n, m);
|
||||
b->cnc -= n;
|
||||
b->cdirty = TRUE;
|
||||
q1 -= n;
|
||||
b->nc -= n;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bufloader(void *v, uint q0, Rune *r, int nr)
|
||||
{
|
||||
bufinsert(v, q0, r, nr);
|
||||
return nr;
|
||||
static int bufloader(void* v, uint q0, Rune* r, int nr) {
|
||||
bufinsert(v, q0, r, nr);
|
||||
return nr;
|
||||
}
|
||||
|
||||
uint
|
||||
loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg, DigestState *h)
|
||||
{
|
||||
char *p;
|
||||
Rune *r;
|
||||
int l, m, n, nb, nr;
|
||||
uint q1;
|
||||
uint loadfile(
|
||||
int fd, uint q0, int* nulls, int (*f)(void*, uint, Rune*, int), void* arg,
|
||||
DigestState* h) {
|
||||
char* p;
|
||||
Rune* r;
|
||||
int l, m, n, nb, nr;
|
||||
uint q1;
|
||||
|
||||
p = emalloc((Maxblock+UTFmax+1)*sizeof p[0]);
|
||||
r = runemalloc(Maxblock);
|
||||
m = 0;
|
||||
n = 1;
|
||||
q1 = q0;
|
||||
/*
|
||||
* At top of loop, may have m bytes left over from
|
||||
* last pass, possibly representing a partial rune.
|
||||
*/
|
||||
while(n > 0){
|
||||
n = read(fd, p+m, Maxblock);
|
||||
if(n < 0){
|
||||
warning(nil, "read error in Buffer.load");
|
||||
break;
|
||||
}
|
||||
if(h != nil)
|
||||
sha1((uchar*)p+m, n, nil, h);
|
||||
m += n;
|
||||
p[m] = 0;
|
||||
l = m;
|
||||
if(n > 0)
|
||||
l -= UTFmax;
|
||||
cvttorunes(p, l, r, &nb, &nr, nulls);
|
||||
memmove(p, p+nb, m-nb);
|
||||
m -= nb;
|
||||
q1 += (*f)(arg, q1, r, nr);
|
||||
}
|
||||
free(p);
|
||||
free(r);
|
||||
return q1-q0;
|
||||
p = emalloc((Maxblock + UTFmax + 1) * sizeof p[0]);
|
||||
r = runemalloc(Maxblock);
|
||||
m = 0;
|
||||
n = 1;
|
||||
q1 = q0;
|
||||
/*
|
||||
* At top of loop, may have m bytes left over from
|
||||
* last pass, possibly representing a partial rune.
|
||||
*/
|
||||
while (n > 0) {
|
||||
n = read(fd, p + m, Maxblock);
|
||||
if (n < 0) {
|
||||
warning(nil, "read error in Buffer.load");
|
||||
break;
|
||||
}
|
||||
if (h != nil)
|
||||
sha1((uchar*)p + m, n, nil, h);
|
||||
m += n;
|
||||
p[m] = 0;
|
||||
l = m;
|
||||
if (n > 0)
|
||||
l -= UTFmax;
|
||||
cvttorunes(p, l, r, &nb, &nr, nulls);
|
||||
memmove(p, p + nb, m - nb);
|
||||
m -= nb;
|
||||
q1 += (*f)(arg, q1, r, nr);
|
||||
}
|
||||
free(p);
|
||||
free(r);
|
||||
return q1 - q0;
|
||||
}
|
||||
|
||||
uint
|
||||
bufload(Buffer *b, uint q0, int fd, int *nulls, DigestState *h)
|
||||
{
|
||||
if(q0 > b->nc)
|
||||
error("internal error: bufload");
|
||||
return loadfile(fd, q0, nulls, bufloader, b, h);
|
||||
uint bufload(Buffer* b, uint q0, int fd, int* nulls, DigestState* h) {
|
||||
if (q0 > b->nc)
|
||||
error("internal error: bufload");
|
||||
return loadfile(fd, q0, nulls, bufloader, b, h);
|
||||
}
|
||||
|
||||
void
|
||||
bufread(Buffer *b, uint q0, Rune *s, uint n)
|
||||
{
|
||||
uint m;
|
||||
void bufread(Buffer* b, uint q0, Rune* s, uint n) {
|
||||
uint m;
|
||||
|
||||
if(!(q0<=b->nc && q0+n<=b->nc))
|
||||
error("bufread: internal error");
|
||||
if (!(q0 <= b->nc && q0 + n <= b->nc))
|
||||
error("bufread: internal error");
|
||||
|
||||
while(n > 0){
|
||||
setcache(b, q0);
|
||||
m = min(n, b->cnc-(q0-b->cq));
|
||||
runemove(s, b->c+(q0-b->cq), m);
|
||||
q0 += m;
|
||||
s += m;
|
||||
n -= m;
|
||||
}
|
||||
while (n > 0) {
|
||||
setcache(b, q0);
|
||||
m = min(n, b->cnc - (q0 - b->cq));
|
||||
runemove(s, b->c + (q0 - b->cq), m);
|
||||
q0 += m;
|
||||
s += m;
|
||||
n -= m;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bufreset(Buffer *b)
|
||||
{
|
||||
int i;
|
||||
void bufreset(Buffer* b) {
|
||||
int i;
|
||||
|
||||
b->nc = 0;
|
||||
b->cnc = 0;
|
||||
b->cq = 0;
|
||||
b->cdirty = 0;
|
||||
b->cbi = 0;
|
||||
/* delete backwards to avoid n² behavior */
|
||||
for(i=b->nbl-1; --i>=0; )
|
||||
delblock(b, i);
|
||||
b->nc = 0;
|
||||
b->cnc = 0;
|
||||
b->cq = 0;
|
||||
b->cdirty = 0;
|
||||
b->cbi = 0;
|
||||
/* delete backwards to avoid n² behavior */
|
||||
for (i = b->nbl - 1; --i >= 0;)
|
||||
delblock(b, i);
|
||||
}
|
||||
|
||||
void
|
||||
bufclose(Buffer *b)
|
||||
{
|
||||
bufreset(b);
|
||||
free(b->c);
|
||||
b->c = nil;
|
||||
b->cnc = 0;
|
||||
free(b->bl);
|
||||
b->bl = nil;
|
||||
b->nbl = 0;
|
||||
void bufclose(Buffer* b) {
|
||||
bufreset(b);
|
||||
free(b->c);
|
||||
b->c = nil;
|
||||
b->cnc = 0;
|
||||
free(b->bl);
|
||||
b->bl = nil;
|
||||
b->nbl = 0;
|
||||
}
|
||||
|
|
8
build.sh
Executable file
8
build.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
clang-format -i ./*.c
|
||||
clang-format -i ./mail/*.c
|
||||
|
||||
mk
|
||||
|
||||
mv o.acme acme
|
181
disk.c
181
disk.c
|
@ -12,122 +12,107 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static Block *blist;
|
||||
static Block* blist;
|
||||
|
||||
int
|
||||
tempfile(void)
|
||||
{
|
||||
char buf[128];
|
||||
int i, fd;
|
||||
int tempfile(void) {
|
||||
char buf[128];
|
||||
int i, fd;
|
||||
|
||||
snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser());
|
||||
for(i='A'; i<='Z'; i++){
|
||||
buf[5] = i;
|
||||
if(access(buf, AEXIST) == 0)
|
||||
continue;
|
||||
fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600);
|
||||
if(fd >= 0)
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser());
|
||||
for (i = 'A'; i <= 'Z'; i++) {
|
||||
buf[5] = i;
|
||||
if (access(buf, AEXIST) == 0)
|
||||
continue;
|
||||
fd = create(buf, ORDWR | ORCLOSE | OCEXEC, 0600);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Disk*
|
||||
diskinit()
|
||||
{
|
||||
Disk *d;
|
||||
Disk* diskinit() {
|
||||
Disk* d;
|
||||
|
||||
d = emalloc(sizeof(Disk));
|
||||
d->fd = tempfile();
|
||||
if(d->fd < 0){
|
||||
fprint(2, "acme: can't create temp file: %r\n");
|
||||
threadexitsall("diskinit");
|
||||
}
|
||||
return d;
|
||||
d = emalloc(sizeof(Disk));
|
||||
d->fd = tempfile();
|
||||
if (d->fd < 0) {
|
||||
fprint(2, "acme: can't create temp file: %r\n");
|
||||
threadexitsall("diskinit");
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static
|
||||
uint
|
||||
ntosize(uint n, uint *ip)
|
||||
{
|
||||
uint size;
|
||||
static uint ntosize(uint n, uint* ip) {
|
||||
uint size;
|
||||
|
||||
if(n > Maxblock)
|
||||
error("internal error: ntosize");
|
||||
size = n;
|
||||
if(size & (Blockincr-1))
|
||||
size += Blockincr - (size & (Blockincr-1));
|
||||
/* last bucket holds blocks of exactly Maxblock */
|
||||
if(ip)
|
||||
*ip = size/Blockincr;
|
||||
return size * sizeof(Rune);
|
||||
if (n > Maxblock)
|
||||
error("internal error: ntosize");
|
||||
size = n;
|
||||
if (size & (Blockincr - 1))
|
||||
size += Blockincr - (size & (Blockincr - 1));
|
||||
/* last bucket holds blocks of exactly Maxblock */
|
||||
if (ip)
|
||||
*ip = size / Blockincr;
|
||||
return size * sizeof(Rune);
|
||||
}
|
||||
|
||||
Block*
|
||||
disknewblock(Disk *d, uint n)
|
||||
{
|
||||
uint i, j, size;
|
||||
Block *b;
|
||||
Block* disknewblock(Disk* d, uint n) {
|
||||
uint i, j, size;
|
||||
Block* b;
|
||||
|
||||
size = ntosize(n, &i);
|
||||
b = d->free[i];
|
||||
if(b)
|
||||
d->free[i] = b->u.next;
|
||||
else{
|
||||
/* allocate in chunks to reduce malloc overhead */
|
||||
if(blist == nil){
|
||||
blist = emalloc(100*sizeof(Block));
|
||||
for(j=0; j<100-1; j++)
|
||||
blist[j].u.next = &blist[j+1];
|
||||
}
|
||||
b = blist;
|
||||
blist = b->u.next;
|
||||
b->addr = d->addr;
|
||||
if(d->addr+size < d->addr){
|
||||
error("temp file overflow");
|
||||
}
|
||||
d->addr += size;
|
||||
}
|
||||
b->u.n = n;
|
||||
return b;
|
||||
size = ntosize(n, &i);
|
||||
b = d->free[i];
|
||||
if (b)
|
||||
d->free[i] = b->u.next;
|
||||
else {
|
||||
/* allocate in chunks to reduce malloc overhead */
|
||||
if (blist == nil) {
|
||||
blist = emalloc(100 * sizeof(Block));
|
||||
for (j = 0; j < 100 - 1; j++)
|
||||
blist[j].u.next = &blist[j + 1];
|
||||
}
|
||||
b = blist;
|
||||
blist = b->u.next;
|
||||
b->addr = d->addr;
|
||||
if (d->addr + size < d->addr) {
|
||||
error("temp file overflow");
|
||||
}
|
||||
d->addr += size;
|
||||
}
|
||||
b->u.n = n;
|
||||
return b;
|
||||
}
|
||||
|
||||
void
|
||||
diskrelease(Disk *d, Block *b)
|
||||
{
|
||||
uint i;
|
||||
void diskrelease(Disk* d, Block* b) {
|
||||
uint i;
|
||||
|
||||
ntosize(b->u.n, &i);
|
||||
b->u.next = d->free[i];
|
||||
d->free[i] = b;
|
||||
ntosize(b->u.n, &i);
|
||||
b->u.next = d->free[i];
|
||||
d->free[i] = b;
|
||||
}
|
||||
|
||||
void
|
||||
diskwrite(Disk *d, Block **bp, Rune *r, uint n)
|
||||
{
|
||||
int size, nsize;
|
||||
Block *b;
|
||||
void diskwrite(Disk* d, Block** bp, Rune* r, uint n) {
|
||||
int size, nsize;
|
||||
Block* b;
|
||||
|
||||
b = *bp;
|
||||
size = ntosize(b->u.n, nil);
|
||||
nsize = ntosize(n, nil);
|
||||
if(size != nsize){
|
||||
diskrelease(d, b);
|
||||
b = disknewblock(d, n);
|
||||
*bp = b;
|
||||
}
|
||||
if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
|
||||
error("write error to temp file");
|
||||
b->u.n = n;
|
||||
b = *bp;
|
||||
size = ntosize(b->u.n, nil);
|
||||
nsize = ntosize(n, nil);
|
||||
if (size != nsize) {
|
||||
diskrelease(d, b);
|
||||
b = disknewblock(d, n);
|
||||
*bp = b;
|
||||
}
|
||||
if (pwrite(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
|
||||
error("write error to temp file");
|
||||
b->u.n = n;
|
||||
}
|
||||
|
||||
void
|
||||
diskread(Disk *d, Block *b, Rune *r, uint n)
|
||||
{
|
||||
if(n > b->u.n)
|
||||
error("internal error: diskread");
|
||||
void diskread(Disk* d, Block* b, Rune* r, uint n) {
|
||||
if (n > b->u.n)
|
||||
error("internal error: diskread");
|
||||
|
||||
ntosize(b->u.n, nil);
|
||||
if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
|
||||
error("read error from temp file");
|
||||
ntosize(b->u.n, nil);
|
||||
if (pread(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
|
||||
error("read error from temp file");
|
||||
}
|
||||
|
|
563
elog.c
563
elog.c
|
@ -14,7 +14,7 @@
|
|||
#include "edit.h"
|
||||
|
||||
static char Wsequence[] = "warning: changes out of sequence\n";
|
||||
static int warned = FALSE;
|
||||
static int warned = FALSE;
|
||||
|
||||
/*
|
||||
* Log of changes made by editing commands. Three reasons for this:
|
||||
|
@ -27,328 +27,321 @@ static int warned = FALSE;
|
|||
*/
|
||||
|
||||
typedef struct Buflog Buflog;
|
||||
struct Buflog
|
||||
{
|
||||
short type; /* Replace, Filename */
|
||||
uint q0; /* location of change (unused in f) */
|
||||
uint nd; /* # runes to delete */
|
||||
uint nr; /* # runes in string or file name */
|
||||
struct Buflog {
|
||||
short type; /* Replace, Filename */
|
||||
uint q0; /* location of change (unused in f) */
|
||||
uint nd; /* # runes to delete */
|
||||
uint nr; /* # runes in string or file name */
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Buflogsize = sizeof(Buflog)/sizeof(Rune)
|
||||
};
|
||||
enum { Buflogsize = sizeof(Buflog) / sizeof(Rune) };
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
Minstring = 16, /* distance beneath which we merge changes */
|
||||
Maxstring = RBUFSIZE /* maximum length of change we will merge into one */
|
||||
enum {
|
||||
Minstring = 16, /* distance beneath which we merge changes */
|
||||
Maxstring = RBUFSIZE /* maximum length of change we will merge into one */
|
||||
};
|
||||
|
||||
void
|
||||
eloginit(File *f)
|
||||
{
|
||||
if(f->elog.type != Empty)
|
||||
return;
|
||||
f->elog.type = Null;
|
||||
if(f->elogbuf == nil)
|
||||
f->elogbuf = emalloc(sizeof(Buffer));
|
||||
if(f->elog.r == nil)
|
||||
f->elog.r = fbufalloc();
|
||||
bufreset(f->elogbuf);
|
||||
void eloginit(File* f) {
|
||||
if (f->elog.type != Empty)
|
||||
return;
|
||||
f->elog.type = Null;
|
||||
if (f->elogbuf == nil)
|
||||
f->elogbuf = emalloc(sizeof(Buffer));
|
||||
if (f->elog.r == nil)
|
||||
f->elog.r = fbufalloc();
|
||||
bufreset(f->elogbuf);
|
||||
}
|
||||
|
||||
void
|
||||
elogclose(File *f)
|
||||
{
|
||||
if(f->elogbuf){
|
||||
bufclose(f->elogbuf);
|
||||
free(f->elogbuf);
|
||||
f->elogbuf = nil;
|
||||
}
|
||||
void elogclose(File* f) {
|
||||
if (f->elogbuf) {
|
||||
bufclose(f->elogbuf);
|
||||
free(f->elogbuf);
|
||||
f->elogbuf = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
elogreset(File *f)
|
||||
{
|
||||
f->elog.type = Null;
|
||||
f->elog.nd = 0;
|
||||
f->elog.nr = 0;
|
||||
void elogreset(File* f) {
|
||||
f->elog.type = Null;
|
||||
f->elog.nd = 0;
|
||||
f->elog.nr = 0;
|
||||
}
|
||||
|
||||
void
|
||||
elogterm(File *f)
|
||||
{
|
||||
elogreset(f);
|
||||
if(f->elogbuf)
|
||||
bufreset(f->elogbuf);
|
||||
f->elog.type = Empty;
|
||||
fbuffree(f->elog.r);
|
||||
f->elog.r = nil;
|
||||
warned = FALSE;
|
||||
void elogterm(File* f) {
|
||||
elogreset(f);
|
||||
if (f->elogbuf)
|
||||
bufreset(f->elogbuf);
|
||||
f->elog.type = Empty;
|
||||
fbuffree(f->elog.r);
|
||||
f->elog.r = nil;
|
||||
warned = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
elogflush(File *f)
|
||||
{
|
||||
Buflog b;
|
||||
void elogflush(File* f) {
|
||||
Buflog b;
|
||||
|
||||
b.type = f->elog.type;
|
||||
b.q0 = f->elog.q0;
|
||||
b.nd = f->elog.nd;
|
||||
b.nr = f->elog.nr;
|
||||
switch(f->elog.type){
|
||||
default:
|
||||
warning(nil, "unknown elog type 0x%ux\n", f->elog.type);
|
||||
break;
|
||||
case Null:
|
||||
break;
|
||||
case Insert:
|
||||
case Replace:
|
||||
if(f->elog.nr > 0)
|
||||
bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr);
|
||||
/* fall through */
|
||||
case Delete:
|
||||
bufinsert(f->elogbuf, f->elogbuf->nc, (Rune*)&b, Buflogsize);
|
||||
break;
|
||||
}
|
||||
elogreset(f);
|
||||
b.type = f->elog.type;
|
||||
b.q0 = f->elog.q0;
|
||||
b.nd = f->elog.nd;
|
||||
b.nr = f->elog.nr;
|
||||
switch (f->elog.type) {
|
||||
default:
|
||||
warning(nil, "unknown elog type 0x%ux\n", f->elog.type);
|
||||
break;
|
||||
case Null:
|
||||
break;
|
||||
case Insert:
|
||||
case Replace:
|
||||
if (f->elog.nr > 0)
|
||||
bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr);
|
||||
/* fall through */
|
||||
case Delete:
|
||||
bufinsert(f->elogbuf, f->elogbuf->nc, (Rune*)&b, Buflogsize);
|
||||
break;
|
||||
}
|
||||
elogreset(f);
|
||||
}
|
||||
|
||||
void
|
||||
elogreplace(File *f, int q0, int q1, Rune *r, int nr)
|
||||
{
|
||||
uint gap;
|
||||
void elogreplace(File* f, int q0, int q1, Rune* r, int nr) {
|
||||
uint gap;
|
||||
|
||||
if(q0==q1 && nr==0)
|
||||
return;
|
||||
eloginit(f);
|
||||
if(f->elog.type!=Null && q0<f->elog.q0){
|
||||
if(warned++ == 0)
|
||||
warning(nil, Wsequence);
|
||||
elogflush(f);
|
||||
}
|
||||
/* try to merge with previous */
|
||||
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(gap < Minstring){
|
||||
if(gap > 0){
|
||||
bufread(&f->b, f->elog.q0+f->elog.nd, f->elog.r+f->elog.nr, gap);
|
||||
f->elog.nr += gap;
|
||||
}
|
||||
f->elog.nd += gap + q1-q0;
|
||||
runemove(f->elog.r+f->elog.nr, r, nr);
|
||||
f->elog.nr += nr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
elogflush(f);
|
||||
f->elog.type = Replace;
|
||||
f->elog.q0 = q0;
|
||||
f->elog.nd = q1-q0;
|
||||
f->elog.nr = nr;
|
||||
if(nr > RBUFSIZE)
|
||||
editerror("internal error: replacement string too large(%d)", nr);
|
||||
runemove(f->elog.r, r, nr);
|
||||
if (q0 == q1 && nr == 0)
|
||||
return;
|
||||
eloginit(f);
|
||||
if (f->elog.type != Null && q0 < f->elog.q0) {
|
||||
if (warned++ == 0)
|
||||
warning(nil, Wsequence);
|
||||
elogflush(f);
|
||||
}
|
||||
/* try to merge with previous */
|
||||
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 (gap < Minstring) {
|
||||
if (gap > 0) {
|
||||
bufread(&f->b, f->elog.q0 + f->elog.nd, f->elog.r + f->elog.nr, gap);
|
||||
f->elog.nr += gap;
|
||||
}
|
||||
f->elog.nd += gap + q1 - q0;
|
||||
runemove(f->elog.r + f->elog.nr, r, nr);
|
||||
f->elog.nr += nr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
elogflush(f);
|
||||
f->elog.type = Replace;
|
||||
f->elog.q0 = q0;
|
||||
f->elog.nd = q1 - q0;
|
||||
f->elog.nr = nr;
|
||||
if (nr > RBUFSIZE)
|
||||
editerror("internal error: replacement string too large(%d)", nr);
|
||||
runemove(f->elog.r, r, nr);
|
||||
}
|
||||
|
||||
void
|
||||
eloginsert(File *f, int q0, Rune *r, int nr)
|
||||
{
|
||||
int n;
|
||||
void eloginsert(File* f, int q0, Rune* r, int nr) {
|
||||
int n;
|
||||
|
||||
if(nr == 0)
|
||||
return;
|
||||
eloginit(f);
|
||||
if(f->elog.type!=Null && q0<f->elog.q0){
|
||||
if(warned++ == 0)
|
||||
warning(nil, Wsequence);
|
||||
elogflush(f);
|
||||
}
|
||||
/* try to merge with previous */
|
||||
if(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;
|
||||
return;
|
||||
}
|
||||
while(nr > 0){
|
||||
elogflush(f);
|
||||
f->elog.type = Insert;
|
||||
f->elog.q0 = q0;
|
||||
n = nr;
|
||||
if(n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
f->elog.nr = n;
|
||||
runemove(f->elog.r, r, n);
|
||||
r += n;
|
||||
nr -= n;
|
||||
}
|
||||
if (nr == 0)
|
||||
return;
|
||||
eloginit(f);
|
||||
if (f->elog.type != Null && q0 < f->elog.q0) {
|
||||
if (warned++ == 0)
|
||||
warning(nil, Wsequence);
|
||||
elogflush(f);
|
||||
}
|
||||
/* try to merge with previous */
|
||||
if (
|
||||
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;
|
||||
return;
|
||||
}
|
||||
while (nr > 0) {
|
||||
elogflush(f);
|
||||
f->elog.type = Insert;
|
||||
f->elog.q0 = q0;
|
||||
n = nr;
|
||||
if (n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
f->elog.nr = n;
|
||||
runemove(f->elog.r, r, n);
|
||||
r += n;
|
||||
nr -= n;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
elogdelete(File *f, int q0, int q1)
|
||||
{
|
||||
if(q0 == q1)
|
||||
return;
|
||||
eloginit(f);
|
||||
if(f->elog.type!=Null && q0<f->elog.q0+f->elog.nd){
|
||||
if(warned++ == 0)
|
||||
warning(nil, Wsequence);
|
||||
elogflush(f);
|
||||
}
|
||||
/* try to merge with previous */
|
||||
if(f->elog.type==Delete && f->elog.q0+f->elog.nd==q0){
|
||||
f->elog.nd += q1-q0;
|
||||
return;
|
||||
}
|
||||
elogflush(f);
|
||||
f->elog.type = Delete;
|
||||
f->elog.q0 = q0;
|
||||
f->elog.nd = q1-q0;
|
||||
void elogdelete(File* f, int q0, int q1) {
|
||||
if (q0 == q1)
|
||||
return;
|
||||
eloginit(f);
|
||||
if (f->elog.type != Null && q0 < f->elog.q0 + f->elog.nd) {
|
||||
if (warned++ == 0)
|
||||
warning(nil, Wsequence);
|
||||
elogflush(f);
|
||||
}
|
||||
/* try to merge with previous */
|
||||
if (f->elog.type == Delete && f->elog.q0 + f->elog.nd == q0) {
|
||||
f->elog.nd += q1 - q0;
|
||||
return;
|
||||
}
|
||||
elogflush(f);
|
||||
f->elog.type = Delete;
|
||||
f->elog.q0 = q0;
|
||||
f->elog.nd = q1 - q0;
|
||||
}
|
||||
|
||||
#define tracelog 0
|
||||
void
|
||||
elogapply(File *f)
|
||||
{
|
||||
Buflog b;
|
||||
Rune *buf;
|
||||
uint i, n, up, mod;
|
||||
uint tq0, tq1;
|
||||
Buffer *log;
|
||||
Text *t;
|
||||
int owner;
|
||||
void elogapply(File* f) {
|
||||
Buflog b;
|
||||
Rune* buf;
|
||||
uint i, n, up, mod;
|
||||
uint tq0, tq1;
|
||||
Buffer* log;
|
||||
Text* t;
|
||||
int owner;
|
||||
|
||||
elogflush(f);
|
||||
log = f->elogbuf;
|
||||
t = f->curtext;
|
||||
elogflush(f);
|
||||
log = f->elogbuf;
|
||||
t = f->curtext;
|
||||
|
||||
buf = fbufalloc();
|
||||
mod = FALSE;
|
||||
buf = fbufalloc();
|
||||
mod = FALSE;
|
||||
|
||||
owner = 0;
|
||||
if(t->w){
|
||||
owner = t->w->owner;
|
||||
if(owner == 0)
|
||||
t->w->owner = 'E';
|
||||
}
|
||||
owner = 0;
|
||||
if (t->w) {
|
||||
owner = t->w->owner;
|
||||
if (owner == 0)
|
||||
t->w->owner = 'E';
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
* we have to update the coordinates to be relative to the modified buffer.
|
||||
* Textinsert and textdelete will do this for us; our only work is to apply the
|
||||
* convention that an insertion at t->q0==t->q1 is intended to select the
|
||||
* inserted text.
|
||||
*/
|
||||
/*
|
||||
* 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, we have to update the coordinates to be relative to the modified
|
||||
* buffer. Textinsert and textdelete will do this for us; our only work is to
|
||||
* apply the convention that an insertion at t->q0==t->q1 is intended to
|
||||
* select the inserted text.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We constrain the addresses in here (with textconstrain()) because
|
||||
* overlapping changes will generate bogus addresses. We will warn
|
||||
* about changes out of sequence but proceed anyway; here we must
|
||||
* keep things in range.
|
||||
*/
|
||||
/*
|
||||
* We constrain the addresses in here (with textconstrain()) because
|
||||
* overlapping changes will generate bogus addresses. We will warn
|
||||
* about changes out of sequence but proceed anyway; here we must
|
||||
* keep things in range.
|
||||
*/
|
||||
|
||||
while(log->nc > 0){
|
||||
up = log->nc-Buflogsize;
|
||||
bufread(log, up, (Rune*)&b, Buflogsize);
|
||||
switch(b.type){
|
||||
default:
|
||||
fprint(2, "elogapply: 0x%ux\n", b.type);
|
||||
abort();
|
||||
break;
|
||||
while (log->nc > 0) {
|
||||
up = log->nc - Buflogsize;
|
||||
bufread(log, up, (Rune*)&b, Buflogsize);
|
||||
switch (b.type) {
|
||||
default:
|
||||
fprint(2, "elogapply: 0x%ux\n", b.type);
|
||||
abort();
|
||||
break;
|
||||
|
||||
case Replace:
|
||||
if(tracelog)
|
||||
warning(nil, "elog replace %d %d (%d %d)\n",
|
||||
b.q0, b.q0+b.nd, t->q0, t->q1);
|
||||
if(!mod){
|
||||
mod = TRUE;
|
||||
filemark(f);
|
||||
}
|
||||
textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1);
|
||||
textdelete(t, tq0, tq1, TRUE);
|
||||
up -= b.nr;
|
||||
for(i=0; i<b.nr; i+=n){
|
||||
n = b.nr - i;
|
||||
if(n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(log, up+i, buf, n);
|
||||
textinsert(t, tq0+i, buf, n, TRUE);
|
||||
}
|
||||
if(t->q0 == b.q0 && t->q1 == b.q0)
|
||||
t->q1 += b.nr;
|
||||
break;
|
||||
case Replace:
|
||||
if (tracelog)
|
||||
warning(
|
||||
nil,
|
||||
"elog replace %d %d (%d %d)\n",
|
||||
b.q0,
|
||||
b.q0 + b.nd,
|
||||
t->q0,
|
||||
t->q1);
|
||||
if (!mod) {
|
||||
mod = TRUE;
|
||||
filemark(f);
|
||||
}
|
||||
textconstrain(t, b.q0, b.q0 + b.nd, &tq0, &tq1);
|
||||
textdelete(t, tq0, tq1, TRUE);
|
||||
up -= b.nr;
|
||||
for (i = 0; i < b.nr; i += n) {
|
||||
n = b.nr - i;
|
||||
if (n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(log, up + i, buf, n);
|
||||
textinsert(t, tq0 + i, buf, n, TRUE);
|
||||
}
|
||||
if (t->q0 == b.q0 && t->q1 == b.q0)
|
||||
t->q1 += b.nr;
|
||||
break;
|
||||
|
||||
case Delete:
|
||||
if(tracelog)
|
||||
warning(nil, "elog delete %d %d (%d %d)\n",
|
||||
b.q0, b.q0+b.nd, t->q0, t->q1);
|
||||
if(!mod){
|
||||
mod = TRUE;
|
||||
filemark(f);
|
||||
}
|
||||
textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1);
|
||||
textdelete(t, tq0, tq1, TRUE);
|
||||
break;
|
||||
case Delete:
|
||||
if (tracelog)
|
||||
warning(
|
||||
nil,
|
||||
"elog delete %d %d (%d %d)\n",
|
||||
b.q0,
|
||||
b.q0 + b.nd,
|
||||
t->q0,
|
||||
t->q1);
|
||||
if (!mod) {
|
||||
mod = TRUE;
|
||||
filemark(f);
|
||||
}
|
||||
textconstrain(t, b.q0, b.q0 + b.nd, &tq0, &tq1);
|
||||
textdelete(t, tq0, tq1, TRUE);
|
||||
break;
|
||||
|
||||
case Insert:
|
||||
if(tracelog)
|
||||
warning(nil, "elog insert %d %d (%d %d)\n",
|
||||
b.q0, b.q0+b.nr, t->q0, t->q1);
|
||||
if(!mod){
|
||||
mod = TRUE;
|
||||
filemark(f);
|
||||
}
|
||||
textconstrain(t, b.q0, b.q0, &tq0, &tq1);
|
||||
up -= b.nr;
|
||||
for(i=0; i<b.nr; i+=n){
|
||||
n = b.nr - i;
|
||||
if(n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(log, up+i, buf, n);
|
||||
textinsert(t, tq0+i, buf, n, TRUE);
|
||||
}
|
||||
if(t->q0 == b.q0 && t->q1 == b.q0)
|
||||
t->q1 += b.nr;
|
||||
break;
|
||||
case Insert:
|
||||
if (tracelog)
|
||||
warning(
|
||||
nil,
|
||||
"elog insert %d %d (%d %d)\n",
|
||||
b.q0,
|
||||
b.q0 + b.nr,
|
||||
t->q0,
|
||||
t->q1);
|
||||
if (!mod) {
|
||||
mod = TRUE;
|
||||
filemark(f);
|
||||
}
|
||||
textconstrain(t, b.q0, b.q0, &tq0, &tq1);
|
||||
up -= b.nr;
|
||||
for (i = 0; i < b.nr; i += n) {
|
||||
n = b.nr - i;
|
||||
if (n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(log, up + i, buf, n);
|
||||
textinsert(t, tq0 + i, buf, n, TRUE);
|
||||
}
|
||||
if (t->q0 == b.q0 && t->q1 == b.q0)
|
||||
t->q1 += b.nr;
|
||||
break;
|
||||
|
||||
/* case Filename:
|
||||
f->seq = u.seq;
|
||||
fileunsetname(f, epsilon);
|
||||
f->mod = u.mod;
|
||||
up -= u.n;
|
||||
free(f->name);
|
||||
if(u.n == 0)
|
||||
f->name = nil;
|
||||
else
|
||||
f->name = runemalloc(u.n);
|
||||
bufread(delta, up, f->name, u.n);
|
||||
f->nname = u.n;
|
||||
break;
|
||||
*/
|
||||
}
|
||||
bufdelete(log, up, log->nc);
|
||||
}
|
||||
fbuffree(buf);
|
||||
elogterm(f);
|
||||
|
||||
/*
|
||||
* 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(t->q0 > f->b.nc || t->q1 > f->b.nc || t->q0 > t->q1){
|
||||
if(!warned)
|
||||
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->q0 = min(t->q0, t->q1);
|
||||
}
|
||||
/* case Filename:
|
||||
f->seq = u.seq;
|
||||
fileunsetname(f, epsilon);
|
||||
f->mod = u.mod;
|
||||
up -= u.n;
|
||||
free(f->name);
|
||||
if(u.n == 0)
|
||||
f->name = nil;
|
||||
else
|
||||
f->name = runemalloc(u.n);
|
||||
bufread(delta, up, f->name, u.n);
|
||||
f->nname = u.n;
|
||||
break;
|
||||
*/
|
||||
}
|
||||
bufdelete(log, up, log->nc);
|
||||
}
|
||||
fbuffree(buf);
|
||||
elogterm(f);
|
||||
|
||||
if(t->w)
|
||||
t->w->owner = owner;
|
||||
/*
|
||||
* 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 (t->q0 > f->b.nc || t->q1 > f->b.nc || t->q0 > t->q1) {
|
||||
if (!warned)
|
||||
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->q0 = min(t->q0, t->q1);
|
||||
}
|
||||
|
||||
if (t->w)
|
||||
t->w->owner = owner;
|
||||
}
|
||||
|
|
455
file.c
455
file.c
|
@ -23,289 +23,256 @@
|
|||
*/
|
||||
|
||||
typedef struct Undo Undo;
|
||||
struct Undo
|
||||
{
|
||||
short type; /* Delete, Insert, Filename */
|
||||
short mod; /* modify bit */
|
||||
uint seq; /* sequence number */
|
||||
uint p0; /* location of change (unused in f) */
|
||||
uint n; /* # runes in string or file name */
|
||||
struct Undo {
|
||||
short type; /* Delete, Insert, Filename */
|
||||
short mod; /* modify bit */
|
||||
uint seq; /* sequence number */
|
||||
uint p0; /* location of change (unused in f) */
|
||||
uint n; /* # runes in string or file name */
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Undosize = sizeof(Undo)/sizeof(Rune)
|
||||
};
|
||||
enum { Undosize = sizeof(Undo) / sizeof(Rune) };
|
||||
|
||||
File*
|
||||
fileaddtext(File *f, Text *t)
|
||||
{
|
||||
if(f == nil){
|
||||
f = emalloc(sizeof(File));
|
||||
f->unread = TRUE;
|
||||
}
|
||||
f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
|
||||
f->text[f->ntext++] = t;
|
||||
f->curtext = t;
|
||||
return f;
|
||||
File* fileaddtext(File* f, Text* t) {
|
||||
if (f == nil) {
|
||||
f = emalloc(sizeof(File));
|
||||
f->unread = TRUE;
|
||||
}
|
||||
f->text = realloc(f->text, (f->ntext + 1) * sizeof(Text*));
|
||||
f->text[f->ntext++] = t;
|
||||
f->curtext = t;
|
||||
return f;
|
||||
}
|
||||
|
||||
void
|
||||
filedeltext(File *f, Text *t)
|
||||
{
|
||||
int i;
|
||||
void filedeltext(File* f, Text* t) {
|
||||
int i;
|
||||
|
||||
for(i=0; i<f->ntext; i++)
|
||||
if(f->text[i] == t)
|
||||
goto Found;
|
||||
error("can't find text in filedeltext");
|
||||
for (i = 0; i < f->ntext; i++)
|
||||
if (f->text[i] == t)
|
||||
goto Found;
|
||||
error("can't find text in filedeltext");
|
||||
|
||||
Found:
|
||||
f->ntext--;
|
||||
if(f->ntext == 0){
|
||||
fileclose(f);
|
||||
return;
|
||||
}
|
||||
memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
|
||||
if(f->curtext == t)
|
||||
f->curtext = f->text[0];
|
||||
Found:
|
||||
f->ntext--;
|
||||
if (f->ntext == 0) {
|
||||
fileclose(f);
|
||||
return;
|
||||
}
|
||||
memmove(f->text + i, f->text + i + 1, (f->ntext - i) * sizeof(Text*));
|
||||
if (f->curtext == t)
|
||||
f->curtext = f->text[0];
|
||||
}
|
||||
|
||||
void
|
||||
fileinsert(File *f, uint p0, Rune *s, uint ns)
|
||||
{
|
||||
if(p0 > f->b.nc)
|
||||
error("internal error: fileinsert");
|
||||
if(f->seq > 0)
|
||||
fileuninsert(f, &f->delta, p0, ns);
|
||||
bufinsert(&f->b, p0, s, ns);
|
||||
if(ns)
|
||||
f->mod = TRUE;
|
||||
void fileinsert(File* f, uint p0, Rune* s, uint ns) {
|
||||
if (p0 > f->b.nc)
|
||||
error("internal error: fileinsert");
|
||||
if (f->seq > 0)
|
||||
fileuninsert(f, &f->delta, p0, ns);
|
||||
bufinsert(&f->b, p0, s, ns);
|
||||
if (ns)
|
||||
f->mod = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
|
||||
{
|
||||
Undo u;
|
||||
void fileuninsert(File* f, Buffer* delta, uint p0, uint ns) {
|
||||
Undo u;
|
||||
|
||||
/* undo an insertion by deleting */
|
||||
u.type = Delete;
|
||||
u.mod = f->mod;
|
||||
u.seq = f->seq;
|
||||
u.p0 = p0;
|
||||
u.n = ns;
|
||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||
/* undo an insertion by deleting */
|
||||
u.type = Delete;
|
||||
u.mod = f->mod;
|
||||
u.seq = f->seq;
|
||||
u.p0 = p0;
|
||||
u.n = ns;
|
||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||
}
|
||||
|
||||
void
|
||||
filedelete(File *f, uint p0, uint p1)
|
||||
{
|
||||
if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
|
||||
error("internal error: filedelete");
|
||||
if(f->seq > 0)
|
||||
fileundelete(f, &f->delta, p0, p1);
|
||||
bufdelete(&f->b, p0, p1);
|
||||
if(p1 > p0)
|
||||
f->mod = TRUE;
|
||||
void filedelete(File* f, uint p0, uint p1) {
|
||||
if (!(p0 <= p1 && p0 <= f->b.nc && p1 <= f->b.nc))
|
||||
error("internal error: filedelete");
|
||||
if (f->seq > 0)
|
||||
fileundelete(f, &f->delta, p0, p1);
|
||||
bufdelete(&f->b, p0, p1);
|
||||
if (p1 > p0)
|
||||
f->mod = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
fileundelete(File *f, Buffer *delta, uint p0, uint p1)
|
||||
{
|
||||
Undo u;
|
||||
Rune *buf;
|
||||
uint i, n;
|
||||
|
||||
/* undo a deletion by inserting */
|
||||
u.type = Insert;
|
||||
u.mod = f->mod;
|
||||
u.seq = f->seq;
|
||||
u.p0 = p0;
|
||||
u.n = p1-p0;
|
||||
buf = fbufalloc();
|
||||
for(i=p0; i<p1; i+=n){
|
||||
n = p1 - i;
|
||||
if(n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(&f->b, i, buf, n);
|
||||
bufinsert(delta, delta->nc, buf, n);
|
||||
}
|
||||
fbuffree(buf);
|
||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||
void fileundelete(File* f, Buffer* delta, uint p0, uint p1) {
|
||||
Undo u;
|
||||
Rune* buf;
|
||||
uint i, n;
|
||||
|
||||
/* undo a deletion by inserting */
|
||||
u.type = Insert;
|
||||
u.mod = f->mod;
|
||||
u.seq = f->seq;
|
||||
u.p0 = p0;
|
||||
u.n = p1 - p0;
|
||||
buf = fbufalloc();
|
||||
for (i = p0; i < p1; i += n) {
|
||||
n = p1 - i;
|
||||
if (n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(&f->b, i, buf, n);
|
||||
bufinsert(delta, delta->nc, buf, n);
|
||||
}
|
||||
fbuffree(buf);
|
||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||
}
|
||||
|
||||
void
|
||||
filesetname(File *f, Rune *name, int n)
|
||||
{
|
||||
if(f->seq > 0)
|
||||
fileunsetname(f, &f->delta);
|
||||
free(f->name);
|
||||
f->name = runemalloc(n);
|
||||
runemove(f->name, name, n);
|
||||
f->nname = n;
|
||||
f->unread = TRUE;
|
||||
void filesetname(File* f, Rune* name, int n) {
|
||||
if (f->seq > 0)
|
||||
fileunsetname(f, &f->delta);
|
||||
free(f->name);
|
||||
f->name = runemalloc(n);
|
||||
runemove(f->name, name, n);
|
||||
f->nname = n;
|
||||
f->unread = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
fileunsetname(File *f, Buffer *delta)
|
||||
{
|
||||
Undo u;
|
||||
void fileunsetname(File* f, Buffer* delta) {
|
||||
Undo u;
|
||||
|
||||
/* undo a file name change by restoring old name */
|
||||
u.type = Filename;
|
||||
u.mod = f->mod;
|
||||
u.seq = f->seq;
|
||||
u.p0 = 0; /* unused */
|
||||
u.n = f->nname;
|
||||
if(f->nname)
|
||||
bufinsert(delta, delta->nc, f->name, f->nname);
|
||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||
/* undo a file name change by restoring old name */
|
||||
u.type = Filename;
|
||||
u.mod = f->mod;
|
||||
u.seq = f->seq;
|
||||
u.p0 = 0; /* unused */
|
||||
u.n = f->nname;
|
||||
if (f->nname)
|
||||
bufinsert(delta, delta->nc, f->name, f->nname);
|
||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||
}
|
||||
|
||||
uint
|
||||
fileload(File *f, uint p0, int fd, int *nulls, DigestState *h)
|
||||
{
|
||||
if(f->seq > 0)
|
||||
error("undo in file.load unimplemented");
|
||||
return bufload(&f->b, p0, fd, nulls, h);
|
||||
uint fileload(File* f, uint p0, int fd, int* nulls, DigestState* h) {
|
||||
if (f->seq > 0)
|
||||
error("undo in file.load unimplemented");
|
||||
return bufload(&f->b, p0, fd, nulls, h);
|
||||
}
|
||||
|
||||
/* return sequence number of pending redo */
|
||||
uint
|
||||
fileredoseq(File *f)
|
||||
{
|
||||
Undo u;
|
||||
Buffer *delta;
|
||||
uint fileredoseq(File* f) {
|
||||
Undo u;
|
||||
Buffer* delta;
|
||||
|
||||
delta = &f->epsilon;
|
||||
if(delta->nc == 0)
|
||||
return 0;
|
||||
bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize);
|
||||
return u.seq;
|
||||
delta = &f->epsilon;
|
||||
if (delta->nc == 0)
|
||||
return 0;
|
||||
bufread(delta, delta->nc - Undosize, (Rune*)&u, Undosize);
|
||||
return u.seq;
|
||||
}
|
||||
|
||||
void
|
||||
fileundo(File *f, int isundo, uint *q0p, uint *q1p)
|
||||
{
|
||||
Undo u;
|
||||
Rune *buf;
|
||||
uint i, j, n, up;
|
||||
uint stop;
|
||||
Buffer *delta, *epsilon;
|
||||
void fileundo(File* f, int isundo, uint* q0p, uint* q1p) {
|
||||
Undo u;
|
||||
Rune* buf;
|
||||
uint i, j, n, up;
|
||||
uint stop;
|
||||
Buffer *delta, *epsilon;
|
||||
|
||||
if(isundo){
|
||||
/* undo; reverse delta onto epsilon, seq decreases */
|
||||
delta = &f->delta;
|
||||
epsilon = &f->epsilon;
|
||||
stop = f->seq;
|
||||
}else{
|
||||
/* redo; reverse epsilon onto delta, seq increases */
|
||||
delta = &f->epsilon;
|
||||
epsilon = &f->delta;
|
||||
stop = 0; /* don't know yet */
|
||||
}
|
||||
if (isundo) {
|
||||
/* undo; reverse delta onto epsilon, seq decreases */
|
||||
delta = &f->delta;
|
||||
epsilon = &f->epsilon;
|
||||
stop = f->seq;
|
||||
} else {
|
||||
/* redo; reverse epsilon onto delta, seq increases */
|
||||
delta = &f->epsilon;
|
||||
epsilon = &f->delta;
|
||||
stop = 0; /* don't know yet */
|
||||
}
|
||||
|
||||
buf = fbufalloc();
|
||||
while(delta->nc > 0){
|
||||
up = delta->nc-Undosize;
|
||||
bufread(delta, up, (Rune*)&u, Undosize);
|
||||
if(isundo){
|
||||
if(u.seq < stop){
|
||||
f->seq = u.seq;
|
||||
goto Return;
|
||||
}
|
||||
}else{
|
||||
if(stop == 0)
|
||||
stop = u.seq;
|
||||
if(u.seq > stop)
|
||||
goto Return;
|
||||
}
|
||||
switch(u.type){
|
||||
default:
|
||||
fprint(2, "undo: 0x%ux\n", u.type);
|
||||
abort();
|
||||
break;
|
||||
buf = fbufalloc();
|
||||
while (delta->nc > 0) {
|
||||
up = delta->nc - Undosize;
|
||||
bufread(delta, up, (Rune*)&u, Undosize);
|
||||
if (isundo) {
|
||||
if (u.seq < stop) {
|
||||
f->seq = u.seq;
|
||||
goto Return;
|
||||
}
|
||||
} else {
|
||||
if (stop == 0)
|
||||
stop = u.seq;
|
||||
if (u.seq > stop)
|
||||
goto Return;
|
||||
}
|
||||
switch (u.type) {
|
||||
default:
|
||||
fprint(2, "undo: 0x%ux\n", u.type);
|
||||
abort();
|
||||
break;
|
||||
|
||||
case Delete:
|
||||
f->seq = u.seq;
|
||||
fileundelete(f, epsilon, u.p0, u.p0+u.n);
|
||||
f->mod = u.mod;
|
||||
bufdelete(&f->b, u.p0, u.p0+u.n);
|
||||
for(j=0; j<f->ntext; j++)
|
||||
textdelete(f->text[j], u.p0, u.p0+u.n, FALSE);
|
||||
*q0p = u.p0;
|
||||
*q1p = u.p0;
|
||||
break;
|
||||
case Delete:
|
||||
f->seq = u.seq;
|
||||
fileundelete(f, epsilon, u.p0, u.p0 + u.n);
|
||||
f->mod = u.mod;
|
||||
bufdelete(&f->b, u.p0, u.p0 + u.n);
|
||||
for (j = 0; j < f->ntext; j++)
|
||||
textdelete(f->text[j], u.p0, u.p0 + u.n, FALSE);
|
||||
*q0p = u.p0;
|
||||
*q1p = u.p0;
|
||||
break;
|
||||
|
||||
case Insert:
|
||||
f->seq = u.seq;
|
||||
fileuninsert(f, epsilon, u.p0, u.n);
|
||||
f->mod = u.mod;
|
||||
up -= u.n;
|
||||
for(i=0; i<u.n; i+=n){
|
||||
n = u.n - i;
|
||||
if(n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(delta, up+i, buf, n);
|
||||
bufinsert(&f->b, u.p0+i, buf, n);
|
||||
for(j=0; j<f->ntext; j++)
|
||||
textinsert(f->text[j], u.p0+i, buf, n, FALSE);
|
||||
}
|
||||
*q0p = u.p0;
|
||||
*q1p = u.p0+u.n;
|
||||
break;
|
||||
case Insert:
|
||||
f->seq = u.seq;
|
||||
fileuninsert(f, epsilon, u.p0, u.n);
|
||||
f->mod = u.mod;
|
||||
up -= u.n;
|
||||
for (i = 0; i < u.n; i += n) {
|
||||
n = u.n - i;
|
||||
if (n > RBUFSIZE)
|
||||
n = RBUFSIZE;
|
||||
bufread(delta, up + i, buf, n);
|
||||
bufinsert(&f->b, u.p0 + i, buf, n);
|
||||
for (j = 0; j < f->ntext; j++)
|
||||
textinsert(f->text[j], u.p0 + i, buf, n, FALSE);
|
||||
}
|
||||
*q0p = u.p0;
|
||||
*q1p = u.p0 + u.n;
|
||||
break;
|
||||
|
||||
case Filename:
|
||||
f->seq = u.seq;
|
||||
fileunsetname(f, epsilon);
|
||||
f->mod = u.mod;
|
||||
up -= u.n;
|
||||
free(f->name);
|
||||
if(u.n == 0)
|
||||
f->name = nil;
|
||||
else
|
||||
f->name = runemalloc(u.n);
|
||||
bufread(delta, up, f->name, u.n);
|
||||
f->nname = u.n;
|
||||
break;
|
||||
}
|
||||
bufdelete(delta, up, delta->nc);
|
||||
}
|
||||
if(isundo)
|
||||
f->seq = 0;
|
||||
Return:
|
||||
fbuffree(buf);
|
||||
case Filename:
|
||||
f->seq = u.seq;
|
||||
fileunsetname(f, epsilon);
|
||||
f->mod = u.mod;
|
||||
up -= u.n;
|
||||
free(f->name);
|
||||
if (u.n == 0)
|
||||
f->name = nil;
|
||||
else
|
||||
f->name = runemalloc(u.n);
|
||||
bufread(delta, up, f->name, u.n);
|
||||
f->nname = u.n;
|
||||
break;
|
||||
}
|
||||
bufdelete(delta, up, delta->nc);
|
||||
}
|
||||
if (isundo)
|
||||
f->seq = 0;
|
||||
Return:
|
||||
fbuffree(buf);
|
||||
}
|
||||
|
||||
void
|
||||
filereset(File *f)
|
||||
{
|
||||
bufreset(&f->delta);
|
||||
bufreset(&f->epsilon);
|
||||
f->seq = 0;
|
||||
void filereset(File* f) {
|
||||
bufreset(&f->delta);
|
||||
bufreset(&f->epsilon);
|
||||
f->seq = 0;
|
||||
}
|
||||
|
||||
void
|
||||
fileclose(File *f)
|
||||
{
|
||||
free(f->name);
|
||||
f->nname = 0;
|
||||
f->name = nil;
|
||||
free(f->text);
|
||||
f->ntext = 0;
|
||||
f->text = nil;
|
||||
bufclose(&f->b);
|
||||
bufclose(&f->delta);
|
||||
bufclose(&f->epsilon);
|
||||
elogclose(f);
|
||||
free(f);
|
||||
void fileclose(File* f) {
|
||||
free(f->name);
|
||||
f->nname = 0;
|
||||
f->name = nil;
|
||||
free(f->text);
|
||||
f->ntext = 0;
|
||||
f->text = nil;
|
||||
bufclose(&f->b);
|
||||
bufclose(&f->delta);
|
||||
bufclose(&f->epsilon);
|
||||
elogclose(f);
|
||||
free(f);
|
||||
}
|
||||
|
||||
void
|
||||
filemark(File *f)
|
||||
{
|
||||
if(f->epsilon.nc)
|
||||
bufdelete(&f->epsilon, 0, f->epsilon.nc);
|
||||
f->seq = seq;
|
||||
void filemark(File* f) {
|
||||
if (f->epsilon.nc)
|
||||
bufdelete(&f->epsilon, 0, f->epsilon.nc);
|
||||
f->seq = seq;
|
||||
}
|
||||
|
|
1
fns.h
1
fns.h
|
@ -95,6 +95,7 @@ void flushwarnings(void);
|
|||
void startplumbing(void);
|
||||
long nlcount(Text*, long, long, long*);
|
||||
long nlcounttopos(Text*, long, long, long);
|
||||
Rune* parsetag(Window*, int*);
|
||||
|
||||
Runestr runestr(Rune*, uint);
|
||||
Range range(int, int);
|
||||
|
|
271
logf.c
271
logf.c
|
@ -14,122 +14,114 @@
|
|||
|
||||
// State for global log file.
|
||||
typedef struct Log Log;
|
||||
struct Log
|
||||
{
|
||||
QLock lk;
|
||||
Rendez r;
|
||||
struct Log {
|
||||
QLock lk;
|
||||
Rendez r;
|
||||
|
||||
vlong start; // msg[0] corresponds to 'start' in the global sequence of events
|
||||
|
||||
// queued events (nev=entries in ev, mev=capacity of p)
|
||||
char **ev;
|
||||
int nev;
|
||||
int mev;
|
||||
vlong start; // msg[0] corresponds to 'start' in the global sequence of events
|
||||
|
||||
// open acme/put files that need to read events
|
||||
Fid **f;
|
||||
int nf;
|
||||
int mf;
|
||||
|
||||
// active (blocked) reads waiting for events
|
||||
Xfid **read;
|
||||
int nread;
|
||||
int mread;
|
||||
// queued events (nev=entries in ev, mev=capacity of p)
|
||||
char** ev;
|
||||
int nev;
|
||||
int mev;
|
||||
|
||||
// open acme/put files that need to read events
|
||||
Fid** f;
|
||||
int nf;
|
||||
int mf;
|
||||
|
||||
// active (blocked) reads waiting for events
|
||||
Xfid** read;
|
||||
int nread;
|
||||
int mread;
|
||||
};
|
||||
|
||||
static Log eventlog;
|
||||
|
||||
void
|
||||
xfidlogopen(Xfid *x)
|
||||
{
|
||||
qlock(&eventlog.lk);
|
||||
if(eventlog.nf >= eventlog.mf) {
|
||||
eventlog.mf = eventlog.mf*2;
|
||||
if(eventlog.mf == 0)
|
||||
eventlog.mf = 8;
|
||||
eventlog.f = erealloc(eventlog.f, eventlog.mf*sizeof eventlog.f[0]);
|
||||
}
|
||||
eventlog.f[eventlog.nf++] = x->f;
|
||||
x->f->logoff = eventlog.start + eventlog.nev;
|
||||
void xfidlogopen(Xfid* x) {
|
||||
qlock(&eventlog.lk);
|
||||
if (eventlog.nf >= eventlog.mf) {
|
||||
eventlog.mf = eventlog.mf * 2;
|
||||
if (eventlog.mf == 0)
|
||||
eventlog.mf = 8;
|
||||
eventlog.f = erealloc(eventlog.f, eventlog.mf * sizeof eventlog.f[0]);
|
||||
}
|
||||
eventlog.f[eventlog.nf++] = x->f;
|
||||
x->f->logoff = eventlog.start + eventlog.nev;
|
||||
|
||||
qunlock(&eventlog.lk);
|
||||
qunlock(&eventlog.lk);
|
||||
}
|
||||
|
||||
void
|
||||
xfidlogclose(Xfid *x)
|
||||
{
|
||||
int i;
|
||||
void xfidlogclose(Xfid* x) {
|
||||
int i;
|
||||
|
||||
qlock(&eventlog.lk);
|
||||
for(i=0; i<eventlog.nf; i++) {
|
||||
if(eventlog.f[i] == x->f) {
|
||||
eventlog.f[i] = eventlog.f[--eventlog.nf];
|
||||
break;
|
||||
}
|
||||
}
|
||||
qunlock(&eventlog.lk);
|
||||
qlock(&eventlog.lk);
|
||||
for (i = 0; i < eventlog.nf; i++) {
|
||||
if (eventlog.f[i] == x->f) {
|
||||
eventlog.f[i] = eventlog.f[--eventlog.nf];
|
||||
break;
|
||||
}
|
||||
}
|
||||
qunlock(&eventlog.lk);
|
||||
}
|
||||
|
||||
void
|
||||
xfidlogread(Xfid *x)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
Fcall fc;
|
||||
void xfidlogread(Xfid* x) {
|
||||
char* p;
|
||||
int i;
|
||||
Fcall fc;
|
||||
|
||||
qlock(&eventlog.lk);
|
||||
if(eventlog.nread >= eventlog.mread) {
|
||||
eventlog.mread = eventlog.mread*2;
|
||||
if(eventlog.mread == 0)
|
||||
eventlog.mread = 8;
|
||||
eventlog.read = erealloc(eventlog.read, eventlog.mread*sizeof eventlog.read[0]);
|
||||
}
|
||||
eventlog.read[eventlog.nread++] = x;
|
||||
|
||||
if(eventlog.r.l == nil)
|
||||
eventlog.r.l = &eventlog.lk;
|
||||
x->flushed = FALSE;
|
||||
while(x->f->logoff >= eventlog.start+eventlog.nev && !x->flushed)
|
||||
rsleep(&eventlog.r);
|
||||
|
||||
for(i=0; i<eventlog.nread; i++) {
|
||||
if(eventlog.read[i] == x) {
|
||||
eventlog.read[i] = eventlog.read[--eventlog.nread];
|
||||
break;
|
||||
}
|
||||
}
|
||||
qlock(&eventlog.lk);
|
||||
if (eventlog.nread >= eventlog.mread) {
|
||||
eventlog.mread = eventlog.mread * 2;
|
||||
if (eventlog.mread == 0)
|
||||
eventlog.mread = 8;
|
||||
eventlog.read =
|
||||
erealloc(eventlog.read, eventlog.mread * sizeof eventlog.read[0]);
|
||||
}
|
||||
eventlog.read[eventlog.nread++] = x;
|
||||
|
||||
if(x->flushed) {
|
||||
qunlock(&eventlog.lk);
|
||||
return;
|
||||
}
|
||||
if (eventlog.r.l == nil)
|
||||
eventlog.r.l = &eventlog.lk;
|
||||
x->flushed = FALSE;
|
||||
while (x->f->logoff >= eventlog.start + eventlog.nev && !x->flushed)
|
||||
rsleep(&eventlog.r);
|
||||
|
||||
i = x->f->logoff - eventlog.start;
|
||||
p = estrdup(eventlog.ev[i]);
|
||||
x->f->logoff++;
|
||||
qunlock(&eventlog.lk);
|
||||
for (i = 0; i < eventlog.nread; i++) {
|
||||
if (eventlog.read[i] == x) {
|
||||
eventlog.read[i] = eventlog.read[--eventlog.nread];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fc.data = p;
|
||||
fc.count = strlen(p);
|
||||
respond(x, &fc, nil);
|
||||
free(p);
|
||||
if (x->flushed) {
|
||||
qunlock(&eventlog.lk);
|
||||
return;
|
||||
}
|
||||
|
||||
i = x->f->logoff - eventlog.start;
|
||||
p = estrdup(eventlog.ev[i]);
|
||||
x->f->logoff++;
|
||||
qunlock(&eventlog.lk);
|
||||
|
||||
fc.data = p;
|
||||
fc.count = strlen(p);
|
||||
respond(x, &fc, nil);
|
||||
free(p);
|
||||
}
|
||||
|
||||
void
|
||||
xfidlogflush(Xfid *x)
|
||||
{
|
||||
int i;
|
||||
Xfid *rx;
|
||||
void xfidlogflush(Xfid* x) {
|
||||
int i;
|
||||
Xfid* rx;
|
||||
|
||||
qlock(&eventlog.lk);
|
||||
for(i=0; i<eventlog.nread; i++) {
|
||||
rx = eventlog.read[i];
|
||||
if(rx->fcall.tag == x->fcall.oldtag) {
|
||||
rx->flushed = TRUE;
|
||||
rwakeupall(&eventlog.r);
|
||||
}
|
||||
}
|
||||
qunlock(&eventlog.lk);
|
||||
qlock(&eventlog.lk);
|
||||
for (i = 0; i < eventlog.nread; i++) {
|
||||
rx = eventlog.read[i];
|
||||
if (rx->fcall.tag == x->fcall.oldtag) {
|
||||
rx->flushed = TRUE;
|
||||
rwakeupall(&eventlog.r);
|
||||
}
|
||||
}
|
||||
qunlock(&eventlog.lk);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -153,47 +145,48 @@ xfidlogflush(Xfid *x)
|
|||
* op == "del" for deleted window
|
||||
* - called from winclose
|
||||
*/
|
||||
void
|
||||
xfidlog(Window *w, char *op)
|
||||
{
|
||||
int i, n;
|
||||
vlong min;
|
||||
File *f;
|
||||
char *name;
|
||||
void xfidlog(Window* w, char* op) {
|
||||
int i, n;
|
||||
vlong min;
|
||||
File* f;
|
||||
char* name;
|
||||
|
||||
qlock(&eventlog.lk);
|
||||
if(eventlog.nev >= eventlog.mev) {
|
||||
// Remove and free any entries that all readers have read.
|
||||
min = eventlog.start + eventlog.nev;
|
||||
for(i=0; i<eventlog.nf; i++) {
|
||||
if(min > eventlog.f[i]->logoff)
|
||||
min = eventlog.f[i]->logoff;
|
||||
}
|
||||
if(min > eventlog.start) {
|
||||
n = min - eventlog.start;
|
||||
for(i=0; i<n; i++)
|
||||
free(eventlog.ev[i]);
|
||||
eventlog.nev -= n;
|
||||
eventlog.start += n;
|
||||
memmove(eventlog.ev, eventlog.ev+n, eventlog.nev*sizeof eventlog.ev[0]);
|
||||
}
|
||||
|
||||
// Otherwise grow.
|
||||
if(eventlog.nev >= eventlog.mev) {
|
||||
eventlog.mev = eventlog.mev*2;
|
||||
if(eventlog.mev == 0)
|
||||
eventlog.mev = 8;
|
||||
eventlog.ev = erealloc(eventlog.ev, eventlog.mev*sizeof eventlog.ev[0]);
|
||||
}
|
||||
}
|
||||
f = w->body.file;
|
||||
name = runetobyte(f->name, f->nname);
|
||||
if(name == nil)
|
||||
name = estrdup("");
|
||||
eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name);
|
||||
free(name);
|
||||
if(eventlog.r.l == nil)
|
||||
eventlog.r.l = &eventlog.lk;
|
||||
rwakeupall(&eventlog.r);
|
||||
qunlock(&eventlog.lk);
|
||||
qlock(&eventlog.lk);
|
||||
if (eventlog.nev >= eventlog.mev) {
|
||||
// Remove and free any entries that all readers have read.
|
||||
min = eventlog.start + eventlog.nev;
|
||||
for (i = 0; i < eventlog.nf; i++) {
|
||||
if (min > eventlog.f[i]->logoff)
|
||||
min = eventlog.f[i]->logoff;
|
||||
}
|
||||
if (min > eventlog.start) {
|
||||
n = min - eventlog.start;
|
||||
for (i = 0; i < n; i++)
|
||||
free(eventlog.ev[i]);
|
||||
eventlog.nev -= n;
|
||||
eventlog.start += n;
|
||||
memmove(
|
||||
eventlog.ev,
|
||||
eventlog.ev + n,
|
||||
eventlog.nev * sizeof eventlog.ev[0]);
|
||||
}
|
||||
|
||||
// Otherwise grow.
|
||||
if (eventlog.nev >= eventlog.mev) {
|
||||
eventlog.mev = eventlog.mev * 2;
|
||||
if (eventlog.mev == 0)
|
||||
eventlog.mev = 8;
|
||||
eventlog.ev = erealloc(eventlog.ev, eventlog.mev * sizeof eventlog.ev[0]);
|
||||
}
|
||||
}
|
||||
f = w->body.file;
|
||||
name = runetobyte(f->name, f->nname);
|
||||
if (name == nil)
|
||||
name = estrdup("");
|
||||
eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name);
|
||||
free(name);
|
||||
if (eventlog.r.l == nil)
|
||||
eventlog.r.l = &eventlog.lk;
|
||||
rwakeupall(&eventlog.r);
|
||||
qunlock(&eventlog.lk);
|
||||
}
|
||||
|
|
112
mail/html.c
112
mail/html.c
|
@ -7,69 +7,65 @@
|
|||
#include <9pclient.h>
|
||||
#include "dat.h"
|
||||
|
||||
char*
|
||||
formathtml(char *body, int *np)
|
||||
{
|
||||
int i, j, p[2], q[2];
|
||||
Exec *e;
|
||||
char buf[1024];
|
||||
Channel *sync;
|
||||
char* formathtml(char* body, int* np) {
|
||||
int i, j, p[2], q[2];
|
||||
Exec* e;
|
||||
char buf[1024];
|
||||
Channel* sync;
|
||||
|
||||
e = emalloc(sizeof(struct Exec));
|
||||
if(pipe(p) < 0 || pipe(q) < 0)
|
||||
error("can't create pipe: %r");
|
||||
e = emalloc(sizeof(struct Exec));
|
||||
if (pipe(p) < 0 || pipe(q) < 0)
|
||||
error("can't create pipe: %r");
|
||||
|
||||
e->p[0] = p[0];
|
||||
e->p[1] = p[1];
|
||||
e->q[0] = q[0];
|
||||
e->q[1] = q[1];
|
||||
e->argv = emalloc(3*sizeof(char*));
|
||||
e->argv[0] = estrdup("htmlfmt");
|
||||
e->argv[1] = estrdup("-cutf-8");
|
||||
e->argv[2] = nil;
|
||||
e->prog = "htmlfmt";
|
||||
sync = chancreate(sizeof(int), 0);
|
||||
e->sync = sync;
|
||||
proccreate(execproc, e, EXECSTACK);
|
||||
recvul(sync);
|
||||
close(p[0]);
|
||||
close(q[1]);
|
||||
e->p[0] = p[0];
|
||||
e->p[1] = p[1];
|
||||
e->q[0] = q[0];
|
||||
e->q[1] = q[1];
|
||||
e->argv = emalloc(3 * sizeof(char*));
|
||||
e->argv[0] = estrdup("htmlfmt");
|
||||
e->argv[1] = estrdup("-cutf-8");
|
||||
e->argv[2] = nil;
|
||||
e->prog = "htmlfmt";
|
||||
sync = chancreate(sizeof(int), 0);
|
||||
e->sync = sync;
|
||||
proccreate(execproc, e, EXECSTACK);
|
||||
recvul(sync);
|
||||
close(p[0]);
|
||||
close(q[1]);
|
||||
|
||||
if((i=write(p[1], body, *np)) != *np){
|
||||
fprint(2, "Mail: warning: htmlfmt failed: wrote %d of %d: %r\n", i, *np);
|
||||
close(p[1]);
|
||||
close(q[0]);
|
||||
return body;
|
||||
}
|
||||
close(p[1]);
|
||||
if ((i = write(p[1], body, *np)) != *np) {
|
||||
fprint(2, "Mail: warning: htmlfmt failed: wrote %d of %d: %r\n", i, *np);
|
||||
close(p[1]);
|
||||
close(q[0]);
|
||||
return body;
|
||||
}
|
||||
close(p[1]);
|
||||
|
||||
free(body);
|
||||
body = nil;
|
||||
i = 0;
|
||||
for(;;){
|
||||
j = read(q[0], buf, sizeof buf);
|
||||
if(j <= 0)
|
||||
break;
|
||||
body = realloc(body, i+j+1);
|
||||
if(body == nil)
|
||||
error("realloc failed: %r");
|
||||
memmove(body+i, buf, j);
|
||||
i += j;
|
||||
body[i] = '\0';
|
||||
}
|
||||
close(q[0]);
|
||||
free(body);
|
||||
body = nil;
|
||||
i = 0;
|
||||
for (;;) {
|
||||
j = read(q[0], buf, sizeof buf);
|
||||
if (j <= 0)
|
||||
break;
|
||||
body = realloc(body, i + j + 1);
|
||||
if (body == nil)
|
||||
error("realloc failed: %r");
|
||||
memmove(body + i, buf, j);
|
||||
i += j;
|
||||
body[i] = '\0';
|
||||
}
|
||||
close(q[0]);
|
||||
|
||||
*np = i;
|
||||
return body;
|
||||
*np = i;
|
||||
return body;
|
||||
}
|
||||
|
||||
char*
|
||||
readbody(char *type, char *dir, int *np)
|
||||
{
|
||||
char *body;
|
||||
|
||||
body = readfile(dir, "body", np);
|
||||
if(body != nil && strcmp(type, "text/html") == 0)
|
||||
return formathtml(body, np);
|
||||
return body;
|
||||
char* readbody(char* type, char* dir, int* np) {
|
||||
char* body;
|
||||
|
||||
body = readfile(dir, "body", np);
|
||||
if (body != nil && strcmp(type, "text/html") == 0)
|
||||
return formathtml(body, np);
|
||||
return body;
|
||||
}
|
||||
|
|
BIN
mail/html.o
BIN
mail/html.o
Binary file not shown.
1122
mail/mail.c
1122
mail/mail.c
File diff suppressed because it is too large
Load diff
BIN
mail/mail.o
BIN
mail/mail.o
Binary file not shown.
2442
mail/mesg.c
2442
mail/mesg.c
File diff suppressed because it is too large
Load diff
BIN
mail/mesg.o
BIN
mail/mesg.o
Binary file not shown.
BIN
mail/o.Mail
BIN
mail/o.Mail
Binary file not shown.
1000
mail/reply.c
1000
mail/reply.c
File diff suppressed because it is too large
Load diff
BIN
mail/reply.o
BIN
mail/reply.o
Binary file not shown.
139
mail/util.c
139
mail/util.c
|
@ -6,102 +6,85 @@
|
|||
#include <9pclient.h>
|
||||
#include "dat.h"
|
||||
|
||||
void*
|
||||
emalloc(uint n)
|
||||
{
|
||||
void *p;
|
||||
void* emalloc(uint n) {
|
||||
void* p;
|
||||
|
||||
p = malloc(n);
|
||||
if(p == nil)
|
||||
error("can't malloc: %r");
|
||||
memset(p, 0, n);
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
return p;
|
||||
p = malloc(n);
|
||||
if (p == nil)
|
||||
error("can't malloc: %r");
|
||||
memset(p, 0, n);
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
return p;
|
||||
}
|
||||
|
||||
void*
|
||||
erealloc(void *p, uint n)
|
||||
{
|
||||
p = realloc(p, n);
|
||||
if(p == nil)
|
||||
error("can't realloc: %r");
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
return p;
|
||||
void* erealloc(void* p, uint n) {
|
||||
p = realloc(p, n);
|
||||
if (p == nil)
|
||||
error("can't realloc: %r");
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
return p;
|
||||
}
|
||||
|
||||
char*
|
||||
estrdup(char *s)
|
||||
{
|
||||
char *t;
|
||||
char* estrdup(char* s) {
|
||||
char* t;
|
||||
|
||||
t = emalloc(strlen(s)+1);
|
||||
strcpy(t, s);
|
||||
return t;
|
||||
t = emalloc(strlen(s) + 1);
|
||||
strcpy(t, s);
|
||||
return t;
|
||||
}
|
||||
|
||||
char*
|
||||
estrstrdup(char *s, char *t)
|
||||
{
|
||||
char *u;
|
||||
char* estrstrdup(char* s, char* t) {
|
||||
char* u;
|
||||
|
||||
u = emalloc(strlen(s)+strlen(t)+1);
|
||||
strcpy(u, s);
|
||||
strcat(u, t);
|
||||
return u;
|
||||
u = emalloc(strlen(s) + strlen(t) + 1);
|
||||
strcpy(u, s);
|
||||
strcat(u, t);
|
||||
return u;
|
||||
}
|
||||
|
||||
char*
|
||||
eappend(char *s, char *sep, char *t)
|
||||
{
|
||||
char *u;
|
||||
char* eappend(char* s, char* sep, char* t) {
|
||||
char* u;
|
||||
|
||||
if(t == nil)
|
||||
u = estrstrdup(s, sep);
|
||||
else{
|
||||
u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1);
|
||||
strcpy(u, s);
|
||||
strcat(u, sep);
|
||||
strcat(u, t);
|
||||
}
|
||||
free(s);
|
||||
return u;
|
||||
if (t == nil)
|
||||
u = estrstrdup(s, sep);
|
||||
else {
|
||||
u = emalloc(strlen(s) + strlen(sep) + strlen(t) + 1);
|
||||
strcpy(u, s);
|
||||
strcat(u, sep);
|
||||
strcat(u, t);
|
||||
}
|
||||
free(s);
|
||||
return u;
|
||||
}
|
||||
|
||||
char*
|
||||
egrow(char *s, char *sep, char *t)
|
||||
{
|
||||
s = eappend(s, sep, t);
|
||||
free(t);
|
||||
return s;
|
||||
char* egrow(char* s, char* sep, char* t) {
|
||||
s = eappend(s, sep, t);
|
||||
free(t);
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
error(char *fmt, ...)
|
||||
{
|
||||
Fmt f;
|
||||
char buf[64];
|
||||
va_list arg;
|
||||
void error(char* fmt, ...) {
|
||||
Fmt f;
|
||||
char buf[64];
|
||||
va_list arg;
|
||||
|
||||
fmtfdinit(&f, 2, buf, sizeof buf);
|
||||
fmtprint(&f, "Mail: ");
|
||||
va_start(arg, fmt);
|
||||
fmtvprint(&f, fmt, arg);
|
||||
va_end(arg);
|
||||
fmtprint(&f, "\n");
|
||||
fmtfdflush(&f);
|
||||
threadexitsall(fmt);
|
||||
fmtfdinit(&f, 2, buf, sizeof buf);
|
||||
fmtprint(&f, "Mail: ");
|
||||
va_start(arg, fmt);
|
||||
fmtvprint(&f, fmt, arg);
|
||||
va_end(arg);
|
||||
fmtprint(&f, "\n");
|
||||
fmtfdflush(&f);
|
||||
threadexitsall(fmt);
|
||||
}
|
||||
|
||||
void
|
||||
ctlprint(CFid *fd, char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list arg;
|
||||
void ctlprint(CFid* fd, char* fmt, ...) {
|
||||
int n;
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
n = fsvprint(fd, fmt, arg);
|
||||
va_end(arg);
|
||||
if(n <= 0)
|
||||
error("control file write error: %r");
|
||||
va_start(arg, fmt);
|
||||
n = fsvprint(fd, fmt, arg);
|
||||
va_end(arg);
|
||||
if (n <= 0)
|
||||
error("control file write error: %r");
|
||||
}
|
||||
|
||||
|
|
BIN
mail/util.o
BIN
mail/util.o
Binary file not shown.
583
mail/win.c
583
mail/win.c
|
@ -6,374 +6,325 @@
|
|||
#include <9pclient.h>
|
||||
#include "dat.h"
|
||||
|
||||
Window*
|
||||
newwindow(void)
|
||||
{
|
||||
char buf[12];
|
||||
Window *w;
|
||||
Window* newwindow(void) {
|
||||
char buf[12];
|
||||
Window* w;
|
||||
|
||||
w = emalloc(sizeof(Window));
|
||||
w->ctl = fsopen(acmefs, "new/ctl", ORDWR|OCEXEC);
|
||||
if(w->ctl == nil || fsread(w->ctl, buf, 12)!=12)
|
||||
error("can't open window ctl file: %r");
|
||||
w = emalloc(sizeof(Window));
|
||||
w->ctl = fsopen(acmefs, "new/ctl", ORDWR | OCEXEC);
|
||||
if (w->ctl == nil || fsread(w->ctl, buf, 12) != 12)
|
||||
error("can't open window ctl file: %r");
|
||||
|
||||
w->id = atoi(buf);
|
||||
w->event = winopenfile(w, "event");
|
||||
w->addr = nil; /* will be opened when needed */
|
||||
w->body = nil;
|
||||
w->data = nil;
|
||||
w->cevent = chancreate(sizeof(Event*), 0);
|
||||
w->ref = 1;
|
||||
return w;
|
||||
w->id = atoi(buf);
|
||||
w->event = winopenfile(w, "event");
|
||||
w->addr = nil; /* will be opened when needed */
|
||||
w->body = nil;
|
||||
w->data = nil;
|
||||
w->cevent = chancreate(sizeof(Event*), 0);
|
||||
w->ref = 1;
|
||||
return w;
|
||||
}
|
||||
|
||||
void
|
||||
winincref(Window *w)
|
||||
{
|
||||
qlock(&w->lk);
|
||||
++w->ref;
|
||||
qunlock(&w->lk);
|
||||
void winincref(Window* w) {
|
||||
qlock(&w->lk);
|
||||
++w->ref;
|
||||
qunlock(&w->lk);
|
||||
}
|
||||
|
||||
void
|
||||
windecref(Window *w)
|
||||
{
|
||||
qlock(&w->lk);
|
||||
if(--w->ref > 0){
|
||||
qunlock(&w->lk);
|
||||
return;
|
||||
}
|
||||
fsclose(w->event);
|
||||
chanfree(w->cevent);
|
||||
free(w);
|
||||
void windecref(Window* w) {
|
||||
qlock(&w->lk);
|
||||
if (--w->ref > 0) {
|
||||
qunlock(&w->lk);
|
||||
return;
|
||||
}
|
||||
fsclose(w->event);
|
||||
chanfree(w->cevent);
|
||||
free(w);
|
||||
}
|
||||
|
||||
void
|
||||
winsetdump(Window *w, char *dir, char *cmd)
|
||||
{
|
||||
if(dir != nil)
|
||||
ctlprint(w->ctl, "dumpdir %s\n", dir);
|
||||
if(cmd != nil)
|
||||
ctlprint(w->ctl, "dump %s\n", cmd);
|
||||
void winsetdump(Window* w, char* dir, char* cmd) {
|
||||
if (dir != nil)
|
||||
ctlprint(w->ctl, "dumpdir %s\n", dir);
|
||||
if (cmd != nil)
|
||||
ctlprint(w->ctl, "dump %s\n", cmd);
|
||||
}
|
||||
|
||||
void
|
||||
wineventproc(void *v)
|
||||
{
|
||||
Window *w;
|
||||
int i;
|
||||
void wineventproc(void* v) {
|
||||
Window* w;
|
||||
int i;
|
||||
|
||||
w = v;
|
||||
for(i=0; ; i++){
|
||||
if(i >= NEVENT)
|
||||
i = 0;
|
||||
wingetevent(w, &w->e[i]);
|
||||
sendp(w->cevent, &w->e[i]);
|
||||
}
|
||||
w = v;
|
||||
for (i = 0;; i++) {
|
||||
if (i >= NEVENT)
|
||||
i = 0;
|
||||
wingetevent(w, &w->e[i]);
|
||||
sendp(w->cevent, &w->e[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static CFid*
|
||||
winopenfile1(Window *w, char *f, int m)
|
||||
{
|
||||
char buf[64];
|
||||
CFid* fd;
|
||||
static CFid* winopenfile1(Window* w, char* f, int m) {
|
||||
char buf[64];
|
||||
CFid* fd;
|
||||
|
||||
sprint(buf, "%d/%s", w->id, f);
|
||||
fd = fsopen(acmefs, buf, m|OCEXEC);
|
||||
if(fd == nil)
|
||||
error("can't open window file %s: %r", f);
|
||||
return fd;
|
||||
sprint(buf, "%d/%s", w->id, f);
|
||||
fd = fsopen(acmefs, buf, m | OCEXEC);
|
||||
if (fd == nil)
|
||||
error("can't open window file %s: %r", f);
|
||||
return fd;
|
||||
}
|
||||
|
||||
CFid*
|
||||
winopenfile(Window *w, char *f)
|
||||
{
|
||||
return winopenfile1(w, f, ORDWR);
|
||||
CFid* winopenfile(Window* w, char* f) { return winopenfile1(w, f, ORDWR); }
|
||||
|
||||
void wintagwrite(Window* w, char* s, int n) {
|
||||
CFid* fid;
|
||||
|
||||
fid = winopenfile(w, "tag");
|
||||
if (fswrite(fid, s, n) != n)
|
||||
error("tag write: %r");
|
||||
fsclose(fid);
|
||||
}
|
||||
|
||||
void
|
||||
wintagwrite(Window *w, char *s, int n)
|
||||
{
|
||||
CFid* fid;
|
||||
void winname(Window* w, char* s) {
|
||||
int len;
|
||||
char *ns, *sp;
|
||||
Rune r = L'␣'; /* visible space */
|
||||
|
||||
fid = winopenfile(w, "tag");
|
||||
if(fswrite(fid, s, n) != n)
|
||||
error("tag write: %r");
|
||||
fsclose(fid);
|
||||
len = 0;
|
||||
ns = emalloc(strlen(s) * runelen(r) + 1);
|
||||
for (sp = s; *sp != '\0'; sp++, len++) {
|
||||
if (isspace(*sp)) {
|
||||
len += runetochar(ns + len, &r) - 1;
|
||||
continue;
|
||||
}
|
||||
*(ns + len) = *sp;
|
||||
}
|
||||
ctlprint(w->ctl, "name %s\n", ns);
|
||||
free(ns);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
winname(Window *w, char *s)
|
||||
{
|
||||
int len;
|
||||
char *ns, *sp;
|
||||
Rune r = L'␣'; /* visible space */
|
||||
void winopenbody(Window* w, int mode) {
|
||||
char buf[256];
|
||||
CFid* fid;
|
||||
|
||||
len = 0;
|
||||
ns = emalloc(strlen(s)*runelen(r) + 1);
|
||||
for(sp = s; *sp != '\0'; sp++, len++){
|
||||
if(isspace(*sp)){
|
||||
len += runetochar(ns+len, &r)-1;
|
||||
continue;
|
||||
}
|
||||
*(ns+len) = *sp;
|
||||
}
|
||||
ctlprint(w->ctl, "name %s\n", ns);
|
||||
free(ns);
|
||||
return;
|
||||
sprint(buf, "%d/body", w->id);
|
||||
fid = fsopen(acmefs, buf, mode | OCEXEC);
|
||||
w->body = fid;
|
||||
if (w->body == nil)
|
||||
error("can't open window body file: %r");
|
||||
}
|
||||
|
||||
void
|
||||
winopenbody(Window *w, int mode)
|
||||
{
|
||||
char buf[256];
|
||||
CFid* fid;
|
||||
|
||||
sprint(buf, "%d/body", w->id);
|
||||
fid = fsopen(acmefs, buf, mode|OCEXEC);
|
||||
w->body = fid;
|
||||
if(w->body == nil)
|
||||
error("can't open window body file: %r");
|
||||
void winclosebody(Window* w) {
|
||||
if (w->body != nil) {
|
||||
fsclose(w->body);
|
||||
w->body = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
winclosebody(Window *w)
|
||||
{
|
||||
if(w->body != nil){
|
||||
fsclose(w->body);
|
||||
w->body = nil;
|
||||
}
|
||||
void winwritebody(Window* w, char* s, int n) {
|
||||
if (w->body == nil)
|
||||
winopenbody(w, OWRITE);
|
||||
if (fswrite(w->body, s, n) != n)
|
||||
error("write error to window: %r");
|
||||
}
|
||||
|
||||
void
|
||||
winwritebody(Window *w, char *s, int n)
|
||||
{
|
||||
if(w->body == nil)
|
||||
winopenbody(w, OWRITE);
|
||||
if(fswrite(w->body, s, n) != n)
|
||||
error("write error to window: %r");
|
||||
int wingetec(Window* w) {
|
||||
if (w->nbuf == 0) {
|
||||
w->nbuf = fsread(w->event, w->buf, sizeof w->buf);
|
||||
if (w->nbuf <= 0) {
|
||||
/* probably because window has exited, and only called by wineventproc, so
|
||||
* just shut down */
|
||||
windecref(w);
|
||||
threadexits(nil);
|
||||
}
|
||||
w->bufp = w->buf;
|
||||
}
|
||||
w->nbuf--;
|
||||
return *w->bufp++;
|
||||
}
|
||||
|
||||
int
|
||||
wingetec(Window *w)
|
||||
{
|
||||
if(w->nbuf == 0){
|
||||
w->nbuf = fsread(w->event, w->buf, sizeof w->buf);
|
||||
if(w->nbuf <= 0){
|
||||
/* probably because window has exited, and only called by wineventproc, so just shut down */
|
||||
windecref(w);
|
||||
threadexits(nil);
|
||||
}
|
||||
w->bufp = w->buf;
|
||||
}
|
||||
w->nbuf--;
|
||||
return *w->bufp++;
|
||||
int wingeten(Window* w) {
|
||||
int n, c;
|
||||
|
||||
n = 0;
|
||||
while ('0' <= (c = wingetec(w)) && c <= '9')
|
||||
n = n * 10 + (c - '0');
|
||||
if (c != ' ')
|
||||
error("event number syntax");
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
wingeten(Window *w)
|
||||
{
|
||||
int n, c;
|
||||
int wingeter(Window* w, char* buf, int* nb) {
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
while('0'<=(c=wingetec(w)) && c<='9')
|
||||
n = n*10+(c-'0');
|
||||
if(c != ' ')
|
||||
error("event number syntax");
|
||||
return n;
|
||||
r = wingetec(w);
|
||||
buf[0] = r;
|
||||
n = 1;
|
||||
if (r >= Runeself) {
|
||||
while (!fullrune(buf, n))
|
||||
buf[n++] = wingetec(w);
|
||||
chartorune(&r, buf);
|
||||
}
|
||||
*nb = n;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
wingeter(Window *w, char *buf, int *nb)
|
||||
{
|
||||
Rune r;
|
||||
int n;
|
||||
void wingetevent(Window* w, Event* e) {
|
||||
int i, nb;
|
||||
|
||||
r = wingetec(w);
|
||||
buf[0] = r;
|
||||
n = 1;
|
||||
if(r >= Runeself) {
|
||||
while(!fullrune(buf, n))
|
||||
buf[n++] = wingetec(w);
|
||||
chartorune(&r, buf);
|
||||
}
|
||||
*nb = n;
|
||||
return r;
|
||||
e->c1 = wingetec(w);
|
||||
e->c2 = wingetec(w);
|
||||
e->q0 = wingeten(w);
|
||||
e->q1 = wingeten(w);
|
||||
e->flag = wingeten(w);
|
||||
e->nr = wingeten(w);
|
||||
if (e->nr > EVENTSIZE)
|
||||
error("event string too long");
|
||||
e->nb = 0;
|
||||
for (i = 0; i < e->nr; i++) {
|
||||
e->r[i] = wingeter(w, e->b + e->nb, &nb);
|
||||
e->nb += nb;
|
||||
}
|
||||
e->r[e->nr] = 0;
|
||||
e->b[e->nb] = 0;
|
||||
if (wingetec(w) != '\n')
|
||||
error("event syntax error");
|
||||
}
|
||||
|
||||
void
|
||||
wingetevent(Window *w, Event *e)
|
||||
{
|
||||
int i, nb;
|
||||
|
||||
e->c1 = wingetec(w);
|
||||
e->c2 = wingetec(w);
|
||||
e->q0 = wingeten(w);
|
||||
e->q1 = wingeten(w);
|
||||
e->flag = wingeten(w);
|
||||
e->nr = wingeten(w);
|
||||
if(e->nr > EVENTSIZE)
|
||||
error("event string too long");
|
||||
e->nb = 0;
|
||||
for(i=0; i<e->nr; i++){
|
||||
e->r[i] = wingeter(w, e->b+e->nb, &nb);
|
||||
e->nb += nb;
|
||||
}
|
||||
e->r[e->nr] = 0;
|
||||
e->b[e->nb] = 0;
|
||||
if(wingetec(w) != '\n')
|
||||
error("event syntax error");
|
||||
void winwriteevent(Window* w, Event* e) {
|
||||
fsprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
|
||||
}
|
||||
|
||||
void
|
||||
winwriteevent(Window *w, Event *e)
|
||||
{
|
||||
fsprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
|
||||
void winread(Window* w, uint q0, uint q1, char* data) {
|
||||
int m, n, nr;
|
||||
char buf[256];
|
||||
|
||||
if (w->addr == nil)
|
||||
w->addr = winopenfile(w, "addr");
|
||||
if (w->data == nil)
|
||||
w->data = winopenfile(w, "data");
|
||||
m = q0;
|
||||
while (m < q1) {
|
||||
n = sprint(buf, "#%d", m);
|
||||
if (fswrite(w->addr, buf, n) != n)
|
||||
error("error writing addr: %r");
|
||||
n = fsread(w->data, buf, sizeof buf);
|
||||
if (n <= 0)
|
||||
error("reading data: %r");
|
||||
nr = utfnlen(buf, n);
|
||||
while (m + nr > q1) {
|
||||
do
|
||||
;
|
||||
while (n > 0 && (buf[--n] & 0xC0) == 0x80);
|
||||
--nr;
|
||||
}
|
||||
if (n == 0)
|
||||
break;
|
||||
memmove(data, buf, n);
|
||||
data += n;
|
||||
*data = 0;
|
||||
m += nr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
winread(Window *w, uint q0, uint q1, char *data)
|
||||
{
|
||||
int m, n, nr;
|
||||
char buf[256];
|
||||
|
||||
if(w->addr == nil)
|
||||
w->addr = winopenfile(w, "addr");
|
||||
if(w->data == nil)
|
||||
w->data = winopenfile(w, "data");
|
||||
m = q0;
|
||||
while(m < q1){
|
||||
n = sprint(buf, "#%d", m);
|
||||
if(fswrite(w->addr, buf, n) != n)
|
||||
error("error writing addr: %r");
|
||||
n = fsread(w->data, buf, sizeof buf);
|
||||
if(n <= 0)
|
||||
error("reading data: %r");
|
||||
nr = utfnlen(buf, n);
|
||||
while(m+nr >q1){
|
||||
do; while(n>0 && (buf[--n]&0xC0)==0x80);
|
||||
--nr;
|
||||
}
|
||||
if(n == 0)
|
||||
break;
|
||||
memmove(data, buf, n);
|
||||
data += n;
|
||||
*data = 0;
|
||||
m += nr;
|
||||
}
|
||||
void windormant(Window* w) {
|
||||
if (w->addr != nil) {
|
||||
fsclose(w->addr);
|
||||
w->addr = nil;
|
||||
}
|
||||
if (w->body != nil) {
|
||||
fsclose(w->body);
|
||||
w->body = nil;
|
||||
}
|
||||
if (w->data != nil) {
|
||||
fsclose(w->data);
|
||||
w->data = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
windormant(Window *w)
|
||||
{
|
||||
if(w->addr != nil){
|
||||
fsclose(w->addr);
|
||||
w->addr = nil;
|
||||
}
|
||||
if(w->body != nil){
|
||||
fsclose(w->body);
|
||||
w->body = nil;
|
||||
}
|
||||
if(w->data != nil){
|
||||
fsclose(w->data);
|
||||
w->data = nil;
|
||||
}
|
||||
int windel(Window* w, int sure) {
|
||||
if (sure)
|
||||
fswrite(w->ctl, "delete\n", 7);
|
||||
else if (fswrite(w->ctl, "del\n", 4) != 4)
|
||||
return 0;
|
||||
/* event proc will die due to read error from event file */
|
||||
windormant(w);
|
||||
fsclose(w->ctl);
|
||||
w->ctl = nil;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void winclean(Window* w) { ctlprint(w->ctl, "clean\n"); }
|
||||
|
||||
int
|
||||
windel(Window *w, int sure)
|
||||
{
|
||||
if(sure)
|
||||
fswrite(w->ctl, "delete\n", 7);
|
||||
else if(fswrite(w->ctl, "del\n", 4) != 4)
|
||||
return 0;
|
||||
/* event proc will die due to read error from event file */
|
||||
windormant(w);
|
||||
fsclose(w->ctl);
|
||||
w->ctl = nil;
|
||||
return 1;
|
||||
int winsetaddr(Window* w, char* addr, int errok) {
|
||||
if (w->addr == nil)
|
||||
w->addr = winopenfile(w, "addr");
|
||||
if (fswrite(w->addr, addr, strlen(addr)) < 0) {
|
||||
if (!errok)
|
||||
error("error writing addr(%s): %r", addr);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
winclean(Window *w)
|
||||
{
|
||||
ctlprint(w->ctl, "clean\n");
|
||||
int winselect(Window* w, char* addr, int errok) {
|
||||
if (winsetaddr(w, addr, errok)) {
|
||||
ctlprint(w->ctl, "dot=addr\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
winsetaddr(Window *w, char *addr, int errok)
|
||||
char* winreadbody(
|
||||
Window* w,
|
||||
int* np) /* can't use readfile because acme doesn't report the length */
|
||||
{
|
||||
if(w->addr == nil)
|
||||
w->addr = winopenfile(w, "addr");
|
||||
if(fswrite(w->addr, addr, strlen(addr)) < 0){
|
||||
if(!errok)
|
||||
error("error writing addr(%s): %r", addr);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
char* s;
|
||||
int m, na, n;
|
||||
|
||||
if (w->body != nil)
|
||||
winclosebody(w);
|
||||
winopenbody(w, OREAD);
|
||||
s = nil;
|
||||
na = 0;
|
||||
n = 0;
|
||||
for (;;) {
|
||||
if (na < n + 512) {
|
||||
na += 1024;
|
||||
s = realloc(s, na + 1);
|
||||
}
|
||||
m = fsread(w->body, s + n, na - n);
|
||||
if (m <= 0)
|
||||
break;
|
||||
n += m;
|
||||
}
|
||||
s[n] = 0;
|
||||
winclosebody(w);
|
||||
*np = n;
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
winselect(Window *w, char *addr, int errok)
|
||||
{
|
||||
if(winsetaddr(w, addr, errok)){
|
||||
ctlprint(w->ctl, "dot=addr\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char*
|
||||
winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */
|
||||
{
|
||||
char *s;
|
||||
int m, na, n;
|
||||
|
||||
if(w->body != nil)
|
||||
winclosebody(w);
|
||||
winopenbody(w, OREAD);
|
||||
s = nil;
|
||||
na = 0;
|
||||
n = 0;
|
||||
for(;;){
|
||||
if(na < n+512){
|
||||
na += 1024;
|
||||
s = realloc(s, na+1);
|
||||
}
|
||||
m = fsread(w->body, s+n, na-n);
|
||||
if(m <= 0)
|
||||
break;
|
||||
n += m;
|
||||
}
|
||||
s[n] = 0;
|
||||
winclosebody(w);
|
||||
*np = n;
|
||||
return s;
|
||||
}
|
||||
|
||||
char*
|
||||
winselection(Window *w)
|
||||
{
|
||||
int m, n;
|
||||
char *buf;
|
||||
char tmp[256];
|
||||
CFid* fid;
|
||||
|
||||
fid = winopenfile1(w, "rdsel", OREAD);
|
||||
if(fid == nil)
|
||||
error("can't open rdsel: %r");
|
||||
n = 0;
|
||||
buf = nil;
|
||||
for(;;){
|
||||
m = fsread(fid, tmp, sizeof tmp);
|
||||
if(m <= 0)
|
||||
break;
|
||||
buf = erealloc(buf, n+m+1);
|
||||
memmove(buf+n, tmp, m);
|
||||
n += m;
|
||||
buf[n] = '\0';
|
||||
}
|
||||
fsclose(fid);
|
||||
return buf;
|
||||
char* winselection(Window* w) {
|
||||
int m, n;
|
||||
char* buf;
|
||||
char tmp[256];
|
||||
CFid* fid;
|
||||
|
||||
fid = winopenfile1(w, "rdsel", OREAD);
|
||||
if (fid == nil)
|
||||
error("can't open rdsel: %r");
|
||||
n = 0;
|
||||
buf = nil;
|
||||
for (;;) {
|
||||
m = fsread(fid, tmp, sizeof tmp);
|
||||
if (m <= 0)
|
||||
break;
|
||||
buf = erealloc(buf, n + m + 1);
|
||||
memmove(buf + n, tmp, m);
|
||||
n += m;
|
||||
buf[n] = '\0';
|
||||
}
|
||||
fsclose(fid);
|
||||
return buf;
|
||||
}
|
||||
|
|
BIN
mail/win.o
BIN
mail/win.o
Binary file not shown.
256
scrl.c
256
scrl.c
|
@ -12,148 +12,142 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static Image *scrtmp;
|
||||
static Image* scrtmp;
|
||||
|
||||
static
|
||||
Rectangle
|
||||
scrpos(Rectangle r, uint p0, uint p1, uint tot)
|
||||
{
|
||||
Rectangle q;
|
||||
int h;
|
||||
static Rectangle scrpos(Rectangle r, uint p0, uint p1, uint tot) {
|
||||
Rectangle q;
|
||||
int h;
|
||||
|
||||
q = r;
|
||||
h = q.max.y-q.min.y;
|
||||
if(tot == 0)
|
||||
return q;
|
||||
if(tot > 1024*1024){
|
||||
tot>>=10;
|
||||
p0>>=10;
|
||||
p1>>=10;
|
||||
}
|
||||
if(p0 > 0)
|
||||
q.min.y += h*p0/tot;
|
||||
if(p1 < tot)
|
||||
q.max.y -= h*(tot-p1)/tot;
|
||||
if(q.max.y < q.min.y+2){
|
||||
if(q.min.y+2 <= r.max.y)
|
||||
q.max.y = q.min.y+2;
|
||||
else
|
||||
q.min.y = q.max.y-2;
|
||||
}
|
||||
return q;
|
||||
q = r;
|
||||
h = q.max.y - q.min.y;
|
||||
if (tot == 0)
|
||||
return q;
|
||||
if (tot > 1024 * 1024) {
|
||||
tot >>= 10;
|
||||
p0 >>= 10;
|
||||
p1 >>= 10;
|
||||
}
|
||||
if (p0 > 0)
|
||||
q.min.y += h * p0 / tot;
|
||||
if (p1 < tot)
|
||||
q.max.y -= h * (tot - p1) / tot;
|
||||
if (q.max.y < q.min.y + 2) {
|
||||
if (q.min.y + 2 <= r.max.y)
|
||||
q.max.y = q.min.y + 2;
|
||||
else
|
||||
q.min.y = q.max.y - 2;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
scrlresize(void)
|
||||
{
|
||||
freeimage(scrtmp);
|
||||
scrtmp = allocimage(display, Rect(0, 0, 32, screen->r.max.y), screen->chan, 0, DNofill);
|
||||
if(scrtmp == nil)
|
||||
error("scroll alloc");
|
||||
void scrlresize(void) {
|
||||
freeimage(scrtmp);
|
||||
scrtmp = allocimage(
|
||||
display,
|
||||
Rect(0, 0, 32, screen->r.max.y),
|
||||
screen->chan,
|
||||
0,
|
||||
DNofill);
|
||||
if (scrtmp == nil)
|
||||
error("scroll alloc");
|
||||
}
|
||||
|
||||
void
|
||||
textscrdraw(Text *t)
|
||||
{
|
||||
Rectangle r, r1, r2;
|
||||
Image *b;
|
||||
void textscrdraw(Text* t) {
|
||||
Rectangle r, r1, r2;
|
||||
Image* b;
|
||||
|
||||
if(t->w==nil || t!=&t->w->body)
|
||||
return;
|
||||
if(scrtmp == nil)
|
||||
scrlresize();
|
||||
r = t->scrollr;
|
||||
b = scrtmp;
|
||||
r1 = r;
|
||||
r1.min.x = 0;
|
||||
r1.max.x = Dx(r);
|
||||
r2 = scrpos(r1, t->org, t->org+t->fr.nchars, t->file->b.nc);
|
||||
if(!eqrect(r2, t->lastsr)){
|
||||
t->lastsr = r2;
|
||||
draw(b, r1, t->fr.cols[BORD], nil, ZP);
|
||||
draw(b, r2, t->fr.cols[BACK], nil, ZP);
|
||||
r2.min.x = r2.max.x-1;
|
||||
draw(b, r2, t->fr.cols[BORD], nil, ZP);
|
||||
draw(t->fr.b, r, b, nil, Pt(0, r1.min.y));
|
||||
/*flushimage(display, 1); // BUG? */
|
||||
}
|
||||
if (t->w == nil || t != &t->w->body)
|
||||
return;
|
||||
if (scrtmp == nil)
|
||||
scrlresize();
|
||||
r = t->scrollr;
|
||||
b = scrtmp;
|
||||
r1 = r;
|
||||
r1.min.x = 0;
|
||||
r1.max.x = Dx(r);
|
||||
r2 = scrpos(r1, t->org, t->org + t->fr.nchars, t->file->b.nc);
|
||||
if (!eqrect(r2, t->lastsr)) {
|
||||
t->lastsr = r2;
|
||||
draw(b, r1, t->fr.cols[BORD], nil, ZP);
|
||||
draw(b, r2, t->fr.cols[BACK], nil, ZP);
|
||||
r2.min.x = r2.max.x - 1;
|
||||
draw(b, r2, t->fr.cols[BORD], nil, ZP);
|
||||
draw(t->fr.b, r, b, nil, Pt(0, r1.min.y));
|
||||
/*flushimage(display, 1); // BUG? */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scrsleep(uint dt)
|
||||
{
|
||||
Timer *timer;
|
||||
static Alt alts[3];
|
||||
void scrsleep(uint dt) {
|
||||
Timer* timer;
|
||||
static Alt alts[3];
|
||||
|
||||
timer = timerstart(dt);
|
||||
alts[0].c = timer->c;
|
||||
alts[0].v = nil;
|
||||
alts[0].op = CHANRCV;
|
||||
alts[1].c = mousectl->c;
|
||||
alts[1].v = &mousectl->m;
|
||||
alts[1].op = CHANRCV;
|
||||
alts[2].op = CHANEND;
|
||||
for(;;)
|
||||
switch(alt(alts)){
|
||||
case 0:
|
||||
timerstop(timer);
|
||||
return;
|
||||
case 1:
|
||||
timercancel(timer);
|
||||
return;
|
||||
}
|
||||
timer = timerstart(dt);
|
||||
alts[0].c = timer->c;
|
||||
alts[0].v = nil;
|
||||
alts[0].op = CHANRCV;
|
||||
alts[1].c = mousectl->c;
|
||||
alts[1].v = &mousectl->m;
|
||||
alts[1].op = CHANRCV;
|
||||
alts[2].op = CHANEND;
|
||||
for (;;)
|
||||
switch (alt(alts)) {
|
||||
case 0:
|
||||
timerstop(timer);
|
||||
return;
|
||||
case 1:
|
||||
timercancel(timer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
textscroll(Text *t, int but)
|
||||
{
|
||||
uint p0, oldp0;
|
||||
Rectangle s;
|
||||
int x, y, my, h, first;
|
||||
void textscroll(Text* t, int but) {
|
||||
uint p0, oldp0;
|
||||
Rectangle s;
|
||||
int x, y, my, h, first;
|
||||
|
||||
s = insetrect(t->scrollr, 1);
|
||||
h = s.max.y-s.min.y;
|
||||
x = (s.min.x+s.max.x)/2;
|
||||
oldp0 = ~0;
|
||||
first = TRUE;
|
||||
do{
|
||||
flushimage(display, 1);
|
||||
my = mouse->xy.y;
|
||||
if(my < s.min.y)
|
||||
my = s.min.y;
|
||||
if(my >= s.max.y)
|
||||
my = s.max.y;
|
||||
if(!eqpt(mouse->xy, Pt(x, my))){
|
||||
moveto(mousectl, Pt(x, my));
|
||||
readmouse(mousectl); /* absorb event generated by moveto() */
|
||||
}
|
||||
if(but == 2){
|
||||
y = my;
|
||||
p0 = (vlong)t->file->b.nc*(y-s.min.y)/h;
|
||||
if(p0 >= t->q1)
|
||||
p0 = textbacknl(t, p0, 2);
|
||||
if(oldp0 != p0)
|
||||
textsetorigin(t, p0, FALSE);
|
||||
oldp0 = p0;
|
||||
readmouse(mousectl);
|
||||
continue;
|
||||
}
|
||||
if(but == 1)
|
||||
p0 = textbacknl(t, t->org, (my-s.min.y)/t->fr.font->height);
|
||||
else
|
||||
p0 = t->org+frcharofpt(&t->fr, Pt(s.max.x, my));
|
||||
if(oldp0 != p0)
|
||||
textsetorigin(t, p0, TRUE);
|
||||
oldp0 = p0;
|
||||
/* debounce */
|
||||
if(first){
|
||||
flushimage(display, 1);
|
||||
sleep(200);
|
||||
nbrecv(mousectl->c, &mousectl->m);
|
||||
first = FALSE;
|
||||
}
|
||||
scrsleep(80);
|
||||
}while(mouse->buttons & (1<<(but-1)));
|
||||
while(mouse->buttons)
|
||||
readmouse(mousectl);
|
||||
s = insetrect(t->scrollr, 1);
|
||||
h = s.max.y - s.min.y;
|
||||
x = (s.min.x + s.max.x) / 2;
|
||||
oldp0 = ~0;
|
||||
first = TRUE;
|
||||
do {
|
||||
flushimage(display, 1);
|
||||
my = mouse->xy.y;
|
||||
if (my < s.min.y)
|
||||
my = s.min.y;
|
||||
if (my >= s.max.y)
|
||||
my = s.max.y;
|
||||
if (!eqpt(mouse->xy, Pt(x, my))) {
|
||||
moveto(mousectl, Pt(x, my));
|
||||
readmouse(mousectl); /* absorb event generated by moveto() */
|
||||
}
|
||||
if (but == 2) {
|
||||
y = my;
|
||||
p0 = (vlong)t->file->b.nc * (y - s.min.y) / h;
|
||||
if (p0 >= t->q1)
|
||||
p0 = textbacknl(t, p0, 2);
|
||||
if (oldp0 != p0)
|
||||
textsetorigin(t, p0, FALSE);
|
||||
oldp0 = p0;
|
||||
readmouse(mousectl);
|
||||
continue;
|
||||
}
|
||||
if (but == 1)
|
||||
p0 = textbacknl(t, t->org, (my - s.min.y) / t->fr.font->height);
|
||||
else
|
||||
p0 = t->org + frcharofpt(&t->fr, Pt(s.max.x, my));
|
||||
if (oldp0 != p0)
|
||||
textsetorigin(t, p0, TRUE);
|
||||
oldp0 = p0;
|
||||
/* debounce */
|
||||
if (first) {
|
||||
flushimage(display, 1);
|
||||
sleep(200);
|
||||
nbrecv(mousectl->c, &mousectl->m);
|
||||
first = FALSE;
|
||||
}
|
||||
scrsleep(80);
|
||||
} while (mouse->buttons & (1 << (but - 1)));
|
||||
while (mouse->buttons)
|
||||
readmouse(mousectl);
|
||||
}
|
||||
|
|
185
time.c
185
time.c
|
@ -12,113 +12,96 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static Channel* ctimer; /* chan(Timer*)[100] */
|
||||
static Timer *timer;
|
||||
static Channel* ctimer; /* chan(Timer*)[100] */
|
||||
static Timer* timer;
|
||||
|
||||
static
|
||||
uint
|
||||
msec(void)
|
||||
{
|
||||
return nsec()/1000000;
|
||||
static uint msec(void) { return nsec() / 1000000; }
|
||||
|
||||
void timerstop(Timer* t) {
|
||||
t->next = timer;
|
||||
timer = t;
|
||||
}
|
||||
|
||||
void
|
||||
timerstop(Timer *t)
|
||||
{
|
||||
t->next = timer;
|
||||
timer = t;
|
||||
void timercancel(Timer* t) { t->cancel = TRUE; }
|
||||
|
||||
static void timerproc(void* v) {
|
||||
int i, nt, na, dt, del;
|
||||
Timer **t, *x;
|
||||
uint old, new;
|
||||
|
||||
USED(v);
|
||||
threadsetname("timerproc");
|
||||
rfork(RFFDG);
|
||||
t = nil;
|
||||
na = 0;
|
||||
nt = 0;
|
||||
old = msec();
|
||||
for (;;) {
|
||||
sleep(10); /* longer sleeps here delay recv on ctimer, but 10ms should not
|
||||
be noticeable */
|
||||
new = msec();
|
||||
dt = new - old;
|
||||
old = new;
|
||||
if (dt < 0) /* timer wrapped; go around, losing a tick */
|
||||
continue;
|
||||
for (i = 0; i < nt; i++) {
|
||||
x = t[i];
|
||||
x->dt -= dt;
|
||||
del = FALSE;
|
||||
if (x->cancel) {
|
||||
timerstop(x);
|
||||
del = TRUE;
|
||||
} else if (x->dt <= 0) {
|
||||
/*
|
||||
* avoid possible deadlock if client is
|
||||
* now sending on ctimer
|
||||
*/
|
||||
if (nbsendul(x->c, 0) > 0)
|
||||
del = TRUE;
|
||||
}
|
||||
if (del) {
|
||||
memmove(&t[i], &t[i + 1], (nt - i - 1) * sizeof t[0]);
|
||||
--nt;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
if (nt == 0) {
|
||||
x = recvp(ctimer);
|
||||
gotit:
|
||||
if (nt == na) {
|
||||
na += 10;
|
||||
t = realloc(t, na * sizeof(Timer*));
|
||||
if (t == nil)
|
||||
error("timer realloc failed");
|
||||
}
|
||||
t[nt++] = x;
|
||||
old = msec();
|
||||
}
|
||||
if (nbrecv(ctimer, &x) > 0)
|
||||
goto gotit;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
timercancel(Timer *t)
|
||||
{
|
||||
t->cancel = TRUE;
|
||||
void timerinit(void) {
|
||||
ctimer = chancreate(sizeof(Timer*), 100);
|
||||
chansetname(ctimer, "ctimer");
|
||||
proccreate(timerproc, nil, STACK);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
timerproc(void *v)
|
||||
{
|
||||
int i, nt, na, dt, del;
|
||||
Timer **t, *x;
|
||||
uint old, new;
|
||||
Timer* timerstart(int dt) {
|
||||
Timer* t;
|
||||
|
||||
USED(v);
|
||||
threadsetname("timerproc");
|
||||
rfork(RFFDG);
|
||||
t = nil;
|
||||
na = 0;
|
||||
nt = 0;
|
||||
old = msec();
|
||||
for(;;){
|
||||
sleep(10); /* longer sleeps here delay recv on ctimer, but 10ms should not be noticeable */
|
||||
new = msec();
|
||||
dt = new-old;
|
||||
old = new;
|
||||
if(dt < 0) /* timer wrapped; go around, losing a tick */
|
||||
continue;
|
||||
for(i=0; i<nt; i++){
|
||||
x = t[i];
|
||||
x->dt -= dt;
|
||||
del = FALSE;
|
||||
if(x->cancel){
|
||||
timerstop(x);
|
||||
del = TRUE;
|
||||
}else if(x->dt <= 0){
|
||||
/*
|
||||
* avoid possible deadlock if client is
|
||||
* now sending on ctimer
|
||||
*/
|
||||
if(nbsendul(x->c, 0) > 0)
|
||||
del = TRUE;
|
||||
}
|
||||
if(del){
|
||||
memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]);
|
||||
--nt;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
if(nt == 0){
|
||||
x = recvp(ctimer);
|
||||
gotit:
|
||||
if(nt == na){
|
||||
na += 10;
|
||||
t = realloc(t, na*sizeof(Timer*));
|
||||
if(t == nil)
|
||||
error("timer realloc failed");
|
||||
}
|
||||
t[nt++] = x;
|
||||
old = msec();
|
||||
}
|
||||
if(nbrecv(ctimer, &x) > 0)
|
||||
goto gotit;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
timerinit(void)
|
||||
{
|
||||
ctimer = chancreate(sizeof(Timer*), 100);
|
||||
chansetname(ctimer, "ctimer");
|
||||
proccreate(timerproc, nil, STACK);
|
||||
}
|
||||
|
||||
Timer*
|
||||
timerstart(int dt)
|
||||
{
|
||||
Timer *t;
|
||||
|
||||
t = timer;
|
||||
if(t)
|
||||
timer = timer->next;
|
||||
else{
|
||||
t = emalloc(sizeof(Timer));
|
||||
t->c = chancreate(sizeof(int), 0);
|
||||
chansetname(t->c, "tc%p", t->c);
|
||||
}
|
||||
t->next = nil;
|
||||
t->dt = dt;
|
||||
t->cancel = FALSE;
|
||||
sendp(ctimer, t);
|
||||
return t;
|
||||
t = timer;
|
||||
if (t)
|
||||
timer = timer->next;
|
||||
else {
|
||||
t = emalloc(sizeof(Timer));
|
||||
t->c = chancreate(sizeof(int), 0);
|
||||
chansetname(t->c, "tc%p", t->c);
|
||||
}
|
||||
t->next = nil;
|
||||
t->dt = dt;
|
||||
t->cancel = FALSE;
|
||||
sendp(ctimer, t);
|
||||
return t;
|
||||
}
|
||||
|
|
749
util.c
749
util.c
|
@ -12,124 +12,112 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static Point prevmouse;
|
||||
static Window *mousew;
|
||||
static Point prevmouse;
|
||||
static Window* mousew;
|
||||
|
||||
Range
|
||||
range(int q0, int q1)
|
||||
{
|
||||
Range r;
|
||||
Range range(int q0, int q1) {
|
||||
Range r;
|
||||
|
||||
r.q0 = q0;
|
||||
r.q1 = q1;
|
||||
return r;
|
||||
r.q0 = q0;
|
||||
r.q1 = q1;
|
||||
return r;
|
||||
}
|
||||
|
||||
Runestr
|
||||
runestr(Rune *r, uint n)
|
||||
{
|
||||
Runestr rs;
|
||||
Runestr runestr(Rune* r, uint n) {
|
||||
Runestr rs;
|
||||
|
||||
rs.r = r;
|
||||
rs.nr = n;
|
||||
return rs;
|
||||
rs.r = r;
|
||||
rs.nr = n;
|
||||
return rs;
|
||||
}
|
||||
|
||||
void
|
||||
cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
|
||||
{
|
||||
uchar *q;
|
||||
Rune *s;
|
||||
int j, w;
|
||||
void cvttorunes(char* p, int n, Rune* r, int* nb, int* nr, int* nulls) {
|
||||
uchar* q;
|
||||
Rune* s;
|
||||
int j, w;
|
||||
|
||||
/*
|
||||
* Always guaranteed that n bytes may be interpreted
|
||||
* without worrying about partial runes. This may mean
|
||||
* reading up to UTFmax-1 more bytes than n; the caller
|
||||
* knows this. If n is a firm limit, the caller should
|
||||
* set p[n] = 0.
|
||||
*/
|
||||
q = (uchar*)p;
|
||||
s = r;
|
||||
for(j=0; j<n; j+=w){
|
||||
if(*q < Runeself){
|
||||
w = 1;
|
||||
*s = *q++;
|
||||
}else{
|
||||
w = chartorune(s, (char*)q);
|
||||
q += w;
|
||||
}
|
||||
if(*s)
|
||||
s++;
|
||||
else if(nulls)
|
||||
*nulls = TRUE;
|
||||
}
|
||||
*nb = (char*)q-p;
|
||||
*nr = s-r;
|
||||
/*
|
||||
* Always guaranteed that n bytes may be interpreted
|
||||
* without worrying about partial runes. This may mean
|
||||
* reading up to UTFmax-1 more bytes than n; the caller
|
||||
* knows this. If n is a firm limit, the caller should
|
||||
* set p[n] = 0.
|
||||
*/
|
||||
q = (uchar*)p;
|
||||
s = r;
|
||||
for (j = 0; j < n; j += w) {
|
||||
if (*q < Runeself) {
|
||||
w = 1;
|
||||
*s = *q++;
|
||||
} else {
|
||||
w = chartorune(s, (char*)q);
|
||||
q += w;
|
||||
}
|
||||
if (*s)
|
||||
s++;
|
||||
else if (nulls)
|
||||
*nulls = TRUE;
|
||||
}
|
||||
*nb = (char*)q - p;
|
||||
*nr = s - r;
|
||||
}
|
||||
|
||||
void
|
||||
error(char *s)
|
||||
{
|
||||
fprint(2, "acme: %s: %r\n", s);
|
||||
threadexitsall(nil);
|
||||
void error(char* s) {
|
||||
fprint(2, "acme: %s: %r\n", s);
|
||||
threadexitsall(nil);
|
||||
}
|
||||
|
||||
Window*
|
||||
errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
|
||||
{
|
||||
Window *w;
|
||||
Rune *r;
|
||||
int i, n;
|
||||
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
|
||||
Window* errorwin1(Rune* dir, int ndir, Rune** incl, int nincl) {
|
||||
Window* w;
|
||||
Rune* r;
|
||||
int i, n;
|
||||
static Rune Lpluserrors[] = {'+', 'E', 'r', 'r', 'o', 'r', 's', 0};
|
||||
|
||||
r = runemalloc(ndir+8);
|
||||
if((n = ndir) != 0){
|
||||
runemove(r, dir, ndir);
|
||||
r[n++] = L'/';
|
||||
}
|
||||
runemove(r+n, Lpluserrors, 7);
|
||||
n += 7;
|
||||
w = lookfile(r, n);
|
||||
if(w == nil){
|
||||
if(row.ncol == 0)
|
||||
if(rowadd(&row, nil, -1) == nil)
|
||||
error("can't create column to make error window");
|
||||
w = coladd(row.col[row.ncol-1], nil, nil, -1);
|
||||
w->filemenu = FALSE;
|
||||
winsetname(w, r, n);
|
||||
xfidlog(w, "new");
|
||||
}
|
||||
free(r);
|
||||
for(i=nincl; --i>=0; ){
|
||||
n = runestrlen(incl[i]);
|
||||
r = runemalloc(n);
|
||||
runemove(r, incl[i], n);
|
||||
winaddincl(w, r, n);
|
||||
}
|
||||
for(i=0; i<NINDENT; i++)
|
||||
w->indent[i] = globalindent[i];
|
||||
return w;
|
||||
r = runemalloc(ndir + 8);
|
||||
if ((n = ndir) != 0) {
|
||||
runemove(r, dir, ndir);
|
||||
r[n++] = L'/';
|
||||
}
|
||||
runemove(r + n, Lpluserrors, 7);
|
||||
n += 7;
|
||||
w = lookfile(r, n);
|
||||
if (w == nil) {
|
||||
if (row.ncol == 0)
|
||||
if (rowadd(&row, nil, -1) == nil)
|
||||
error("can't create column to make error window");
|
||||
w = coladd(row.col[row.ncol - 1], nil, nil, -1);
|
||||
w->filemenu = FALSE;
|
||||
winsetname(w, r, n);
|
||||
xfidlog(w, "new");
|
||||
}
|
||||
free(r);
|
||||
for (i = nincl; --i >= 0;) {
|
||||
n = runestrlen(incl[i]);
|
||||
r = runemalloc(n);
|
||||
runemove(r, incl[i], n);
|
||||
winaddincl(w, r, n);
|
||||
}
|
||||
for (i = 0; i < NINDENT; i++)
|
||||
w->indent[i] = globalindent[i];
|
||||
return w;
|
||||
}
|
||||
|
||||
/* make new window, if necessary; return with it locked */
|
||||
Window*
|
||||
errorwin(Mntdir *md, int owner)
|
||||
{
|
||||
Window *w;
|
||||
Window* errorwin(Mntdir* md, int owner) {
|
||||
Window* w;
|
||||
|
||||
for(;;){
|
||||
if(md == nil)
|
||||
w = errorwin1(nil, 0, nil, 0);
|
||||
else
|
||||
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
|
||||
winlock(w, owner);
|
||||
if(w->col != nil)
|
||||
break;
|
||||
/* window was deleted too fast */
|
||||
winunlock(w);
|
||||
}
|
||||
return w;
|
||||
for (;;) {
|
||||
if (md == nil)
|
||||
w = errorwin1(nil, 0, nil, 0);
|
||||
else
|
||||
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
|
||||
winlock(w, owner);
|
||||
if (w->col != nil)
|
||||
break;
|
||||
/* window was deleted too fast */
|
||||
winunlock(w);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -137,360 +125,315 @@ errorwin(Mntdir *md, int owner)
|
|||
* It will be unlocked and returned window
|
||||
* will be locked in its place.
|
||||
*/
|
||||
Window*
|
||||
errorwinforwin(Window *w)
|
||||
{
|
||||
int i, n, nincl, owner;
|
||||
Rune **incl;
|
||||
Runestr dir;
|
||||
Text *t;
|
||||
Window* errorwinforwin(Window* w) {
|
||||
int i, n, nincl, owner;
|
||||
Rune** incl;
|
||||
Runestr dir;
|
||||
Text* t;
|
||||
|
||||
t = &w->body;
|
||||
dir = dirname(t, nil, 0);
|
||||
if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */
|
||||
free(dir.r);
|
||||
dir.r = nil;
|
||||
dir.nr = 0;
|
||||
}
|
||||
incl = nil;
|
||||
nincl = w->nincl;
|
||||
if(nincl > 0){
|
||||
incl = emalloc(nincl*sizeof(Rune*));
|
||||
for(i=0; i<nincl; i++){
|
||||
n = runestrlen(w->incl[i]);
|
||||
incl[i] = runemalloc(n+1);
|
||||
runemove(incl[i], w->incl[i], n);
|
||||
}
|
||||
}
|
||||
owner = w->owner;
|
||||
winunlock(w);
|
||||
for(;;){
|
||||
w = errorwin1(dir.r, dir.nr, incl, nincl);
|
||||
winlock(w, owner);
|
||||
if(w->col != nil)
|
||||
break;
|
||||
/* window deleted too fast */
|
||||
winunlock(w);
|
||||
}
|
||||
return w;
|
||||
t = &w->body;
|
||||
dir = dirname(t, nil, 0);
|
||||
if (dir.nr == 1 && dir.r[0] == '.') { /* sigh */
|
||||
free(dir.r);
|
||||
dir.r = nil;
|
||||
dir.nr = 0;
|
||||
}
|
||||
incl = nil;
|
||||
nincl = w->nincl;
|
||||
if (nincl > 0) {
|
||||
incl = emalloc(nincl * sizeof(Rune*));
|
||||
for (i = 0; i < nincl; i++) {
|
||||
n = runestrlen(w->incl[i]);
|
||||
incl[i] = runemalloc(n + 1);
|
||||
runemove(incl[i], w->incl[i], n);
|
||||
}
|
||||
}
|
||||
owner = w->owner;
|
||||
winunlock(w);
|
||||
for (;;) {
|
||||
w = errorwin1(dir.r, dir.nr, incl, nincl);
|
||||
winlock(w, owner);
|
||||
if (w->col != nil)
|
||||
break;
|
||||
/* window deleted too fast */
|
||||
winunlock(w);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
typedef struct Warning Warning;
|
||||
|
||||
struct Warning{
|
||||
Mntdir *md;
|
||||
Buffer buf;
|
||||
Warning *next;
|
||||
struct Warning {
|
||||
Mntdir* md;
|
||||
Buffer buf;
|
||||
Warning* next;
|
||||
};
|
||||
|
||||
static Warning *warnings;
|
||||
static Warning* warnings;
|
||||
|
||||
static
|
||||
void
|
||||
addwarningtext(Mntdir *md, Rune *r, int nr)
|
||||
{
|
||||
Warning *warn;
|
||||
static void addwarningtext(Mntdir* md, Rune* r, int nr) {
|
||||
Warning* warn;
|
||||
|
||||
for(warn = warnings; warn; warn=warn->next){
|
||||
if(warn->md == md){
|
||||
bufinsert(&warn->buf, warn->buf.nc, r, nr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
warn = emalloc(sizeof(Warning));
|
||||
warn->next = warnings;
|
||||
warn->md = md;
|
||||
if(md)
|
||||
fsysincid(md);
|
||||
warnings = warn;
|
||||
bufinsert(&warn->buf, 0, r, nr);
|
||||
nbsendp(cwarn, 0);
|
||||
for (warn = warnings; warn; warn = warn->next) {
|
||||
if (warn->md == md) {
|
||||
bufinsert(&warn->buf, warn->buf.nc, r, nr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
warn = emalloc(sizeof(Warning));
|
||||
warn->next = warnings;
|
||||
warn->md = md;
|
||||
if (md)
|
||||
fsysincid(md);
|
||||
warnings = warn;
|
||||
bufinsert(&warn->buf, 0, r, nr);
|
||||
nbsendp(cwarn, 0);
|
||||
}
|
||||
|
||||
/* called while row is locked */
|
||||
void
|
||||
flushwarnings(void)
|
||||
{
|
||||
Warning *warn, *next;
|
||||
Window *w;
|
||||
Text *t;
|
||||
int owner, nr, q0, n;
|
||||
Rune *r;
|
||||
void flushwarnings(void) {
|
||||
Warning *warn, *next;
|
||||
Window* w;
|
||||
Text* t;
|
||||
int owner, nr, q0, n;
|
||||
Rune* r;
|
||||
|
||||
for(warn=warnings; warn; warn=next) {
|
||||
w = errorwin(warn->md, 'E');
|
||||
t = &w->body;
|
||||
owner = w->owner;
|
||||
if(owner == 0)
|
||||
w->owner = 'E';
|
||||
wincommit(w, t);
|
||||
/*
|
||||
* Most commands don't generate much output. For instance,
|
||||
* Edit ,>cat goes through /dev/cons and is already in blocks
|
||||
* because of the i/o system, but a few can. Edit ,p will
|
||||
* put the entire result into a single hunk. So it's worth doing
|
||||
* this in blocks (and putting the text in a buffer in the first
|
||||
* place), to avoid a big memory footprint.
|
||||
*/
|
||||
r = fbufalloc();
|
||||
q0 = t->file->b.nc;
|
||||
for(n = 0; n < warn->buf.nc; n += nr){
|
||||
nr = warn->buf.nc - n;
|
||||
if(nr > RBUFSIZE)
|
||||
nr = RBUFSIZE;
|
||||
bufread(&warn->buf, n, r, nr);
|
||||
textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
|
||||
}
|
||||
textshow(t, q0, t->file->b.nc, 1);
|
||||
free(r);
|
||||
winsettag(t->w);
|
||||
textscrdraw(t);
|
||||
w->owner = owner;
|
||||
w->dirty = FALSE;
|
||||
winunlock(w);
|
||||
bufclose(&warn->buf);
|
||||
next = warn->next;
|
||||
if(warn->md)
|
||||
fsysdelid(warn->md);
|
||||
free(warn);
|
||||
}
|
||||
warnings = nil;
|
||||
for (warn = warnings; warn; warn = next) {
|
||||
w = errorwin(warn->md, 'E');
|
||||
t = &w->body;
|
||||
owner = w->owner;
|
||||
if (owner == 0)
|
||||
w->owner = 'E';
|
||||
wincommit(w, t);
|
||||
/*
|
||||
* Most commands don't generate much output. For instance,
|
||||
* Edit ,>cat goes through /dev/cons and is already in blocks
|
||||
* because of the i/o system, but a few can. Edit ,p will
|
||||
* put the entire result into a single hunk. So it's worth doing
|
||||
* this in blocks (and putting the text in a buffer in the first
|
||||
* place), to avoid a big memory footprint.
|
||||
*/
|
||||
r = fbufalloc();
|
||||
q0 = t->file->b.nc;
|
||||
for (n = 0; n < warn->buf.nc; n += nr) {
|
||||
nr = warn->buf.nc - n;
|
||||
if (nr > RBUFSIZE)
|
||||
nr = RBUFSIZE;
|
||||
bufread(&warn->buf, n, r, nr);
|
||||
textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
|
||||
}
|
||||
textshow(t, q0, t->file->b.nc, 1);
|
||||
free(r);
|
||||
winsettag(t->w);
|
||||
textscrdraw(t);
|
||||
w->owner = owner;
|
||||
w->dirty = FALSE;
|
||||
winunlock(w);
|
||||
bufclose(&warn->buf);
|
||||
next = warn->next;
|
||||
if (warn->md)
|
||||
fsysdelid(warn->md);
|
||||
free(warn);
|
||||
}
|
||||
warnings = nil;
|
||||
}
|
||||
|
||||
void
|
||||
warning(Mntdir *md, char *s, ...)
|
||||
{
|
||||
Rune *r;
|
||||
va_list arg;
|
||||
void warning(Mntdir* md, char* s, ...) {
|
||||
Rune* r;
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, s);
|
||||
r = runevsmprint(s, arg);
|
||||
va_end(arg);
|
||||
if(r == nil)
|
||||
error("runevsmprint failed");
|
||||
addwarningtext(md, r, runestrlen(r));
|
||||
free(r);
|
||||
va_start(arg, s);
|
||||
r = runevsmprint(s, arg);
|
||||
va_end(arg);
|
||||
if (r == nil)
|
||||
error("runevsmprint failed");
|
||||
addwarningtext(md, r, runestrlen(r));
|
||||
free(r);
|
||||
}
|
||||
|
||||
int
|
||||
runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
|
||||
{
|
||||
if(n1 != n2)
|
||||
return FALSE;
|
||||
return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
|
||||
int runeeq(Rune* s1, uint n1, Rune* s2, uint n2) {
|
||||
if (n1 != n2)
|
||||
return FALSE;
|
||||
return memcmp(s1, s2, n1 * sizeof(Rune)) == 0;
|
||||
}
|
||||
|
||||
uint
|
||||
min(uint a, uint b)
|
||||
{
|
||||
if(a < b)
|
||||
return a;
|
||||
return b;
|
||||
uint min(uint a, uint b) {
|
||||
if (a < b)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
uint
|
||||
max(uint a, uint b)
|
||||
{
|
||||
if(a > b)
|
||||
return a;
|
||||
return b;
|
||||
uint max(uint a, uint b) {
|
||||
if (a > b)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
char*
|
||||
runetobyte(Rune *r, int n)
|
||||
{
|
||||
char *s;
|
||||
char* runetobyte(Rune* r, int n) {
|
||||
char* s;
|
||||
|
||||
if(r == nil)
|
||||
return nil;
|
||||
s = emalloc(n*UTFmax+1);
|
||||
setmalloctag(s, getcallerpc(&r));
|
||||
snprint(s, n*UTFmax+1, "%.*S", n, r);
|
||||
return s;
|
||||
if (r == nil)
|
||||
return nil;
|
||||
s = emalloc(n * UTFmax + 1);
|
||||
setmalloctag(s, getcallerpc(&r));
|
||||
snprint(s, n * UTFmax + 1, "%.*S", n, r);
|
||||
return s;
|
||||
}
|
||||
|
||||
Rune*
|
||||
bytetorune(char *s, int *ip)
|
||||
{
|
||||
Rune *r;
|
||||
int nb, nr;
|
||||
Rune* bytetorune(char* s, int* ip) {
|
||||
Rune* r;
|
||||
int nb, nr;
|
||||
|
||||
nb = strlen(s);
|
||||
r = runemalloc(nb+1);
|
||||
cvttorunes(s, nb, r, &nb, &nr, nil);
|
||||
r[nr] = '\0';
|
||||
*ip = nr;
|
||||
return r;
|
||||
nb = strlen(s);
|
||||
r = runemalloc(nb + 1);
|
||||
cvttorunes(s, nb, r, &nb, &nr, nil);
|
||||
r[nr] = '\0';
|
||||
*ip = nr;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
isalnum(Rune c)
|
||||
{
|
||||
/*
|
||||
* Hard to get absolutely right. Use what we know about ASCII
|
||||
* and assume anything above the Latin control characters is
|
||||
* potentially an alphanumeric.
|
||||
*/
|
||||
if(c <= ' ')
|
||||
return FALSE;
|
||||
if(0x7F<=c && c<=0xA0)
|
||||
return FALSE;
|
||||
if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
int isalnum(Rune c) {
|
||||
/*
|
||||
* Hard to get absolutely right. Use what we know about ASCII
|
||||
* and assume anything above the Latin control characters is
|
||||
* potentially an alphanumeric.
|
||||
*/
|
||||
if (c <= ' ')
|
||||
return FALSE;
|
||||
if (0x7F <= c && c <= 0xA0)
|
||||
return FALSE;
|
||||
if (utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
rgetc(void *v, uint n)
|
||||
{
|
||||
return ((Rune*)v)[n];
|
||||
int rgetc(void* v, uint n) { return ((Rune*)v)[n]; }
|
||||
|
||||
int tgetc(void* a, uint n) {
|
||||
Text* t;
|
||||
|
||||
t = a;
|
||||
if (n >= t->file->b.nc)
|
||||
return 0;
|
||||
return textreadc(t, n);
|
||||
}
|
||||
|
||||
int
|
||||
tgetc(void *a, uint n)
|
||||
{
|
||||
Text *t;
|
||||
|
||||
t = a;
|
||||
if(n >= t->file->b.nc)
|
||||
return 0;
|
||||
return textreadc(t, n);
|
||||
Rune* skipbl(Rune* r, int n, int* np) {
|
||||
while (n > 0 && (*r == ' ' || *r == '\t' || *r == '\n')) {
|
||||
--n;
|
||||
r++;
|
||||
}
|
||||
*np = n;
|
||||
return r;
|
||||
}
|
||||
|
||||
Rune*
|
||||
skipbl(Rune *r, int n, int *np)
|
||||
{
|
||||
while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){
|
||||
--n;
|
||||
r++;
|
||||
}
|
||||
*np = n;
|
||||
return r;
|
||||
Rune* findbl(Rune* r, int n, int* np) {
|
||||
while (n > 0 && *r != ' ' && *r != '\t' && *r != '\n') {
|
||||
--n;
|
||||
r++;
|
||||
}
|
||||
*np = n;
|
||||
return r;
|
||||
}
|
||||
|
||||
Rune*
|
||||
findbl(Rune *r, int n, int *np)
|
||||
{
|
||||
while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
|
||||
--n;
|
||||
r++;
|
||||
}
|
||||
*np = n;
|
||||
return r;
|
||||
void savemouse(Window* w) {
|
||||
prevmouse = mouse->xy;
|
||||
mousew = w;
|
||||
}
|
||||
|
||||
void
|
||||
savemouse(Window *w)
|
||||
{
|
||||
prevmouse = mouse->xy;
|
||||
mousew = w;
|
||||
int restoremouse(Window* w) {
|
||||
int did;
|
||||
|
||||
did = 0;
|
||||
if (mousew != nil && mousew == w) {
|
||||
moveto(mousectl, prevmouse);
|
||||
did = 1;
|
||||
}
|
||||
mousew = nil;
|
||||
return did;
|
||||
}
|
||||
|
||||
int
|
||||
restoremouse(Window *w)
|
||||
{
|
||||
int did;
|
||||
void clearmouse() { mousew = nil; }
|
||||
|
||||
did = 0;
|
||||
if(mousew!=nil && mousew==w) {
|
||||
moveto(mousectl, prevmouse);
|
||||
did = 1;
|
||||
}
|
||||
mousew = nil;
|
||||
return did;
|
||||
char* estrdup(char* s) {
|
||||
char* t;
|
||||
|
||||
t = strdup(s);
|
||||
if (t == nil)
|
||||
error("strdup failed");
|
||||
setmalloctag(t, getcallerpc(&s));
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
clearmouse()
|
||||
{
|
||||
mousew = nil;
|
||||
void* emalloc(uint n) {
|
||||
void* p;
|
||||
|
||||
p = malloc(n);
|
||||
if (p == nil)
|
||||
error("malloc failed");
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
memset(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
char*
|
||||
estrdup(char *s)
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = strdup(s);
|
||||
if(t == nil)
|
||||
error("strdup failed");
|
||||
setmalloctag(t, getcallerpc(&s));
|
||||
return t;
|
||||
}
|
||||
|
||||
void*
|
||||
emalloc(uint n)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc(n);
|
||||
if(p == nil)
|
||||
error("malloc failed");
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
memset(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
void*
|
||||
erealloc(void *p, uint n)
|
||||
{
|
||||
p = realloc(p, n);
|
||||
if(p == nil)
|
||||
error("realloc failed");
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
return p;
|
||||
void* erealloc(void* p, uint n) {
|
||||
p = realloc(p, n);
|
||||
if (p == nil)
|
||||
error("realloc failed");
|
||||
setmalloctag(p, getcallerpc(&n));
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Heuristic city.
|
||||
*/
|
||||
Window*
|
||||
makenewwindow(Text *t)
|
||||
{
|
||||
Column *c;
|
||||
Window *w, *bigw, *emptyw;
|
||||
Text *emptyb;
|
||||
int i, y, el;
|
||||
Window* makenewwindow(Text* t) {
|
||||
Column* c;
|
||||
Window *w, *bigw, *emptyw;
|
||||
Text* emptyb;
|
||||
int i, y, el;
|
||||
|
||||
if(activecol)
|
||||
c = activecol;
|
||||
else if(seltext && seltext->col)
|
||||
c = seltext->col;
|
||||
else if(t && t->col)
|
||||
c = t->col;
|
||||
else{
|
||||
if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
|
||||
error("can't make column");
|
||||
c = row.col[row.ncol-1];
|
||||
}
|
||||
activecol = c;
|
||||
if(t==nil || t->w==nil || c->nw==0)
|
||||
return coladd(c, nil, nil, -1);
|
||||
if (activecol)
|
||||
c = activecol;
|
||||
else if (seltext && seltext->col)
|
||||
c = seltext->col;
|
||||
else if (t && t->col)
|
||||
c = t->col;
|
||||
else {
|
||||
if (row.ncol == 0 && rowadd(&row, nil, -1) == nil)
|
||||
error("can't make column");
|
||||
c = row.col[row.ncol - 1];
|
||||
}
|
||||
activecol = c;
|
||||
if (t == nil || t->w == nil || c->nw == 0)
|
||||
return coladd(c, nil, nil, -1);
|
||||
|
||||
/* find biggest window and biggest blank spot */
|
||||
emptyw = c->w[0];
|
||||
bigw = emptyw;
|
||||
for(i=1; i<c->nw; i++){
|
||||
w = c->w[i];
|
||||
/* use >= to choose one near bottom of screen */
|
||||
if(w->body.fr.maxlines >= bigw->body.fr.maxlines)
|
||||
bigw = w;
|
||||
if(w->body.fr.maxlines-w->body.fr.nlines >= emptyw->body.fr.maxlines-emptyw->body.fr.nlines)
|
||||
emptyw = w;
|
||||
}
|
||||
emptyb = &emptyw->body;
|
||||
el = emptyb->fr.maxlines-emptyb->fr.nlines;
|
||||
/* if empty space is big, use it */
|
||||
if(el>15 || (el>3 && el>(bigw->body.fr.maxlines-1)/2))
|
||||
y = emptyb->fr.r.min.y+emptyb->fr.nlines*font->height;
|
||||
else{
|
||||
/* 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)
|
||||
bigw = t->w;
|
||||
y = (bigw->r.min.y + bigw->r.max.y)/2;
|
||||
}
|
||||
w = coladd(c, nil, nil, y);
|
||||
if(w->body.fr.maxlines < 2)
|
||||
colgrow(w->col, w, 1);
|
||||
return w;
|
||||
/* find biggest window and biggest blank spot */
|
||||
emptyw = c->w[0];
|
||||
bigw = emptyw;
|
||||
for (i = 1; i < c->nw; i++) {
|
||||
w = c->w[i];
|
||||
/* use >= to choose one near bottom of screen */
|
||||
if (w->body.fr.maxlines >= bigw->body.fr.maxlines)
|
||||
bigw = w;
|
||||
if (
|
||||
w->body.fr.maxlines - w->body.fr.nlines >=
|
||||
emptyw->body.fr.maxlines - emptyw->body.fr.nlines)
|
||||
emptyw = w;
|
||||
}
|
||||
emptyb = &emptyw->body;
|
||||
el = emptyb->fr.maxlines - emptyb->fr.nlines;
|
||||
/* if empty space is big, use it */
|
||||
if (el > 15 || (el > 3 && el > (bigw->body.fr.maxlines - 1) / 2))
|
||||
y = emptyb->fr.r.min.y + emptyb->fr.nlines * font->height;
|
||||
else {
|
||||
/* 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)
|
||||
bigw = t->w;
|
||||
y = (bigw->r.min.y + bigw->r.max.y) / 2;
|
||||
}
|
||||
w = coladd(c, nil, nil, y);
|
||||
if (w->body.fr.maxlines < 2)
|
||||
colgrow(w->col, w, 1);
|
||||
return w;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue