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
|
||||||
**/o.*
|
**/o.*
|
||||||
|
acme
|
||||||
|
|
196
addr.c
196
addr.c
|
@ -12,39 +12,27 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
enum
|
enum { None = 0, Fore = '+', Back = '-' };
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Fore = '+',
|
|
||||||
Back = '-'
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
enum { Char, Line };
|
||||||
{
|
|
||||||
Char,
|
|
||||||
Line
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
int isaddrc(int r) {
|
||||||
isaddrc(int r)
|
if (r && utfrune("0123456789+-/$.#,;?", r) != nil)
|
||||||
{
|
|
||||||
if(r && utfrune("0123456789+-/$.#,;?", r)!=nil)
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* quite hard: could be almost anything but white space, but we are a little conservative,
|
* quite hard: could be almost anything but white space, but we are a little
|
||||||
* aiming for regular expressions of alphanumerics and no white space
|
* conservative, aiming for regular expressions of alphanumerics and no white
|
||||||
|
* space
|
||||||
*/
|
*/
|
||||||
int
|
int isregexc(int r) {
|
||||||
isregexc(int r)
|
if (r == 0)
|
||||||
{
|
|
||||||
if(r == 0)
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if(isalnum(r))
|
if (isalnum(r))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
if(utfrune("^+-.*?#,;[]()$", r)!=nil)
|
if (utfrune("^+-.*?#,;[]()$", r) != nil)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -54,130 +42,125 @@ isregexc(int r)
|
||||||
// and then nr chars, being careful not to walk past
|
// and then nr chars, being careful not to walk past
|
||||||
// the end of the current line.
|
// the end of the current line.
|
||||||
// It returns the final position.
|
// It returns the final position.
|
||||||
long
|
long nlcounttopos(Text* t, long q0, long nl, long nr) {
|
||||||
nlcounttopos(Text *t, long q0, long nl, long nr)
|
while (nl > 0 && q0 < t->file->b.nc) {
|
||||||
{
|
if (textreadc(t, q0++) == '\n')
|
||||||
while(nl > 0 && q0 < t->file->b.nc) {
|
|
||||||
if(textreadc(t, q0++) == '\n')
|
|
||||||
nl--;
|
nl--;
|
||||||
}
|
}
|
||||||
if(nl > 0)
|
if (nl > 0)
|
||||||
return q0;
|
return q0;
|
||||||
while(nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') {
|
while (nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') {
|
||||||
q0++;
|
q0++;
|
||||||
nr--;
|
nr--;
|
||||||
}
|
}
|
||||||
return q0;
|
return q0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Range
|
Range number(
|
||||||
number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp)
|
uint showerr, Text* t, Range r, int line, int dir, int size, int* evalp) {
|
||||||
{
|
|
||||||
uint q0, q1;
|
uint q0, q1;
|
||||||
|
|
||||||
if(size == Char){
|
if (size == Char) {
|
||||||
if(dir == Fore)
|
if (dir == Fore)
|
||||||
line = r.q1+line;
|
line = r.q1 + line;
|
||||||
else if(dir == Back){
|
else if (dir == Back) {
|
||||||
if(r.q0==0 && line>0)
|
if (r.q0 == 0 && line > 0)
|
||||||
r.q0 = t->file->b.nc;
|
r.q0 = t->file->b.nc;
|
||||||
line = r.q0 - line;
|
line = r.q0 - line;
|
||||||
}
|
}
|
||||||
if(line<0 || line>t->file->b.nc)
|
if (line < 0 || line > t->file->b.nc)
|
||||||
goto Rescue;
|
goto Rescue;
|
||||||
*evalp = TRUE;
|
*evalp = TRUE;
|
||||||
return range(line, line);
|
return range(line, line);
|
||||||
}
|
}
|
||||||
q0 = r.q0;
|
q0 = r.q0;
|
||||||
q1 = r.q1;
|
q1 = r.q1;
|
||||||
switch(dir){
|
switch (dir) {
|
||||||
case None:
|
case None:
|
||||||
q0 = 0;
|
q0 = 0;
|
||||||
q1 = 0;
|
q1 = 0;
|
||||||
Forward:
|
Forward:
|
||||||
while(line>0 && q1<t->file->b.nc)
|
while (line > 0 && q1 < t->file->b.nc)
|
||||||
if(textreadc(t, q1++) == '\n' || q1==t->file->b.nc)
|
if (textreadc(t, q1++) == '\n' || q1 == t->file->b.nc)
|
||||||
if(--line > 0)
|
if (--line > 0)
|
||||||
q0 = q1;
|
q0 = q1;
|
||||||
if(line==1 && q1==t->file->b.nc) // 6 goes to end of 5-line file
|
if (line == 1 && q1 == t->file->b.nc) // 6 goes to end of 5-line file
|
||||||
break;
|
break;
|
||||||
if(line > 0)
|
if (line > 0)
|
||||||
goto Rescue;
|
goto Rescue;
|
||||||
break;
|
break;
|
||||||
case Fore:
|
case Fore:
|
||||||
if(q1 > 0)
|
if (q1 > 0)
|
||||||
while(q1<t->file->b.nc && textreadc(t, q1-1) != '\n')
|
while (q1 < t->file->b.nc && textreadc(t, q1 - 1) != '\n')
|
||||||
q1++;
|
q1++;
|
||||||
q0 = q1;
|
q0 = q1;
|
||||||
goto Forward;
|
goto Forward;
|
||||||
case Back:
|
case Back:
|
||||||
if(q0 < t->file->b.nc)
|
if (q0 < t->file->b.nc)
|
||||||
while(q0>0 && textreadc(t, q0-1)!='\n')
|
while (q0 > 0 && textreadc(t, q0 - 1) != '\n')
|
||||||
q0--;
|
q0--;
|
||||||
q1 = q0;
|
q1 = q0;
|
||||||
while(line>0 && q0>0){
|
while (line > 0 && q0 > 0) {
|
||||||
if(textreadc(t, q0-1) == '\n'){
|
if (textreadc(t, q0 - 1) == '\n') {
|
||||||
if(--line >= 0)
|
if (--line >= 0)
|
||||||
q1 = q0;
|
q1 = q0;
|
||||||
}
|
}
|
||||||
--q0;
|
--q0;
|
||||||
}
|
}
|
||||||
/* :1-1 is :0 = #0, but :1-2 is an error */
|
/* :1-1 is :0 = #0, but :1-2 is an error */
|
||||||
if(line > 1)
|
if (line > 1)
|
||||||
goto Rescue;
|
goto Rescue;
|
||||||
while(q0>0 && textreadc(t, q0-1)!='\n')
|
while (q0 > 0 && textreadc(t, q0 - 1) != '\n')
|
||||||
--q0;
|
--q0;
|
||||||
}
|
}
|
||||||
*evalp = TRUE;
|
*evalp = TRUE;
|
||||||
return range(q0, q1);
|
return range(q0, q1);
|
||||||
|
|
||||||
Rescue:
|
Rescue:
|
||||||
if(showerr)
|
if (showerr)
|
||||||
warning(nil, "address out of range\n");
|
warning(nil, "address out of range\n");
|
||||||
*evalp = FALSE;
|
*evalp = FALSE;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Range regexp(
|
||||||
Range
|
uint showerr, Text* t, Range lim, Range r, Rune* pat, int dir, int* foundp) {
|
||||||
regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
|
|
||||||
{
|
|
||||||
int found;
|
int found;
|
||||||
Rangeset sel;
|
Rangeset sel;
|
||||||
int q;
|
int q;
|
||||||
|
|
||||||
if(pat[0] == '\0' && rxnull()){
|
if (pat[0] == '\0' && rxnull()) {
|
||||||
if(showerr)
|
if (showerr)
|
||||||
warning(nil, "no previous regular expression\n");
|
warning(nil, "no previous regular expression\n");
|
||||||
*foundp = FALSE;
|
*foundp = FALSE;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
if(pat[0] && rxcompile(pat) == FALSE){
|
if (pat[0] && rxcompile(pat) == FALSE) {
|
||||||
*foundp = FALSE;
|
*foundp = FALSE;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
if(dir == Back)
|
if (dir == Back)
|
||||||
found = rxbexecute(t, r.q0, &sel);
|
found = rxbexecute(t, r.q0, &sel);
|
||||||
else{
|
else {
|
||||||
if(lim.q0 < 0)
|
if (lim.q0 < 0)
|
||||||
q = Infinity;
|
q = Infinity;
|
||||||
else
|
else
|
||||||
q = lim.q1;
|
q = lim.q1;
|
||||||
found = rxexecute(t, nil, r.q1, q, &sel);
|
found = rxexecute(t, nil, r.q1, q, &sel);
|
||||||
}
|
}
|
||||||
if(!found && showerr)
|
if (!found && showerr)
|
||||||
warning(nil, "no match for regexp\n");
|
warning(nil, "no match for regexp\n");
|
||||||
*foundp = found;
|
*foundp = found;
|
||||||
return sel.r[0];
|
return sel.r[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Range
|
Range address(
|
||||||
address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
|
uint showerr, Text* t, Range lim, Range ar, void* a, uint q0, uint q1,
|
||||||
{
|
int (*getc)(void*, uint), int* evalp, uint* qp) {
|
||||||
int dir, size, npat;
|
int dir, size, npat;
|
||||||
int prevc, c, nc, n;
|
int prevc, c, nc, n;
|
||||||
uint q;
|
uint q;
|
||||||
Rune *pat;
|
Rune* pat;
|
||||||
Range r, nr;
|
Range r, nr;
|
||||||
|
|
||||||
r = ar;
|
r = ar;
|
||||||
|
@ -185,22 +168,22 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
|
||||||
dir = None;
|
dir = None;
|
||||||
size = Line;
|
size = Line;
|
||||||
c = 0;
|
c = 0;
|
||||||
while(q < q1){
|
while (q < q1) {
|
||||||
prevc = c;
|
prevc = c;
|
||||||
c = (*getc)(a, q++);
|
c = (*getc)(a, q++);
|
||||||
switch(c){
|
switch (c) {
|
||||||
default:
|
default:
|
||||||
*qp = q-1;
|
*qp = q - 1;
|
||||||
return r;
|
return r;
|
||||||
case ';':
|
case ';':
|
||||||
ar = r;
|
ar = r;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case ',':
|
case ',':
|
||||||
if(prevc == 0) /* lhs defaults to 0 */
|
if (prevc == 0) /* lhs defaults to 0 */
|
||||||
r.q0 = 0;
|
r.q0 = 0;
|
||||||
if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
|
if (q >= q1 && t != nil && t->file != nil) /* rhs defaults to $ */
|
||||||
r.q1 = t->file->b.nc;
|
r.q1 = t->file->b.nc;
|
||||||
else{
|
else {
|
||||||
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
|
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
|
||||||
r.q1 = nr.q1;
|
r.q1 = nr.q1;
|
||||||
}
|
}
|
||||||
|
@ -208,46 +191,55 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
|
||||||
return r;
|
return r;
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
if(*evalp && (prevc=='+' || prevc=='-'))
|
if (*evalp && (prevc == '+' || prevc == '-'))
|
||||||
if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
|
if ((nc = (*getc)(a, q)) != '#' && nc != '/' && nc != '?')
|
||||||
r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */
|
r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one
|
||||||
|
*/
|
||||||
dir = c;
|
dir = c;
|
||||||
break;
|
break;
|
||||||
case '.':
|
case '.':
|
||||||
case '$':
|
case '$':
|
||||||
if(q != q0+1){
|
if (q != q0 + 1) {
|
||||||
*qp = q-1;
|
*qp = q - 1;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
if(*evalp)
|
if (*evalp)
|
||||||
if(c == '.')
|
if (c == '.')
|
||||||
r = ar;
|
r = ar;
|
||||||
else
|
else
|
||||||
r = range(t->file->b.nc, t->file->b.nc);
|
r = range(t->file->b.nc, t->file->b.nc);
|
||||||
if(q < q1)
|
if (q < q1)
|
||||||
dir = Fore;
|
dir = Fore;
|
||||||
else
|
else
|
||||||
dir = None;
|
dir = None;
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){
|
if (q == q1 || (c = (*getc)(a, q++)) < '0' || '9' < c) {
|
||||||
*qp = q-1;
|
*qp = q - 1;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
size = Char;
|
size = Char;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
case '0':
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
case '1':
|
||||||
n = c -'0';
|
case '2':
|
||||||
while(q<q1){
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
n = c - '0';
|
||||||
|
while (q < q1) {
|
||||||
nc = (*getc)(a, q++);
|
nc = (*getc)(a, q++);
|
||||||
if(nc<'0' || '9'<nc){
|
if (nc < '0' || '9' < nc) {
|
||||||
q--;
|
q--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n = n*10+(nc-'0');
|
n = n * 10 + (nc - '0');
|
||||||
}
|
}
|
||||||
if(*evalp)
|
if (*evalp)
|
||||||
r = number(showerr, t, r, n, dir, size, evalp);
|
r = number(showerr, t, r, n, dir, size, evalp);
|
||||||
dir = None;
|
dir = None;
|
||||||
size = Line;
|
size = Line;
|
||||||
|
@ -258,29 +250,29 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
|
||||||
case '/':
|
case '/':
|
||||||
npat = 0;
|
npat = 0;
|
||||||
pat = nil;
|
pat = nil;
|
||||||
while(q<q1){
|
while (q < q1) {
|
||||||
c = (*getc)(a, q++);
|
c = (*getc)(a, q++);
|
||||||
switch(c){
|
switch (c) {
|
||||||
case '\n':
|
case '\n':
|
||||||
--q;
|
--q;
|
||||||
goto out;
|
goto out;
|
||||||
case '\\':
|
case '\\':
|
||||||
pat = runerealloc(pat, npat+1);
|
pat = runerealloc(pat, npat + 1);
|
||||||
pat[npat++] = c;
|
pat[npat++] = c;
|
||||||
if(q == q1)
|
if (q == q1)
|
||||||
goto out;
|
goto out;
|
||||||
c = (*getc)(a, q++);
|
c = (*getc)(a, q++);
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
pat = runerealloc(pat, npat+1);
|
pat = runerealloc(pat, npat + 1);
|
||||||
pat[npat++] = c;
|
pat[npat++] = c;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
pat = runerealloc(pat, npat+1);
|
pat = runerealloc(pat, npat + 1);
|
||||||
pat[npat] = 0;
|
pat[npat] = 0;
|
||||||
if(*evalp)
|
if (*evalp)
|
||||||
r = regexp(showerr, t, lim, r, pat, dir, evalp);
|
r = regexp(showerr, t, lim, r, pat, dir, evalp);
|
||||||
free(pat);
|
free(pat);
|
||||||
dir = None;
|
dir = None;
|
||||||
|
@ -288,7 +280,7 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(*evalp && dir != None)
|
if (*evalp && dir != None)
|
||||||
r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
|
r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
|
||||||
*qp = q;
|
*qp = q;
|
||||||
return r;
|
return r;
|
||||||
|
|
194
buff.c
194
buff.c
|
@ -12,47 +12,37 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
Slop = 100 /* room to grow with reallocation */
|
Slop = 100 /* room to grow with reallocation */
|
||||||
};
|
};
|
||||||
|
|
||||||
static
|
static void sizecache(Buffer* b, uint n) {
|
||||||
void
|
if (n <= b->cmax)
|
||||||
sizecache(Buffer *b, uint n)
|
|
||||||
{
|
|
||||||
if(n <= b->cmax)
|
|
||||||
return;
|
return;
|
||||||
b->cmax = n+Slop;
|
b->cmax = n + Slop;
|
||||||
b->c = runerealloc(b->c, b->cmax);
|
b->c = runerealloc(b->c, b->cmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void addblock(Buffer* b, uint i, uint n) {
|
||||||
void
|
if (i > b->nbl)
|
||||||
addblock(Buffer *b, uint i, uint n)
|
|
||||||
{
|
|
||||||
if(i > b->nbl)
|
|
||||||
error("internal error: addblock");
|
error("internal error: addblock");
|
||||||
|
|
||||||
b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]);
|
b->bl = realloc(b->bl, (b->nbl + 1) * sizeof b->bl[0]);
|
||||||
if(i < b->nbl)
|
if (i < b->nbl)
|
||||||
memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*));
|
memmove(b->bl + i + 1, b->bl + i, (b->nbl - i) * sizeof(Block*));
|
||||||
b->bl[i] = disknewblock(disk, n);
|
b->bl[i] = disknewblock(disk, n);
|
||||||
b->nbl++;
|
b->nbl++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void delblock(Buffer* b, uint i) {
|
||||||
void
|
if (i >= b->nbl)
|
||||||
delblock(Buffer *b, uint i)
|
|
||||||
{
|
|
||||||
if(i >= b->nbl)
|
|
||||||
error("internal error: delblock");
|
error("internal error: delblock");
|
||||||
|
|
||||||
diskrelease(disk, b->bl[i]);
|
diskrelease(disk, b->bl[i]);
|
||||||
b->nbl--;
|
b->nbl--;
|
||||||
if(i < b->nbl)
|
if (i < b->nbl)
|
||||||
memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*));
|
memmove(b->bl + i, b->bl + i + 1, (b->nbl - i) * sizeof(Block*));
|
||||||
b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]);
|
b->bl = realloc(b->bl, b->nbl * sizeof b->bl[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -60,12 +50,9 @@ delblock(Buffer *b, uint i)
|
||||||
* If at very end, q0 will fall on end of cache block.
|
* If at very end, q0 will fall on end of cache block.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static void flush(Buffer* b) {
|
||||||
void
|
if (b->cdirty || b->cnc == 0) {
|
||||||
flush(Buffer *b)
|
if (b->cnc == 0)
|
||||||
{
|
|
||||||
if(b->cdirty || b->cnc==0){
|
|
||||||
if(b->cnc == 0)
|
|
||||||
delblock(b, b->cbi);
|
delblock(b, b->cbi);
|
||||||
else
|
else
|
||||||
diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
|
diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
|
||||||
|
@ -73,40 +60,37 @@ flush(Buffer *b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void setcache(Buffer* b, uint q0) {
|
||||||
void
|
|
||||||
setcache(Buffer *b, uint q0)
|
|
||||||
{
|
|
||||||
Block **blp, *bl;
|
Block **blp, *bl;
|
||||||
uint i, q;
|
uint i, q;
|
||||||
|
|
||||||
if(q0 > b->nc)
|
if (q0 > b->nc)
|
||||||
error("internal error: setcache");
|
error("internal error: setcache");
|
||||||
/*
|
/*
|
||||||
* flush and reload if q0 is not in cache.
|
* flush and reload if q0 is not in cache.
|
||||||
*/
|
*/
|
||||||
if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))
|
if (b->nc == 0 || (b->cq <= q0 && q0 < b->cq + b->cnc))
|
||||||
return;
|
return;
|
||||||
/*
|
/*
|
||||||
* if q0 is at end of file and end of cache, continue to grow this block
|
* if q0 is at end of file and end of cache, continue to grow this block
|
||||||
*/
|
*/
|
||||||
if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<Maxblock)
|
if (q0 == b->nc && q0 == b->cq + b->cnc && b->cnc < Maxblock)
|
||||||
return;
|
return;
|
||||||
flush(b);
|
flush(b);
|
||||||
/* find block */
|
/* find block */
|
||||||
if(q0 < b->cq){
|
if (q0 < b->cq) {
|
||||||
q = 0;
|
q = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
}else{
|
} else {
|
||||||
q = b->cq;
|
q = b->cq;
|
||||||
i = b->cbi;
|
i = b->cbi;
|
||||||
}
|
}
|
||||||
blp = &b->bl[i];
|
blp = &b->bl[i];
|
||||||
while(q+(*blp)->u.n <= q0 && q+(*blp)->u.n < b->nc){
|
while (q + (*blp)->u.n <= q0 && q + (*blp)->u.n < b->nc) {
|
||||||
q += (*blp)->u.n;
|
q += (*blp)->u.n;
|
||||||
i++;
|
i++;
|
||||||
blp++;
|
blp++;
|
||||||
if(i >= b->nbl)
|
if (i >= b->nbl)
|
||||||
error("block not found");
|
error("block not found");
|
||||||
}
|
}
|
||||||
bl = *blp;
|
bl = *blp;
|
||||||
|
@ -119,30 +103,28 @@ setcache(Buffer *b, uint q0)
|
||||||
diskread(disk, bl, b->c, b->cnc);
|
diskread(disk, bl, b->c, b->cnc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void bufinsert(Buffer* b, uint q0, Rune* s, uint n) {
|
||||||
bufinsert(Buffer *b, uint q0, Rune *s, uint n)
|
|
||||||
{
|
|
||||||
uint i, m, t, off;
|
uint i, m, t, off;
|
||||||
|
|
||||||
if(q0 > b->nc)
|
if (q0 > b->nc)
|
||||||
error("internal error: bufinsert");
|
error("internal error: bufinsert");
|
||||||
|
|
||||||
while(n > 0){
|
while (n > 0) {
|
||||||
setcache(b, q0);
|
setcache(b, q0);
|
||||||
off = q0-b->cq;
|
off = q0 - b->cq;
|
||||||
if(b->cnc+n <= Maxblock){
|
if (b->cnc + n <= Maxblock) {
|
||||||
/* Everything fits in one block. */
|
/* Everything fits in one block. */
|
||||||
t = b->cnc+n;
|
t = b->cnc + n;
|
||||||
m = n;
|
m = n;
|
||||||
if(b->bl == nil){ /* allocate */
|
if (b->bl == nil) { /* allocate */
|
||||||
if(b->cnc != 0)
|
if (b->cnc != 0)
|
||||||
error("internal error: bufinsert1 cnc!=0");
|
error("internal error: bufinsert1 cnc!=0");
|
||||||
addblock(b, 0, t);
|
addblock(b, 0, t);
|
||||||
b->cbi = 0;
|
b->cbi = 0;
|
||||||
}
|
}
|
||||||
sizecache(b, t);
|
sizecache(b, t);
|
||||||
runemove(b->c+off+m, b->c+off, b->cnc-off);
|
runemove(b->c + off + m, b->c + off, b->cnc - off);
|
||||||
runemove(b->c+off, s, m);
|
runemove(b->c + off, s, m);
|
||||||
b->cnc = t;
|
b->cnc = t;
|
||||||
goto Tail;
|
goto Tail;
|
||||||
}
|
}
|
||||||
|
@ -151,17 +133,17 @@ bufinsert(Buffer *b, uint q0, Rune *s, uint n)
|
||||||
* the very beginning or end of this block,
|
* the very beginning or end of this block,
|
||||||
* just make a new block and fill it.
|
* just make a new block and fill it.
|
||||||
*/
|
*/
|
||||||
if(q0==b->cq || q0==b->cq+b->cnc){
|
if (q0 == b->cq || q0 == b->cq + b->cnc) {
|
||||||
if(b->cdirty)
|
if (b->cdirty)
|
||||||
flush(b);
|
flush(b);
|
||||||
m = min(n, Maxblock);
|
m = min(n, Maxblock);
|
||||||
if(b->bl == nil){ /* allocate */
|
if (b->bl == nil) { /* allocate */
|
||||||
if(b->cnc != 0)
|
if (b->cnc != 0)
|
||||||
error("internal error: bufinsert2 cnc!=0");
|
error("internal error: bufinsert2 cnc!=0");
|
||||||
i = 0;
|
i = 0;
|
||||||
}else{
|
} else {
|
||||||
i = b->cbi;
|
i = b->cbi;
|
||||||
if(q0 > b->cq)
|
if (q0 > b->cq)
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
addblock(b, i, m);
|
addblock(b, i, m);
|
||||||
|
@ -176,20 +158,20 @@ bufinsert(Buffer *b, uint q0, Rune *s, uint n)
|
||||||
* Split the block; cut off the right side and
|
* Split the block; cut off the right side and
|
||||||
* let go of it.
|
* let go of it.
|
||||||
*/
|
*/
|
||||||
m = b->cnc-off;
|
m = b->cnc - off;
|
||||||
if(m > 0){
|
if (m > 0) {
|
||||||
i = b->cbi+1;
|
i = b->cbi + 1;
|
||||||
addblock(b, i, m);
|
addblock(b, i, m);
|
||||||
diskwrite(disk, &b->bl[i], b->c+off, m);
|
diskwrite(disk, &b->bl[i], b->c + off, m);
|
||||||
b->cnc -= m;
|
b->cnc -= m;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Now at end of block. Take as much input
|
* Now at end of block. Take as much input
|
||||||
* as possible and tack it on end of block.
|
* as possible and tack it on end of block.
|
||||||
*/
|
*/
|
||||||
m = min(n, Maxblock-b->cnc);
|
m = min(n, Maxblock - b->cnc);
|
||||||
sizecache(b, b->cnc+m);
|
sizecache(b, b->cnc + m);
|
||||||
runemove(b->c+b->cnc, s, m);
|
runemove(b->c + b->cnc, s, m);
|
||||||
b->cnc += m;
|
b->cnc += m;
|
||||||
Tail:
|
Tail:
|
||||||
b->nc += m;
|
b->nc += m;
|
||||||
|
@ -200,23 +182,21 @@ bufinsert(Buffer *b, uint q0, Rune *s, uint n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void bufdelete(Buffer* b, uint q0, uint q1) {
|
||||||
bufdelete(Buffer *b, uint q0, uint q1)
|
|
||||||
{
|
|
||||||
uint m, n, off;
|
uint m, n, off;
|
||||||
|
|
||||||
if(!(q0<=q1 && q0<=b->nc && q1<=b->nc))
|
if (!(q0 <= q1 && q0 <= b->nc && q1 <= b->nc))
|
||||||
error("internal error: bufdelete");
|
error("internal error: bufdelete");
|
||||||
while(q1 > q0){
|
while (q1 > q0) {
|
||||||
setcache(b, q0);
|
setcache(b, q0);
|
||||||
off = q0-b->cq;
|
off = q0 - b->cq;
|
||||||
if(q1 > b->cq+b->cnc)
|
if (q1 > b->cq + b->cnc)
|
||||||
n = b->cnc - off;
|
n = b->cnc - off;
|
||||||
else
|
else
|
||||||
n = q1-q0;
|
n = q1 - q0;
|
||||||
m = b->cnc - (off+n);
|
m = b->cnc - (off + n);
|
||||||
if(m > 0)
|
if (m > 0)
|
||||||
runemove(b->c+off, b->c+off+n, m);
|
runemove(b->c + off, b->c + off + n, m);
|
||||||
b->cnc -= n;
|
b->cnc -= n;
|
||||||
b->cdirty = TRUE;
|
b->cdirty = TRUE;
|
||||||
q1 -= n;
|
q1 -= n;
|
||||||
|
@ -224,22 +204,20 @@ bufdelete(Buffer *b, uint q0, uint q1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int bufloader(void* v, uint q0, Rune* r, int nr) {
|
||||||
bufloader(void *v, uint q0, Rune *r, int nr)
|
|
||||||
{
|
|
||||||
bufinsert(v, q0, r, nr);
|
bufinsert(v, q0, r, nr);
|
||||||
return nr;
|
return nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint loadfile(
|
||||||
loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg, DigestState *h)
|
int fd, uint q0, int* nulls, int (*f)(void*, uint, Rune*, int), void* arg,
|
||||||
{
|
DigestState* h) {
|
||||||
char *p;
|
char* p;
|
||||||
Rune *r;
|
Rune* r;
|
||||||
int l, m, n, nb, nr;
|
int l, m, n, nb, nr;
|
||||||
uint q1;
|
uint q1;
|
||||||
|
|
||||||
p = emalloc((Maxblock+UTFmax+1)*sizeof p[0]);
|
p = emalloc((Maxblock + UTFmax + 1) * sizeof p[0]);
|
||||||
r = runemalloc(Maxblock);
|
r = runemalloc(Maxblock);
|
||||||
m = 0;
|
m = 0;
|
||||||
n = 1;
|
n = 1;
|
||||||
|
@ -248,58 +226,52 @@ loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *ar
|
||||||
* At top of loop, may have m bytes left over from
|
* At top of loop, may have m bytes left over from
|
||||||
* last pass, possibly representing a partial rune.
|
* last pass, possibly representing a partial rune.
|
||||||
*/
|
*/
|
||||||
while(n > 0){
|
while (n > 0) {
|
||||||
n = read(fd, p+m, Maxblock);
|
n = read(fd, p + m, Maxblock);
|
||||||
if(n < 0){
|
if (n < 0) {
|
||||||
warning(nil, "read error in Buffer.load");
|
warning(nil, "read error in Buffer.load");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(h != nil)
|
if (h != nil)
|
||||||
sha1((uchar*)p+m, n, nil, h);
|
sha1((uchar*)p + m, n, nil, h);
|
||||||
m += n;
|
m += n;
|
||||||
p[m] = 0;
|
p[m] = 0;
|
||||||
l = m;
|
l = m;
|
||||||
if(n > 0)
|
if (n > 0)
|
||||||
l -= UTFmax;
|
l -= UTFmax;
|
||||||
cvttorunes(p, l, r, &nb, &nr, nulls);
|
cvttorunes(p, l, r, &nb, &nr, nulls);
|
||||||
memmove(p, p+nb, m-nb);
|
memmove(p, p + nb, m - nb);
|
||||||
m -= nb;
|
m -= nb;
|
||||||
q1 += (*f)(arg, q1, r, nr);
|
q1 += (*f)(arg, q1, r, nr);
|
||||||
}
|
}
|
||||||
free(p);
|
free(p);
|
||||||
free(r);
|
free(r);
|
||||||
return q1-q0;
|
return q1 - q0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint bufload(Buffer* b, uint q0, int fd, int* nulls, DigestState* h) {
|
||||||
bufload(Buffer *b, uint q0, int fd, int *nulls, DigestState *h)
|
if (q0 > b->nc)
|
||||||
{
|
|
||||||
if(q0 > b->nc)
|
|
||||||
error("internal error: bufload");
|
error("internal error: bufload");
|
||||||
return loadfile(fd, q0, nulls, bufloader, b, h);
|
return loadfile(fd, q0, nulls, bufloader, b, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void bufread(Buffer* b, uint q0, Rune* s, uint n) {
|
||||||
bufread(Buffer *b, uint q0, Rune *s, uint n)
|
|
||||||
{
|
|
||||||
uint m;
|
uint m;
|
||||||
|
|
||||||
if(!(q0<=b->nc && q0+n<=b->nc))
|
if (!(q0 <= b->nc && q0 + n <= b->nc))
|
||||||
error("bufread: internal error");
|
error("bufread: internal error");
|
||||||
|
|
||||||
while(n > 0){
|
while (n > 0) {
|
||||||
setcache(b, q0);
|
setcache(b, q0);
|
||||||
m = min(n, b->cnc-(q0-b->cq));
|
m = min(n, b->cnc - (q0 - b->cq));
|
||||||
runemove(s, b->c+(q0-b->cq), m);
|
runemove(s, b->c + (q0 - b->cq), m);
|
||||||
q0 += m;
|
q0 += m;
|
||||||
s += m;
|
s += m;
|
||||||
n -= m;
|
n -= m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void bufreset(Buffer* b) {
|
||||||
bufreset(Buffer *b)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
b->nc = 0;
|
b->nc = 0;
|
||||||
|
@ -308,13 +280,11 @@ bufreset(Buffer *b)
|
||||||
b->cdirty = 0;
|
b->cdirty = 0;
|
||||||
b->cbi = 0;
|
b->cbi = 0;
|
||||||
/* delete backwards to avoid n² behavior */
|
/* delete backwards to avoid n² behavior */
|
||||||
for(i=b->nbl-1; --i>=0; )
|
for (i = b->nbl - 1; --i >= 0;)
|
||||||
delblock(b, i);
|
delblock(b, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void bufclose(Buffer* b) {
|
||||||
bufclose(Buffer *b)
|
|
||||||
{
|
|
||||||
bufreset(b);
|
bufreset(b);
|
||||||
free(b->c);
|
free(b->c);
|
||||||
b->c = nil;
|
b->c = nil;
|
||||||
|
|
8
build.sh
Executable file
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
|
433
cols.c
433
cols.c
|
@ -12,24 +12,21 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
static Rune Lheader[] = {
|
static Rune Lheader[] = {'N', 'e', 'w', ' ', 'C', 'u', 't', ' ', 'P', 'a',
|
||||||
'N', 'e', 'w', ' ',
|
's', 't', 'e', ' ', 'S', 'n', 'a', 'r', 'f', ' ',
|
||||||
'C', 'u', 't', ' ',
|
'S', 'o', 'r', 't', ' ', 'Z', 'e', 'r', 'o', 'x',
|
||||||
'P', 'a', 's', 't', 'e', ' ',
|
' ', 'D', 'e', 'l', 'c', 'o', 'l', ' ', 0};
|
||||||
'S', 'n', 'a', 'r', 'f', ' ',
|
|
||||||
'S', 'o', 'r', 't', ' ',
|
|
||||||
'Z', 'e', 'r', 'o', 'x', ' ',
|
|
||||||
'D', 'e', 'l', 'c', 'o', 'l', ' ',
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
void colinit(Column* c, Rectangle r) {
|
||||||
colinit(Column *c, Rectangle r)
|
|
||||||
{
|
|
||||||
Rectangle r1;
|
Rectangle r1;
|
||||||
Text *t;
|
Text* t;
|
||||||
|
|
||||||
draw(screen, r, allocimage(display,Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
c->r = r;
|
c->r = r;
|
||||||
c->w = nil;
|
c->w = nil;
|
||||||
c->nw = 0;
|
c->nw = 0;
|
||||||
|
@ -42,44 +39,47 @@ colinit(Column *c, Rectangle r)
|
||||||
t->what = Columntag;
|
t->what = Columntag;
|
||||||
r1.min.y = r1.max.y;
|
r1.min.y = r1.max.y;
|
||||||
r1.max.y += Border;
|
r1.max.y += Border;
|
||||||
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r1,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
textinsert(t, 0, Lheader, 38, TRUE);
|
textinsert(t, 0, Lheader, 38, TRUE);
|
||||||
textsetselect(t, t->file->b.nc, t->file->b.nc);
|
textsetselect(t, t->file->b.nc, t->file->b.nc);
|
||||||
draw(screen, t->scrollr, colbutton, nil, colbutton->r.min);
|
draw(screen, t->scrollr, colbutton, nil, colbutton->r.min);
|
||||||
c->safe = TRUE;
|
c->safe = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Window*
|
Window* coladd(Column* c, Window* w, Window* clone, int y) {
|
||||||
coladd(Column *c, Window *w, Window *clone, int y)
|
|
||||||
{
|
|
||||||
Rectangle r, r1;
|
Rectangle r, r1;
|
||||||
Window *v;
|
Window* v;
|
||||||
int i, j, minht, ymax, buggered;
|
int i, j, minht, ymax, buggered;
|
||||||
|
|
||||||
v = nil;
|
v = nil;
|
||||||
r = c->r;
|
r = c->r;
|
||||||
r.min.y = c->tag.fr.r.max.y+Border;
|
r.min.y = c->tag.fr.r.max.y + Border;
|
||||||
if(y<r.min.y && c->nw>0){ /* steal half of last window by default */
|
if (y < r.min.y && c->nw > 0) { /* steal half of last window by default */
|
||||||
v = c->w[c->nw-1];
|
v = c->w[c->nw - 1];
|
||||||
y = v->body.fr.r.min.y+Dy(v->body.fr.r)/2;
|
y = v->body.fr.r.min.y + Dy(v->body.fr.r) / 2;
|
||||||
}
|
}
|
||||||
/* look for window we'll land on */
|
/* look for window we'll land on */
|
||||||
for(i=0; i<c->nw; i++){
|
for (i = 0; i < c->nw; i++) {
|
||||||
v = c->w[i];
|
v = c->w[i];
|
||||||
if(y < v->r.max.y)
|
if (y < v->r.max.y)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
buggered = 0;
|
buggered = 0;
|
||||||
if(c->nw > 0){
|
if (c->nw > 0) {
|
||||||
if(i < c->nw)
|
if (i < c->nw)
|
||||||
i++; /* new window will go after v */
|
i++; /* new window will go after v */
|
||||||
/*
|
/*
|
||||||
* if landing window (v) is too small, grow it first.
|
* if landing window (v) is too small, grow it first.
|
||||||
*/
|
*/
|
||||||
minht = v->tag.fr.font->height+Border+1;
|
minht = v->tag.fr.font->height + Border + 1;
|
||||||
j = 0;
|
j = 0;
|
||||||
while(!c->safe || v->body.fr.maxlines<=3 || Dy(v->body.all) <= minht){
|
while (!c->safe || v->body.fr.maxlines <= 3 || Dy(v->body.all) <= minht) {
|
||||||
if(++j > 10){
|
if (++j > 10) {
|
||||||
buggered = 1; /* too many windows in column */
|
buggered = 1; /* too many windows in column */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -91,19 +91,19 @@ coladd(Column *c, Window *w, Window *clone, int y)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* new window stops where next window begins */
|
/* new window stops where next window begins */
|
||||||
if(i < c->nw)
|
if (i < c->nw)
|
||||||
ymax = c->w[i]->r.min.y-Border;
|
ymax = c->w[i]->r.min.y - Border;
|
||||||
else
|
else
|
||||||
ymax = c->r.max.y;
|
ymax = c->r.max.y;
|
||||||
|
|
||||||
/* new window must start after v's tag ends */
|
/* new window must start after v's tag ends */
|
||||||
y = max(y, v->tagtop.max.y+Border);
|
y = max(y, v->tagtop.max.y + Border);
|
||||||
|
|
||||||
/* new window must start early enough to end before ymax */
|
/* new window must start early enough to end before ymax */
|
||||||
y = min(y, ymax - minht);
|
y = min(y, ymax - minht);
|
||||||
|
|
||||||
/* if y is too small, too many windows in column */
|
/* if y is too small, too many windows in column */
|
||||||
if(y < v->tagtop.max.y+Border)
|
if (y < v->tagtop.max.y + Border)
|
||||||
buggered = 1;
|
buggered = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -113,23 +113,32 @@ coladd(Column *c, Window *w, Window *clone, int y)
|
||||||
r.max.y = ymax;
|
r.max.y = ymax;
|
||||||
draw(screen, r, textcols[BACK], nil, ZP);
|
draw(screen, r, textcols[BACK], nil, ZP);
|
||||||
r1 = r;
|
r1 = r;
|
||||||
y = min(y, ymax-(v->tag.fr.font->height*v->taglines+v->body.fr.font->height+Border+1));
|
y = min(
|
||||||
r1.max.y = min(y, v->body.fr.r.min.y+v->body.fr.nlines*v->body.fr.font->height);
|
y,
|
||||||
|
ymax - (v->tag.fr.font->height * v->taglines + v->body.fr.font->height +
|
||||||
|
Border + 1));
|
||||||
|
r1.max.y =
|
||||||
|
min(y, v->body.fr.r.min.y + v->body.fr.nlines * v->body.fr.font->height);
|
||||||
r1.min.y = winresize(v, r1, FALSE, FALSE);
|
r1.min.y = winresize(v, r1, FALSE, FALSE);
|
||||||
r1.max.y = r1.min.y+Border;
|
r1.max.y = r1.min.y + Border;
|
||||||
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r1,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* leave r with w's coordinates
|
* leave r with w's coordinates
|
||||||
*/
|
*/
|
||||||
r.min.y = r1.max.y;
|
r.min.y = r1.max.y;
|
||||||
}
|
}
|
||||||
if(w == nil){
|
if (w == nil) {
|
||||||
w = emalloc(sizeof(Window));
|
w = emalloc(sizeof(Window));
|
||||||
w->col = c;
|
w->col = c;
|
||||||
draw(screen, r, textcols[BACK], nil, ZP);
|
draw(screen, r, textcols[BACK], nil, ZP);
|
||||||
wininit(w, clone, r);
|
wininit(w, clone, r);
|
||||||
}else{
|
} else {
|
||||||
w->col = c;
|
w->col = c;
|
||||||
winresize(w, r, FALSE, TRUE);
|
winresize(w, r, FALSE, TRUE);
|
||||||
}
|
}
|
||||||
|
@ -137,14 +146,14 @@ coladd(Column *c, Window *w, Window *clone, int y)
|
||||||
w->tag.row = c->row;
|
w->tag.row = c->row;
|
||||||
w->body.col = c;
|
w->body.col = c;
|
||||||
w->body.row = c->row;
|
w->body.row = c->row;
|
||||||
c->w = realloc(c->w, (c->nw+1)*sizeof(Window*));
|
c->w = realloc(c->w, (c->nw + 1) * sizeof(Window*));
|
||||||
memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*));
|
memmove(c->w + i + 1, c->w + i, (c->nw - i) * sizeof(Window*));
|
||||||
c->nw++;
|
c->nw++;
|
||||||
c->w[i] = w;
|
c->w[i] = w;
|
||||||
c->safe = TRUE;
|
c->safe = TRUE;
|
||||||
|
|
||||||
/* if there were too many windows, redraw the whole column */
|
/* if there were too many windows, redraw the whole column */
|
||||||
if(buggered)
|
if (buggered)
|
||||||
colresize(c, c->r);
|
colresize(c, c->r);
|
||||||
|
|
||||||
savemouse(w);
|
savemouse(w);
|
||||||
|
@ -154,66 +163,67 @@ coladd(Column *c, Window *w, Window *clone, int y)
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void colclose(Column* c, Window* w, int dofree) {
|
||||||
colclose(Column *c, Window *w, int dofree)
|
|
||||||
{
|
|
||||||
Rectangle r;
|
Rectangle r;
|
||||||
int i, didmouse, up;
|
int i, didmouse, up;
|
||||||
|
|
||||||
/* w is locked */
|
/* w is locked */
|
||||||
if(!c->safe)
|
if (!c->safe)
|
||||||
colgrow(c, w, 1);
|
colgrow(c, w, 1);
|
||||||
for(i=0; i<c->nw; i++)
|
for (i = 0; i < c->nw; i++)
|
||||||
if(c->w[i] == w)
|
if (c->w[i] == w)
|
||||||
goto Found;
|
goto Found;
|
||||||
error("can't find window");
|
error("can't find window");
|
||||||
Found:
|
Found:
|
||||||
r = w->r;
|
r = w->r;
|
||||||
w->tag.col = nil;
|
w->tag.col = nil;
|
||||||
w->body.col = nil;
|
w->body.col = nil;
|
||||||
w->col = nil;
|
w->col = nil;
|
||||||
didmouse = restoremouse(w);
|
didmouse = restoremouse(w);
|
||||||
if(dofree){
|
if (dofree) {
|
||||||
windelete(w);
|
windelete(w);
|
||||||
winclose(w);
|
winclose(w);
|
||||||
}
|
}
|
||||||
c->nw--;
|
c->nw--;
|
||||||
memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*));
|
memmove(c->w + i, c->w + i + 1, (c->nw - i) * sizeof(Window*));
|
||||||
c->w = realloc(c->w, c->nw*sizeof(Window*));
|
c->w = realloc(c->w, c->nw * sizeof(Window*));
|
||||||
if(c->nw == 0){
|
if (c->nw == 0) {
|
||||||
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
up = 0;
|
up = 0;
|
||||||
if(i == c->nw){ /* extend last window down */
|
if (i == c->nw) { /* extend last window down */
|
||||||
w = c->w[i-1];
|
w = c->w[i - 1];
|
||||||
r.min.y = w->r.min.y;
|
r.min.y = w->r.min.y;
|
||||||
r.max.y = c->r.max.y;
|
r.max.y = c->r.max.y;
|
||||||
}else{ /* extend next window up */
|
} else { /* extend next window up */
|
||||||
up = 1;
|
up = 1;
|
||||||
w = c->w[i];
|
w = c->w[i];
|
||||||
r.max.y = w->r.max.y;
|
r.max.y = w->r.max.y;
|
||||||
}
|
}
|
||||||
draw(screen, r, textcols[BACK], nil, ZP);
|
draw(screen, r, textcols[BACK], nil, ZP);
|
||||||
if(c->safe) {
|
if (c->safe) {
|
||||||
if(!didmouse && up)
|
if (!didmouse && up)
|
||||||
w->showdel = TRUE;
|
w->showdel = TRUE;
|
||||||
winresize(w, r, FALSE, TRUE);
|
winresize(w, r, FALSE, TRUE);
|
||||||
if(!didmouse && up)
|
if (!didmouse && up)
|
||||||
movetodel(w);
|
movetodel(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void colcloseall(Column* c) {
|
||||||
colcloseall(Column *c)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
Window *w;
|
Window* w;
|
||||||
|
|
||||||
if(c == activecol)
|
if (c == activecol)
|
||||||
activecol = nil;
|
activecol = nil;
|
||||||
textclose(&c->tag);
|
textclose(&c->tag);
|
||||||
for(i=0; i<c->nw; i++){
|
for (i = 0; i < c->nw; i++) {
|
||||||
w = c->w[i];
|
w = c->w[i];
|
||||||
winclose(w);
|
winclose(w);
|
||||||
}
|
}
|
||||||
|
@ -223,18 +233,14 @@ colcloseall(Column *c)
|
||||||
clearmouse();
|
clearmouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void colmousebut(Column* c) {
|
||||||
colmousebut(Column *c)
|
|
||||||
{
|
|
||||||
moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2));
|
moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void colresize(Column* c, Rectangle r) {
|
||||||
colresize(Column *c, Rectangle r)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
Rectangle r1, r2;
|
Rectangle r1, r2;
|
||||||
Window *w;
|
Window* w;
|
||||||
|
|
||||||
clearmouse();
|
clearmouse();
|
||||||
r1 = r;
|
r1 = r;
|
||||||
|
@ -243,33 +249,40 @@ colresize(Column *c, Rectangle r)
|
||||||
draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
|
draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
|
||||||
r1.min.y = r1.max.y;
|
r1.min.y = r1.max.y;
|
||||||
r1.max.y += Border;
|
r1.max.y += Border;
|
||||||
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r1,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
r1.max.y = r.max.y;
|
r1.max.y = r.max.y;
|
||||||
for(i=0; i<c->nw; i++){
|
for (i = 0; i < c->nw; i++) {
|
||||||
w = c->w[i];
|
w = c->w[i];
|
||||||
w->maxlines = 0;
|
w->maxlines = 0;
|
||||||
if(i == c->nw-1)
|
if (i == c->nw - 1)
|
||||||
r1.max.y = r.max.y;
|
r1.max.y = r.max.y;
|
||||||
else{
|
else {
|
||||||
r1.max.y = r1.min.y;
|
r1.max.y = r1.min.y;
|
||||||
if(Dy(c->r) != 0){
|
if (Dy(c->r) != 0) {
|
||||||
r1.max.y += (Dy(w->r)+Border)*Dy(r)/Dy(c->r);
|
r1.max.y += (Dy(w->r) + Border) * Dy(r) / Dy(c->r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r1.max.y = max(r1.max.y, r1.min.y + Border+font->height);
|
r1.max.y = max(r1.max.y, r1.min.y + Border + font->height);
|
||||||
r2 = r1;
|
r2 = r1;
|
||||||
r2.max.y = r2.min.y+Border;
|
r2.max.y = r2.min.y + Border;
|
||||||
draw(screen, r2, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r2,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
r1.min.y = r2.max.y;
|
r1.min.y = r2.max.y;
|
||||||
r1.min.y = winresize(w, r1, FALSE, i==c->nw-1);
|
r1.min.y = winresize(w, r1, FALSE, i == c->nw - 1);
|
||||||
}
|
}
|
||||||
c->r = r;
|
c->r = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int colcmp(const void* a, const void* b) {
|
||||||
int
|
|
||||||
colcmp(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
Rune *r1, *r2;
|
Rune *r1, *r2;
|
||||||
int i, nr1, nr2;
|
int i, nr1, nr2;
|
||||||
|
|
||||||
|
@ -277,86 +290,87 @@ colcmp(const void *a, const void *b)
|
||||||
nr1 = (*(Window**)a)->body.file->nname;
|
nr1 = (*(Window**)a)->body.file->nname;
|
||||||
r2 = (*(Window**)b)->body.file->name;
|
r2 = (*(Window**)b)->body.file->name;
|
||||||
nr2 = (*(Window**)b)->body.file->nname;
|
nr2 = (*(Window**)b)->body.file->nname;
|
||||||
for(i=0; i<nr1 && i<nr2; i++){
|
for (i = 0; i < nr1 && i < nr2; i++) {
|
||||||
if(*r1 != *r2)
|
if (*r1 != *r2)
|
||||||
return *r1-*r2;
|
return *r1 - *r2;
|
||||||
r1++;
|
r1++;
|
||||||
r2++;
|
r2++;
|
||||||
}
|
}
|
||||||
return nr1-nr2;
|
return nr1 - nr2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void colsort(Column* c) {
|
||||||
colsort(Column *c)
|
|
||||||
{
|
|
||||||
int i, y;
|
int i, y;
|
||||||
Rectangle r, r1, *rp;
|
Rectangle r, r1, *rp;
|
||||||
Window **wp, *w;
|
Window **wp, *w;
|
||||||
|
|
||||||
if(c->nw == 0)
|
if (c->nw == 0)
|
||||||
return;
|
return;
|
||||||
clearmouse();
|
clearmouse();
|
||||||
rp = emalloc(c->nw*sizeof(Rectangle));
|
rp = emalloc(c->nw * sizeof(Rectangle));
|
||||||
wp = emalloc(c->nw*sizeof(Window*));
|
wp = emalloc(c->nw * sizeof(Window*));
|
||||||
memmove(wp, c->w, c->nw*sizeof(Window*));
|
memmove(wp, c->w, c->nw * sizeof(Window*));
|
||||||
qsort(wp, c->nw, sizeof(Window*), colcmp);
|
qsort(wp, c->nw, sizeof(Window*), colcmp);
|
||||||
for(i=0; i<c->nw; i++)
|
for (i = 0; i < c->nw; i++)
|
||||||
rp[i] = wp[i]->r;
|
rp[i] = wp[i]->r;
|
||||||
r = c->r;
|
r = c->r;
|
||||||
r.min.y = c->tag.fr.r.max.y;
|
r.min.y = c->tag.fr.r.max.y;
|
||||||
draw(screen, r, textcols[BACK], nil, ZP);
|
draw(screen, r, textcols[BACK], nil, ZP);
|
||||||
y = r.min.y;
|
y = r.min.y;
|
||||||
for(i=0; i<c->nw; i++){
|
for (i = 0; i < c->nw; i++) {
|
||||||
w = wp[i];
|
w = wp[i];
|
||||||
r.min.y = y;
|
r.min.y = y;
|
||||||
if(i == c->nw-1)
|
if (i == c->nw - 1)
|
||||||
r.max.y = c->r.max.y;
|
r.max.y = c->r.max.y;
|
||||||
else
|
else
|
||||||
r.max.y = r.min.y+Dy(w->r)+Border;
|
r.max.y = r.min.y + Dy(w->r) + Border;
|
||||||
r1 = r;
|
r1 = r;
|
||||||
r1.max.y = r1.min.y+Border;
|
r1.max.y = r1.min.y + Border;
|
||||||
draw(screen, r1, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r1,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
r.min.y = r1.max.y;
|
r.min.y = r1.max.y;
|
||||||
y = winresize(w, r, FALSE, i==c->nw-1);
|
y = winresize(w, r, FALSE, i == c->nw - 1);
|
||||||
}
|
}
|
||||||
free(rp);
|
free(rp);
|
||||||
free(c->w);
|
free(c->w);
|
||||||
c->w = wp;
|
c->w = wp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void colgrow(Column* c, Window* w, int but) {
|
||||||
colgrow(Column *c, Window *w, int but)
|
|
||||||
{
|
|
||||||
Rectangle r, cr;
|
Rectangle r, cr;
|
||||||
int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h;
|
int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h;
|
||||||
Window *v;
|
Window* v;
|
||||||
|
|
||||||
for(i=0; i<c->nw; i++)
|
for (i = 0; i < c->nw; i++)
|
||||||
if(c->w[i] == w)
|
if (c->w[i] == w)
|
||||||
goto Found;
|
goto Found;
|
||||||
error("can't find window");
|
error("can't find window");
|
||||||
|
|
||||||
Found:
|
Found:
|
||||||
cr = c->r;
|
cr = c->r;
|
||||||
if(but < 0){ /* make sure window fills its own space properly */
|
if (but < 0) { /* make sure window fills its own space properly */
|
||||||
r = w->r;
|
r = w->r;
|
||||||
if(i==c->nw-1 || c->safe==FALSE)
|
if (i == c->nw - 1 || c->safe == FALSE)
|
||||||
r.max.y = cr.max.y;
|
r.max.y = cr.max.y;
|
||||||
else
|
else
|
||||||
r.max.y = c->w[i+1]->r.min.y - Border;
|
r.max.y = c->w[i + 1]->r.min.y - Border;
|
||||||
winresize(w, r, FALSE, TRUE);
|
winresize(w, r, FALSE, TRUE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cr.min.y = c->w[0]->r.min.y;
|
cr.min.y = c->w[0]->r.min.y;
|
||||||
if(but == 3){ /* full size */
|
if (but == 3) { /* full size */
|
||||||
if(i != 0){
|
if (i != 0) {
|
||||||
v = c->w[0];
|
v = c->w[0];
|
||||||
c->w[0] = w;
|
c->w[0] = w;
|
||||||
c->w[i] = v;
|
c->w[i] = v;
|
||||||
}
|
}
|
||||||
draw(screen, cr, textcols[BACK], nil, ZP);
|
draw(screen, cr, textcols[BACK], nil, ZP);
|
||||||
winresize(w, cr, FALSE, TRUE);
|
winresize(w, cr, FALSE, TRUE);
|
||||||
for(i=1; i<c->nw; i++)
|
for (i = 1; i < c->nw; i++)
|
||||||
c->w[i]->body.fr.maxlines = 0;
|
c->w[i]->body.fr.maxlines = 0;
|
||||||
c->safe = FALSE;
|
c->safe = FALSE;
|
||||||
return;
|
return;
|
||||||
|
@ -366,64 +380,69 @@ colgrow(Column *c, Window *w, int but)
|
||||||
nl = emalloc(c->nw * sizeof(int));
|
nl = emalloc(c->nw * sizeof(int));
|
||||||
ny = emalloc(c->nw * sizeof(int));
|
ny = emalloc(c->nw * sizeof(int));
|
||||||
tot = 0;
|
tot = 0;
|
||||||
for(j=0; j<c->nw; j++){
|
for (j = 0; j < c->nw; j++) {
|
||||||
l = c->w[j]->taglines-1 + c->w[j]->body.fr.maxlines;
|
l = c->w[j]->taglines - 1 + c->w[j]->body.fr.maxlines;
|
||||||
nl[j] = l;
|
nl[j] = l;
|
||||||
tot += l;
|
tot += l;
|
||||||
}
|
}
|
||||||
/* approximate new #lines for this window */
|
/* approximate new #lines for this window */
|
||||||
if(but == 2){ /* as big as can be */
|
if (but == 2) { /* as big as can be */
|
||||||
memset(nl, 0, c->nw * sizeof(int));
|
memset(nl, 0, c->nw * sizeof(int));
|
||||||
goto Pack;
|
goto Pack;
|
||||||
}
|
}
|
||||||
nnl = min(onl + max(min(5, w->taglines-1+w->maxlines), onl/2), tot);
|
nnl = min(onl + max(min(5, w->taglines - 1 + w->maxlines), onl / 2), tot);
|
||||||
if(nnl < w->taglines-1+w->maxlines)
|
if (nnl < w->taglines - 1 + w->maxlines)
|
||||||
nnl = (w->taglines-1+w->maxlines + nnl)/2;
|
nnl = (w->taglines - 1 + w->maxlines + nnl) / 2;
|
||||||
if(nnl == 0)
|
if (nnl == 0)
|
||||||
nnl = 2;
|
nnl = 2;
|
||||||
dnl = nnl - onl;
|
dnl = nnl - onl;
|
||||||
/* compute new #lines for each window */
|
/* compute new #lines for each window */
|
||||||
for(k=1; k<c->nw; k++){
|
for (k = 1; k < c->nw; k++) {
|
||||||
/* prune from later window */
|
/* prune from later window */
|
||||||
j = i+k;
|
j = i + k;
|
||||||
if(j<c->nw && nl[j]){
|
if (j < c->nw && nl[j]) {
|
||||||
l = min(dnl, max(1, nl[j]/2));
|
l = min(dnl, max(1, nl[j] / 2));
|
||||||
nl[j] -= l;
|
nl[j] -= l;
|
||||||
nl[i] += l;
|
nl[i] += l;
|
||||||
dnl -= l;
|
dnl -= l;
|
||||||
}
|
}
|
||||||
/* prune from earlier window */
|
/* prune from earlier window */
|
||||||
j = i-k;
|
j = i - k;
|
||||||
if(j>=0 && nl[j]){
|
if (j >= 0 && nl[j]) {
|
||||||
l = min(dnl, max(1, nl[j]/2));
|
l = min(dnl, max(1, nl[j] / 2));
|
||||||
nl[j] -= l;
|
nl[j] -= l;
|
||||||
nl[i] += l;
|
nl[i] += l;
|
||||||
dnl -= l;
|
dnl -= l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pack:
|
Pack:
|
||||||
/* pack everyone above */
|
/* pack everyone above */
|
||||||
y1 = cr.min.y;
|
y1 = cr.min.y;
|
||||||
for(j=0; j<i; j++){
|
for (j = 0; j < i; j++) {
|
||||||
v = c->w[j];
|
v = c->w[j];
|
||||||
r = v->r;
|
r = v->r;
|
||||||
r.min.y = y1;
|
r.min.y = y1;
|
||||||
r.max.y = y1+Dy(v->tagtop);
|
r.max.y = y1 + Dy(v->tagtop);
|
||||||
if(nl[j])
|
if (nl[j])
|
||||||
r.max.y += 1 + nl[j]*v->body.fr.font->height;
|
r.max.y += 1 + nl[j] * v->body.fr.font->height;
|
||||||
r.min.y = winresize(v, r, c->safe, FALSE);
|
r.min.y = winresize(v, r, c->safe, FALSE);
|
||||||
r.max.y += Border;
|
r.max.y += Border;
|
||||||
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
y1 = r.max.y;
|
y1 = r.max.y;
|
||||||
}
|
}
|
||||||
/* scan to see new size of everyone below */
|
/* scan to see new size of everyone below */
|
||||||
y2 = c->r.max.y;
|
y2 = c->r.max.y;
|
||||||
for(j=c->nw-1; j>i; j--){
|
for (j = c->nw - 1; j > i; j--) {
|
||||||
v = c->w[j];
|
v = c->w[j];
|
||||||
r = v->r;
|
r = v->r;
|
||||||
r.min.y = y2-Dy(v->tagtop);
|
r.min.y = y2 - Dy(v->tagtop);
|
||||||
if(nl[j])
|
if (nl[j])
|
||||||
r.min.y -= 1 + nl[j]*v->body.fr.font->height;
|
r.min.y -= 1 + nl[j] * v->body.fr.font->height;
|
||||||
r.min.y -= Border;
|
r.min.y -= Border;
|
||||||
ny[j] = r.min.y;
|
ny[j] = r.min.y;
|
||||||
y2 = r.min.y;
|
y2 = r.min.y;
|
||||||
|
@ -433,31 +452,41 @@ colgrow(Column *c, Window *w, int but)
|
||||||
r.min.y = y1;
|
r.min.y = y1;
|
||||||
r.max.y = y2;
|
r.max.y = y2;
|
||||||
h = w->body.fr.font->height;
|
h = w->body.fr.font->height;
|
||||||
if(Dy(r) < Dy(w->tagtop)+1+h+Border)
|
if (Dy(r) < Dy(w->tagtop) + 1 + h + Border)
|
||||||
r.max.y = r.min.y + Dy(w->tagtop)+1+h+Border;
|
r.max.y = r.min.y + Dy(w->tagtop) + 1 + h + Border;
|
||||||
/* draw window */
|
/* draw window */
|
||||||
r.max.y = winresize(w, r, c->safe, TRUE);
|
r.max.y = winresize(w, r, c->safe, TRUE);
|
||||||
if(i < c->nw-1){
|
if (i < c->nw - 1) {
|
||||||
r.min.y = r.max.y;
|
r.min.y = r.max.y;
|
||||||
r.max.y += Border;
|
r.max.y += Border;
|
||||||
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
for(j=i+1; j<c->nw; j++)
|
screen,
|
||||||
ny[j] -= (y2-r.max.y);
|
r,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
|
for (j = i + 1; j < c->nw; j++)
|
||||||
|
ny[j] -= (y2 - r.max.y);
|
||||||
}
|
}
|
||||||
/* pack everyone below */
|
/* pack everyone below */
|
||||||
y1 = r.max.y;
|
y1 = r.max.y;
|
||||||
for(j=i+1; j<c->nw; j++){
|
for (j = i + 1; j < c->nw; j++) {
|
||||||
v = c->w[j];
|
v = c->w[j];
|
||||||
r = v->r;
|
r = v->r;
|
||||||
r.min.y = y1;
|
r.min.y = y1;
|
||||||
r.max.y = y1+Dy(v->tagtop);
|
r.max.y = y1 + Dy(v->tagtop);
|
||||||
if(nl[j])
|
if (nl[j])
|
||||||
r.max.y += 1 + nl[j]*v->body.fr.font->height;
|
r.max.y += 1 + nl[j] * v->body.fr.font->height;
|
||||||
y1 = winresize(v, r, c->safe, j==c->nw-1);
|
y1 = winresize(v, r, c->safe, j == c->nw - 1);
|
||||||
if(j < c->nw-1){ /* no border on last window */
|
if (j < c->nw - 1) { /* no border on last window */
|
||||||
r.min.y = y1;
|
r.min.y = y1;
|
||||||
r.max.y += Border;
|
r.max.y += Border;
|
||||||
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
y1 = r.max.y;
|
y1 = r.max.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,106 +496,108 @@ colgrow(Column *c, Window *w, int but)
|
||||||
winmousebut(w);
|
winmousebut(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void coldragwin(Column* c, Window* w, int but) {
|
||||||
coldragwin(Column *c, Window *w, int but)
|
|
||||||
{
|
|
||||||
Rectangle r;
|
Rectangle r;
|
||||||
int i, b;
|
int i, b;
|
||||||
Point p, op;
|
Point p, op;
|
||||||
Window *v;
|
Window* v;
|
||||||
Column *nc;
|
Column* nc;
|
||||||
|
|
||||||
clearmouse();
|
clearmouse();
|
||||||
setcursor2(mousectl, &boxcursor, &boxcursor2);
|
setcursor2(mousectl, &boxcursor, &boxcursor2);
|
||||||
b = mouse->buttons;
|
b = mouse->buttons;
|
||||||
op = mouse->xy;
|
op = mouse->xy;
|
||||||
while(mouse->buttons == b)
|
while (mouse->buttons == b)
|
||||||
readmouse(mousectl);
|
readmouse(mousectl);
|
||||||
setcursor(mousectl, nil);
|
setcursor(mousectl, nil);
|
||||||
if(mouse->buttons){
|
if (mouse->buttons) {
|
||||||
while(mouse->buttons)
|
while (mouse->buttons)
|
||||||
readmouse(mousectl);
|
readmouse(mousectl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0; i<c->nw; i++)
|
for (i = 0; i < c->nw; i++)
|
||||||
if(c->w[i] == w)
|
if (c->w[i] == w)
|
||||||
goto Found;
|
goto Found;
|
||||||
error("can't find window");
|
error("can't find window");
|
||||||
|
|
||||||
Found:
|
Found:
|
||||||
if(w->tagexpand) /* force recomputation of window tag size */
|
if (w->tagexpand) /* force recomputation of window tag size */
|
||||||
w->taglines = 1;
|
w->taglines = 1;
|
||||||
p = mouse->xy;
|
p = mouse->xy;
|
||||||
if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
|
if (abs(p.x - op.x) < 5 && abs(p.y - op.y) < 5) {
|
||||||
colgrow(c, w, but);
|
colgrow(c, w, but);
|
||||||
winmousebut(w);
|
winmousebut(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* is it a flick to the right? */
|
/* is it a flick to the right? */
|
||||||
if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c)
|
if (abs(p.y - op.y) < 10 && p.x > op.x + 30 && rowwhichcol(c->row, p) == c)
|
||||||
p.x = op.x+Dx(w->r); /* yes: toss to next column */
|
p.x = op.x + Dx(w->r); /* yes: toss to next column */
|
||||||
nc = rowwhichcol(c->row, p);
|
nc = rowwhichcol(c->row, p);
|
||||||
if(nc!=nil && nc!=c){
|
if (nc != nil && nc != c) {
|
||||||
colclose(c, w, FALSE);
|
colclose(c, w, FALSE);
|
||||||
coladd(nc, w, nil, p.y);
|
coladd(nc, w, nil, p.y);
|
||||||
winmousebut(w);
|
winmousebut(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(i==0 && c->nw==1)
|
if (i == 0 && c->nw == 1)
|
||||||
return; /* can't do it */
|
return; /* can't do it */
|
||||||
if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max.y)
|
if (
|
||||||
|| (i==0 && p.y>w->r.max.y)){
|
(i > 0 && p.y < c->w[i - 1]->r.min.y) ||
|
||||||
|
(i < c->nw - 1 && p.y > w->r.max.y) || (i == 0 && p.y > w->r.max.y)) {
|
||||||
/* shuffle */
|
/* shuffle */
|
||||||
colclose(c, w, FALSE);
|
colclose(c, w, FALSE);
|
||||||
coladd(c, w, nil, p.y);
|
coladd(c, w, nil, p.y);
|
||||||
winmousebut(w);
|
winmousebut(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(i == 0)
|
if (i == 0)
|
||||||
return;
|
return;
|
||||||
v = c->w[i-1];
|
v = c->w[i - 1];
|
||||||
if(p.y < v->tagtop.max.y)
|
if (p.y < v->tagtop.max.y)
|
||||||
p.y = v->tagtop.max.y;
|
p.y = v->tagtop.max.y;
|
||||||
if(p.y > w->r.max.y-Dy(w->tagtop)-Border)
|
if (p.y > w->r.max.y - Dy(w->tagtop) - Border)
|
||||||
p.y = w->r.max.y-Dy(w->tagtop)-Border;
|
p.y = w->r.max.y - Dy(w->tagtop) - Border;
|
||||||
r = v->r;
|
r = v->r;
|
||||||
r.max.y = p.y;
|
r.max.y = p.y;
|
||||||
if(r.max.y > v->body.fr.r.min.y){
|
if (r.max.y > v->body.fr.r.min.y) {
|
||||||
r.max.y -= (r.max.y-v->body.fr.r.min.y)%v->body.fr.font->height;
|
r.max.y -= (r.max.y - v->body.fr.r.min.y) % v->body.fr.font->height;
|
||||||
if(v->body.fr.r.min.y == v->body.fr.r.max.y)
|
if (v->body.fr.r.min.y == v->body.fr.r.max.y)
|
||||||
r.max.y++;
|
r.max.y++;
|
||||||
}
|
}
|
||||||
r.min.y = winresize(v, r, c->safe, FALSE);
|
r.min.y = winresize(v, r, c->safe, FALSE);
|
||||||
r.max.y = r.min.y+Border;
|
r.max.y = r.min.y + Border;
|
||||||
draw(screen, r, allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x222222FF), nil, ZP);
|
draw(
|
||||||
|
screen,
|
||||||
|
r,
|
||||||
|
allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x222222FF),
|
||||||
|
nil,
|
||||||
|
ZP);
|
||||||
r.min.y = r.max.y;
|
r.min.y = r.max.y;
|
||||||
if(i == c->nw-1)
|
if (i == c->nw - 1)
|
||||||
r.max.y = c->r.max.y;
|
r.max.y = c->r.max.y;
|
||||||
else
|
else
|
||||||
r.max.y = c->w[i+1]->r.min.y-Border;
|
r.max.y = c->w[i + 1]->r.min.y - Border;
|
||||||
winresize(w, r, c->safe, TRUE);
|
winresize(w, r, c->safe, TRUE);
|
||||||
c->safe = TRUE;
|
c->safe = TRUE;
|
||||||
winmousebut(w);
|
winmousebut(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
Text*
|
Text* colwhich(Column* c, Point p) {
|
||||||
colwhich(Column *c, Point p)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
Window *w;
|
Window* w;
|
||||||
|
|
||||||
if(!ptinrect(p, c->r))
|
if (!ptinrect(p, c->r))
|
||||||
return nil;
|
return nil;
|
||||||
if(ptinrect(p, c->tag.all))
|
if (ptinrect(p, c->tag.all))
|
||||||
return &c->tag;
|
return &c->tag;
|
||||||
for(i=0; i<c->nw; i++){
|
for (i = 0; i < c->nw; i++) {
|
||||||
w = c->w[i];
|
w = c->w[i];
|
||||||
if(ptinrect(p, w->r)){
|
if (ptinrect(p, w->r)) {
|
||||||
if(ptinrect(p, w->tagtop) || ptinrect(p, w->tag.all))
|
if (ptinrect(p, w->tagtop) || ptinrect(p, w->tag.all))
|
||||||
return &w->tag;
|
return &w->tag;
|
||||||
/* exclude partial line at bottom */
|
/* exclude partial line at bottom */
|
||||||
if(p.x >= w->body.scrollr.max.x && p.y >= w->body.fr.r.max.y)
|
if (p.x >= w->body.scrollr.max.x && p.y >= w->body.fr.r.max.y)
|
||||||
return nil;
|
return nil;
|
||||||
return &w->body;
|
return &w->body;
|
||||||
}
|
}
|
||||||
|
@ -574,13 +605,11 @@ colwhich(Column *c, Point p)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int colclean(Column* c) {
|
||||||
colclean(Column *c)
|
|
||||||
{
|
|
||||||
int i, clean;
|
int i, clean;
|
||||||
|
|
||||||
clean = TRUE;
|
clean = TRUE;
|
||||||
for(i=0; i<c->nw; i++)
|
for (i = 0; i < c->nw; i++)
|
||||||
clean &= winclean(c->w[i], TRUE);
|
clean &= winclean(c->w[i], TRUE);
|
||||||
return clean;
|
return clean;
|
||||||
}
|
}
|
||||||
|
|
79
disk.c
79
disk.c
|
@ -12,78 +12,69 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
static Block *blist;
|
static Block* blist;
|
||||||
|
|
||||||
int
|
int tempfile(void) {
|
||||||
tempfile(void)
|
|
||||||
{
|
|
||||||
char buf[128];
|
char buf[128];
|
||||||
int i, fd;
|
int i, fd;
|
||||||
|
|
||||||
snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser());
|
snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser());
|
||||||
for(i='A'; i<='Z'; i++){
|
for (i = 'A'; i <= 'Z'; i++) {
|
||||||
buf[5] = i;
|
buf[5] = i;
|
||||||
if(access(buf, AEXIST) == 0)
|
if (access(buf, AEXIST) == 0)
|
||||||
continue;
|
continue;
|
||||||
fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600);
|
fd = create(buf, ORDWR | ORCLOSE | OCEXEC, 0600);
|
||||||
if(fd >= 0)
|
if (fd >= 0)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Disk*
|
Disk* diskinit() {
|
||||||
diskinit()
|
Disk* d;
|
||||||
{
|
|
||||||
Disk *d;
|
|
||||||
|
|
||||||
d = emalloc(sizeof(Disk));
|
d = emalloc(sizeof(Disk));
|
||||||
d->fd = tempfile();
|
d->fd = tempfile();
|
||||||
if(d->fd < 0){
|
if (d->fd < 0) {
|
||||||
fprint(2, "acme: can't create temp file: %r\n");
|
fprint(2, "acme: can't create temp file: %r\n");
|
||||||
threadexitsall("diskinit");
|
threadexitsall("diskinit");
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static uint ntosize(uint n, uint* ip) {
|
||||||
uint
|
|
||||||
ntosize(uint n, uint *ip)
|
|
||||||
{
|
|
||||||
uint size;
|
uint size;
|
||||||
|
|
||||||
if(n > Maxblock)
|
if (n > Maxblock)
|
||||||
error("internal error: ntosize");
|
error("internal error: ntosize");
|
||||||
size = n;
|
size = n;
|
||||||
if(size & (Blockincr-1))
|
if (size & (Blockincr - 1))
|
||||||
size += Blockincr - (size & (Blockincr-1));
|
size += Blockincr - (size & (Blockincr - 1));
|
||||||
/* last bucket holds blocks of exactly Maxblock */
|
/* last bucket holds blocks of exactly Maxblock */
|
||||||
if(ip)
|
if (ip)
|
||||||
*ip = size/Blockincr;
|
*ip = size / Blockincr;
|
||||||
return size * sizeof(Rune);
|
return size * sizeof(Rune);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block*
|
Block* disknewblock(Disk* d, uint n) {
|
||||||
disknewblock(Disk *d, uint n)
|
|
||||||
{
|
|
||||||
uint i, j, size;
|
uint i, j, size;
|
||||||
Block *b;
|
Block* b;
|
||||||
|
|
||||||
size = ntosize(n, &i);
|
size = ntosize(n, &i);
|
||||||
b = d->free[i];
|
b = d->free[i];
|
||||||
if(b)
|
if (b)
|
||||||
d->free[i] = b->u.next;
|
d->free[i] = b->u.next;
|
||||||
else{
|
else {
|
||||||
/* allocate in chunks to reduce malloc overhead */
|
/* allocate in chunks to reduce malloc overhead */
|
||||||
if(blist == nil){
|
if (blist == nil) {
|
||||||
blist = emalloc(100*sizeof(Block));
|
blist = emalloc(100 * sizeof(Block));
|
||||||
for(j=0; j<100-1; j++)
|
for (j = 0; j < 100 - 1; j++)
|
||||||
blist[j].u.next = &blist[j+1];
|
blist[j].u.next = &blist[j + 1];
|
||||||
}
|
}
|
||||||
b = blist;
|
b = blist;
|
||||||
blist = b->u.next;
|
blist = b->u.next;
|
||||||
b->addr = d->addr;
|
b->addr = d->addr;
|
||||||
if(d->addr+size < d->addr){
|
if (d->addr + size < d->addr) {
|
||||||
error("temp file overflow");
|
error("temp file overflow");
|
||||||
}
|
}
|
||||||
d->addr += size;
|
d->addr += size;
|
||||||
|
@ -92,9 +83,7 @@ disknewblock(Disk *d, uint n)
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void diskrelease(Disk* d, Block* b) {
|
||||||
diskrelease(Disk *d, Block *b)
|
|
||||||
{
|
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
ntosize(b->u.n, &i);
|
ntosize(b->u.n, &i);
|
||||||
|
@ -102,32 +91,28 @@ diskrelease(Disk *d, Block *b)
|
||||||
d->free[i] = b;
|
d->free[i] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void diskwrite(Disk* d, Block** bp, Rune* r, uint n) {
|
||||||
diskwrite(Disk *d, Block **bp, Rune *r, uint n)
|
|
||||||
{
|
|
||||||
int size, nsize;
|
int size, nsize;
|
||||||
Block *b;
|
Block* b;
|
||||||
|
|
||||||
b = *bp;
|
b = *bp;
|
||||||
size = ntosize(b->u.n, nil);
|
size = ntosize(b->u.n, nil);
|
||||||
nsize = ntosize(n, nil);
|
nsize = ntosize(n, nil);
|
||||||
if(size != nsize){
|
if (size != nsize) {
|
||||||
diskrelease(d, b);
|
diskrelease(d, b);
|
||||||
b = disknewblock(d, n);
|
b = disknewblock(d, n);
|
||||||
*bp = b;
|
*bp = b;
|
||||||
}
|
}
|
||||||
if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
|
if (pwrite(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
|
||||||
error("write error to temp file");
|
error("write error to temp file");
|
||||||
b->u.n = n;
|
b->u.n = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void diskread(Disk* d, Block* b, Rune* r, uint n) {
|
||||||
diskread(Disk *d, Block *b, Rune *r, uint n)
|
if (n > b->u.n)
|
||||||
{
|
|
||||||
if(n > b->u.n)
|
|
||||||
error("internal error: diskread");
|
error("internal error: diskread");
|
||||||
|
|
||||||
ntosize(b->u.n, nil);
|
ntosize(b->u.n, nil);
|
||||||
if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
|
if (pread(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
|
||||||
error("read error from temp file");
|
error("read error from temp file");
|
||||||
}
|
}
|
||||||
|
|
211
elog.c
211
elog.c
|
@ -27,65 +27,52 @@ static int warned = FALSE;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct Buflog Buflog;
|
typedef struct Buflog Buflog;
|
||||||
struct Buflog
|
struct Buflog {
|
||||||
{
|
|
||||||
short type; /* Replace, Filename */
|
short type; /* Replace, Filename */
|
||||||
uint q0; /* location of change (unused in f) */
|
uint q0; /* location of change (unused in f) */
|
||||||
uint nd; /* # runes to delete */
|
uint nd; /* # runes to delete */
|
||||||
uint nr; /* # runes in string or file name */
|
uint nr; /* # runes in string or file name */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum { Buflogsize = sizeof(Buflog) / sizeof(Rune) };
|
||||||
{
|
|
||||||
Buflogsize = sizeof(Buflog)/sizeof(Rune)
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Minstring shouldn't be very big or we will do lots of I/O for small changes.
|
* Minstring shouldn't be very big or we will do lots of I/O for small changes.
|
||||||
* Maxstring is RBUFSIZE so we can fbufalloc() once and not realloc elog.r.
|
* Maxstring is RBUFSIZE so we can fbufalloc() once and not realloc elog.r.
|
||||||
*/
|
*/
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
Minstring = 16, /* distance beneath which we merge changes */
|
Minstring = 16, /* distance beneath which we merge changes */
|
||||||
Maxstring = RBUFSIZE /* maximum length of change we will merge into one */
|
Maxstring = RBUFSIZE /* maximum length of change we will merge into one */
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void eloginit(File* f) {
|
||||||
eloginit(File *f)
|
if (f->elog.type != Empty)
|
||||||
{
|
|
||||||
if(f->elog.type != Empty)
|
|
||||||
return;
|
return;
|
||||||
f->elog.type = Null;
|
f->elog.type = Null;
|
||||||
if(f->elogbuf == nil)
|
if (f->elogbuf == nil)
|
||||||
f->elogbuf = emalloc(sizeof(Buffer));
|
f->elogbuf = emalloc(sizeof(Buffer));
|
||||||
if(f->elog.r == nil)
|
if (f->elog.r == nil)
|
||||||
f->elog.r = fbufalloc();
|
f->elog.r = fbufalloc();
|
||||||
bufreset(f->elogbuf);
|
bufreset(f->elogbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void elogclose(File* f) {
|
||||||
elogclose(File *f)
|
if (f->elogbuf) {
|
||||||
{
|
|
||||||
if(f->elogbuf){
|
|
||||||
bufclose(f->elogbuf);
|
bufclose(f->elogbuf);
|
||||||
free(f->elogbuf);
|
free(f->elogbuf);
|
||||||
f->elogbuf = nil;
|
f->elogbuf = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void elogreset(File* f) {
|
||||||
elogreset(File *f)
|
|
||||||
{
|
|
||||||
f->elog.type = Null;
|
f->elog.type = Null;
|
||||||
f->elog.nd = 0;
|
f->elog.nd = 0;
|
||||||
f->elog.nr = 0;
|
f->elog.nr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void elogterm(File* f) {
|
||||||
elogterm(File *f)
|
|
||||||
{
|
|
||||||
elogreset(f);
|
elogreset(f);
|
||||||
if(f->elogbuf)
|
if (f->elogbuf)
|
||||||
bufreset(f->elogbuf);
|
bufreset(f->elogbuf);
|
||||||
f->elog.type = Empty;
|
f->elog.type = Empty;
|
||||||
fbuffree(f->elog.r);
|
fbuffree(f->elog.r);
|
||||||
|
@ -93,16 +80,14 @@ elogterm(File *f)
|
||||||
warned = FALSE;
|
warned = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void elogflush(File* f) {
|
||||||
elogflush(File *f)
|
|
||||||
{
|
|
||||||
Buflog b;
|
Buflog b;
|
||||||
|
|
||||||
b.type = f->elog.type;
|
b.type = f->elog.type;
|
||||||
b.q0 = f->elog.q0;
|
b.q0 = f->elog.q0;
|
||||||
b.nd = f->elog.nd;
|
b.nd = f->elog.nd;
|
||||||
b.nr = f->elog.nr;
|
b.nr = f->elog.nr;
|
||||||
switch(f->elog.type){
|
switch (f->elog.type) {
|
||||||
default:
|
default:
|
||||||
warning(nil, "unknown elog type 0x%ux\n", f->elog.type);
|
warning(nil, "unknown elog type 0x%ux\n", f->elog.type);
|
||||||
break;
|
break;
|
||||||
|
@ -110,7 +95,7 @@ elogflush(File *f)
|
||||||
break;
|
break;
|
||||||
case Insert:
|
case Insert:
|
||||||
case Replace:
|
case Replace:
|
||||||
if(f->elog.nr > 0)
|
if (f->elog.nr > 0)
|
||||||
bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr);
|
bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case Delete:
|
case Delete:
|
||||||
|
@ -120,29 +105,27 @@ elogflush(File *f)
|
||||||
elogreset(f);
|
elogreset(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void elogreplace(File* f, int q0, int q1, Rune* r, int nr) {
|
||||||
elogreplace(File *f, int q0, int q1, Rune *r, int nr)
|
|
||||||
{
|
|
||||||
uint gap;
|
uint gap;
|
||||||
|
|
||||||
if(q0==q1 && nr==0)
|
if (q0 == q1 && nr == 0)
|
||||||
return;
|
return;
|
||||||
eloginit(f);
|
eloginit(f);
|
||||||
if(f->elog.type!=Null && q0<f->elog.q0){
|
if (f->elog.type != Null && q0 < f->elog.q0) {
|
||||||
if(warned++ == 0)
|
if (warned++ == 0)
|
||||||
warning(nil, Wsequence);
|
warning(nil, Wsequence);
|
||||||
elogflush(f);
|
elogflush(f);
|
||||||
}
|
}
|
||||||
/* try to merge with previous */
|
/* try to merge with previous */
|
||||||
gap = q0 - (f->elog.q0+f->elog.nd); /* gap between previous and this */
|
gap = q0 - (f->elog.q0 + f->elog.nd); /* gap between previous and this */
|
||||||
if(f->elog.type==Replace && f->elog.nr+gap+nr<Maxstring){
|
if (f->elog.type == Replace && f->elog.nr + gap + nr < Maxstring) {
|
||||||
if(gap < Minstring){
|
if (gap < Minstring) {
|
||||||
if(gap > 0){
|
if (gap > 0) {
|
||||||
bufread(&f->b, f->elog.q0+f->elog.nd, f->elog.r+f->elog.nr, gap);
|
bufread(&f->b, f->elog.q0 + f->elog.nd, f->elog.r + f->elog.nr, gap);
|
||||||
f->elog.nr += gap;
|
f->elog.nr += gap;
|
||||||
}
|
}
|
||||||
f->elog.nd += gap + q1-q0;
|
f->elog.nd += gap + q1 - q0;
|
||||||
runemove(f->elog.r+f->elog.nr, r, nr);
|
runemove(f->elog.r + f->elog.nr, r, nr);
|
||||||
f->elog.nr += nr;
|
f->elog.nr += nr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -150,38 +133,37 @@ elogreplace(File *f, int q0, int q1, Rune *r, int nr)
|
||||||
elogflush(f);
|
elogflush(f);
|
||||||
f->elog.type = Replace;
|
f->elog.type = Replace;
|
||||||
f->elog.q0 = q0;
|
f->elog.q0 = q0;
|
||||||
f->elog.nd = q1-q0;
|
f->elog.nd = q1 - q0;
|
||||||
f->elog.nr = nr;
|
f->elog.nr = nr;
|
||||||
if(nr > RBUFSIZE)
|
if (nr > RBUFSIZE)
|
||||||
editerror("internal error: replacement string too large(%d)", nr);
|
editerror("internal error: replacement string too large(%d)", nr);
|
||||||
runemove(f->elog.r, r, nr);
|
runemove(f->elog.r, r, nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void eloginsert(File* f, int q0, Rune* r, int nr) {
|
||||||
eloginsert(File *f, int q0, Rune *r, int nr)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if(nr == 0)
|
if (nr == 0)
|
||||||
return;
|
return;
|
||||||
eloginit(f);
|
eloginit(f);
|
||||||
if(f->elog.type!=Null && q0<f->elog.q0){
|
if (f->elog.type != Null && q0 < f->elog.q0) {
|
||||||
if(warned++ == 0)
|
if (warned++ == 0)
|
||||||
warning(nil, Wsequence);
|
warning(nil, Wsequence);
|
||||||
elogflush(f);
|
elogflush(f);
|
||||||
}
|
}
|
||||||
/* try to merge with previous */
|
/* try to merge with previous */
|
||||||
if(f->elog.type==Insert && q0==f->elog.q0 && f->elog.nr+nr<Maxstring){
|
if (
|
||||||
runemove(f->elog.r+f->elog.nr, r, nr);
|
f->elog.type == Insert && q0 == f->elog.q0 && f->elog.nr + nr < Maxstring) {
|
||||||
|
runemove(f->elog.r + f->elog.nr, r, nr);
|
||||||
f->elog.nr += nr;
|
f->elog.nr += nr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while(nr > 0){
|
while (nr > 0) {
|
||||||
elogflush(f);
|
elogflush(f);
|
||||||
f->elog.type = Insert;
|
f->elog.type = Insert;
|
||||||
f->elog.q0 = q0;
|
f->elog.q0 = q0;
|
||||||
n = nr;
|
n = nr;
|
||||||
if(n > RBUFSIZE)
|
if (n > RBUFSIZE)
|
||||||
n = RBUFSIZE;
|
n = RBUFSIZE;
|
||||||
f->elog.nr = n;
|
f->elog.nr = n;
|
||||||
runemove(f->elog.r, r, n);
|
runemove(f->elog.r, r, n);
|
||||||
|
@ -190,38 +172,34 @@ eloginsert(File *f, int q0, Rune *r, int nr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void elogdelete(File* f, int q0, int q1) {
|
||||||
elogdelete(File *f, int q0, int q1)
|
if (q0 == q1)
|
||||||
{
|
|
||||||
if(q0 == q1)
|
|
||||||
return;
|
return;
|
||||||
eloginit(f);
|
eloginit(f);
|
||||||
if(f->elog.type!=Null && q0<f->elog.q0+f->elog.nd){
|
if (f->elog.type != Null && q0 < f->elog.q0 + f->elog.nd) {
|
||||||
if(warned++ == 0)
|
if (warned++ == 0)
|
||||||
warning(nil, Wsequence);
|
warning(nil, Wsequence);
|
||||||
elogflush(f);
|
elogflush(f);
|
||||||
}
|
}
|
||||||
/* try to merge with previous */
|
/* try to merge with previous */
|
||||||
if(f->elog.type==Delete && f->elog.q0+f->elog.nd==q0){
|
if (f->elog.type == Delete && f->elog.q0 + f->elog.nd == q0) {
|
||||||
f->elog.nd += q1-q0;
|
f->elog.nd += q1 - q0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
elogflush(f);
|
elogflush(f);
|
||||||
f->elog.type = Delete;
|
f->elog.type = Delete;
|
||||||
f->elog.q0 = q0;
|
f->elog.q0 = q0;
|
||||||
f->elog.nd = q1-q0;
|
f->elog.nd = q1 - q0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define tracelog 0
|
#define tracelog 0
|
||||||
void
|
void elogapply(File* f) {
|
||||||
elogapply(File *f)
|
|
||||||
{
|
|
||||||
Buflog b;
|
Buflog b;
|
||||||
Rune *buf;
|
Rune* buf;
|
||||||
uint i, n, up, mod;
|
uint i, n, up, mod;
|
||||||
uint tq0, tq1;
|
uint tq0, tq1;
|
||||||
Buffer *log;
|
Buffer* log;
|
||||||
Text *t;
|
Text* t;
|
||||||
int owner;
|
int owner;
|
||||||
|
|
||||||
elogflush(f);
|
elogflush(f);
|
||||||
|
@ -232,19 +210,19 @@ elogapply(File *f)
|
||||||
mod = FALSE;
|
mod = FALSE;
|
||||||
|
|
||||||
owner = 0;
|
owner = 0;
|
||||||
if(t->w){
|
if (t->w) {
|
||||||
owner = t->w->owner;
|
owner = t->w->owner;
|
||||||
if(owner == 0)
|
if (owner == 0)
|
||||||
t->w->owner = 'E';
|
t->w->owner = 'E';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The edit commands have already updated the selection in t->q0, t->q1,
|
* The edit commands have already updated the selection in t->q0, t->q1,
|
||||||
* but using coordinates relative to the unmodified buffer. As we apply the log,
|
* but using coordinates relative to the unmodified buffer. As we apply the
|
||||||
* we have to update the coordinates to be relative to the modified buffer.
|
* log, we have to update the coordinates to be relative to the modified
|
||||||
* Textinsert and textdelete will do this for us; our only work is to apply the
|
* buffer. Textinsert and textdelete will do this for us; our only work is to
|
||||||
* convention that an insertion at t->q0==t->q1 is intended to select the
|
* apply the convention that an insertion at t->q0==t->q1 is intended to
|
||||||
* inserted text.
|
* select the inserted text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -254,71 +232,86 @@ elogapply(File *f)
|
||||||
* keep things in range.
|
* keep things in range.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while(log->nc > 0){
|
while (log->nc > 0) {
|
||||||
up = log->nc-Buflogsize;
|
up = log->nc - Buflogsize;
|
||||||
bufread(log, up, (Rune*)&b, Buflogsize);
|
bufread(log, up, (Rune*)&b, Buflogsize);
|
||||||
switch(b.type){
|
switch (b.type) {
|
||||||
default:
|
default:
|
||||||
fprint(2, "elogapply: 0x%ux\n", b.type);
|
fprint(2, "elogapply: 0x%ux\n", b.type);
|
||||||
abort();
|
abort();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Replace:
|
case Replace:
|
||||||
if(tracelog)
|
if (tracelog)
|
||||||
warning(nil, "elog replace %d %d (%d %d)\n",
|
warning(
|
||||||
b.q0, b.q0+b.nd, t->q0, t->q1);
|
nil,
|
||||||
if(!mod){
|
"elog replace %d %d (%d %d)\n",
|
||||||
|
b.q0,
|
||||||
|
b.q0 + b.nd,
|
||||||
|
t->q0,
|
||||||
|
t->q1);
|
||||||
|
if (!mod) {
|
||||||
mod = TRUE;
|
mod = TRUE;
|
||||||
filemark(f);
|
filemark(f);
|
||||||
}
|
}
|
||||||
textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1);
|
textconstrain(t, b.q0, b.q0 + b.nd, &tq0, &tq1);
|
||||||
textdelete(t, tq0, tq1, TRUE);
|
textdelete(t, tq0, tq1, TRUE);
|
||||||
up -= b.nr;
|
up -= b.nr;
|
||||||
for(i=0; i<b.nr; i+=n){
|
for (i = 0; i < b.nr; i += n) {
|
||||||
n = b.nr - i;
|
n = b.nr - i;
|
||||||
if(n > RBUFSIZE)
|
if (n > RBUFSIZE)
|
||||||
n = RBUFSIZE;
|
n = RBUFSIZE;
|
||||||
bufread(log, up+i, buf, n);
|
bufread(log, up + i, buf, n);
|
||||||
textinsert(t, tq0+i, buf, n, TRUE);
|
textinsert(t, tq0 + i, buf, n, TRUE);
|
||||||
}
|
}
|
||||||
if(t->q0 == b.q0 && t->q1 == b.q0)
|
if (t->q0 == b.q0 && t->q1 == b.q0)
|
||||||
t->q1 += b.nr;
|
t->q1 += b.nr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Delete:
|
case Delete:
|
||||||
if(tracelog)
|
if (tracelog)
|
||||||
warning(nil, "elog delete %d %d (%d %d)\n",
|
warning(
|
||||||
b.q0, b.q0+b.nd, t->q0, t->q1);
|
nil,
|
||||||
if(!mod){
|
"elog delete %d %d (%d %d)\n",
|
||||||
|
b.q0,
|
||||||
|
b.q0 + b.nd,
|
||||||
|
t->q0,
|
||||||
|
t->q1);
|
||||||
|
if (!mod) {
|
||||||
mod = TRUE;
|
mod = TRUE;
|
||||||
filemark(f);
|
filemark(f);
|
||||||
}
|
}
|
||||||
textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1);
|
textconstrain(t, b.q0, b.q0 + b.nd, &tq0, &tq1);
|
||||||
textdelete(t, tq0, tq1, TRUE);
|
textdelete(t, tq0, tq1, TRUE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Insert:
|
case Insert:
|
||||||
if(tracelog)
|
if (tracelog)
|
||||||
warning(nil, "elog insert %d %d (%d %d)\n",
|
warning(
|
||||||
b.q0, b.q0+b.nr, t->q0, t->q1);
|
nil,
|
||||||
if(!mod){
|
"elog insert %d %d (%d %d)\n",
|
||||||
|
b.q0,
|
||||||
|
b.q0 + b.nr,
|
||||||
|
t->q0,
|
||||||
|
t->q1);
|
||||||
|
if (!mod) {
|
||||||
mod = TRUE;
|
mod = TRUE;
|
||||||
filemark(f);
|
filemark(f);
|
||||||
}
|
}
|
||||||
textconstrain(t, b.q0, b.q0, &tq0, &tq1);
|
textconstrain(t, b.q0, b.q0, &tq0, &tq1);
|
||||||
up -= b.nr;
|
up -= b.nr;
|
||||||
for(i=0; i<b.nr; i+=n){
|
for (i = 0; i < b.nr; i += n) {
|
||||||
n = b.nr - i;
|
n = b.nr - i;
|
||||||
if(n > RBUFSIZE)
|
if (n > RBUFSIZE)
|
||||||
n = RBUFSIZE;
|
n = RBUFSIZE;
|
||||||
bufread(log, up+i, buf, n);
|
bufread(log, up + i, buf, n);
|
||||||
textinsert(t, tq0+i, buf, n, TRUE);
|
textinsert(t, tq0 + i, buf, n, TRUE);
|
||||||
}
|
}
|
||||||
if(t->q0 == b.q0 && t->q1 == b.q0)
|
if (t->q0 == b.q0 && t->q1 == b.q0)
|
||||||
t->q1 += b.nr;
|
t->q1 += b.nr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* case Filename:
|
/* case Filename:
|
||||||
f->seq = u.seq;
|
f->seq = u.seq;
|
||||||
fileunsetname(f, epsilon);
|
fileunsetname(f, epsilon);
|
||||||
f->mod = u.mod;
|
f->mod = u.mod;
|
||||||
|
@ -331,7 +324,7 @@ elogapply(File *f)
|
||||||
bufread(delta, up, f->name, u.n);
|
bufread(delta, up, f->name, u.n);
|
||||||
f->nname = u.n;
|
f->nname = u.n;
|
||||||
break;
|
break;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
bufdelete(log, up, log->nc);
|
bufdelete(log, up, log->nc);
|
||||||
}
|
}
|
||||||
|
@ -342,13 +335,13 @@ elogapply(File *f)
|
||||||
* Bad addresses will cause bufload to crash, so double check.
|
* Bad addresses will cause bufload to crash, so double check.
|
||||||
* If changes were out of order, we expect problems so don't complain further.
|
* If changes were out of order, we expect problems so don't complain further.
|
||||||
*/
|
*/
|
||||||
if(t->q0 > f->b.nc || t->q1 > f->b.nc || t->q0 > t->q1){
|
if (t->q0 > f->b.nc || t->q1 > f->b.nc || t->q0 > t->q1) {
|
||||||
if(!warned)
|
if (!warned)
|
||||||
warning(nil, "elogapply: can't happen %d %d %d\n", t->q0, t->q1, f->b.nc);
|
warning(nil, "elogapply: can't happen %d %d %d\n", t->q0, t->q1, f->b.nc);
|
||||||
t->q1 = min(t->q1, f->b.nc);
|
t->q1 = min(t->q1, f->b.nc);
|
||||||
t->q0 = min(t->q0, t->q1);
|
t->q0 = min(t->q0, t->q1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t->w)
|
if (t->w)
|
||||||
t->w->owner = owner;
|
t->w->owner = owner;
|
||||||
}
|
}
|
||||||
|
|
165
file.c
165
file.c
|
@ -23,8 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct Undo Undo;
|
typedef struct Undo Undo;
|
||||||
struct Undo
|
struct Undo {
|
||||||
{
|
|
||||||
short type; /* Delete, Insert, Filename */
|
short type; /* Delete, Insert, Filename */
|
||||||
short mod; /* modify bit */
|
short mod; /* modify bit */
|
||||||
uint seq; /* sequence number */
|
uint seq; /* sequence number */
|
||||||
|
@ -32,60 +31,49 @@ struct Undo
|
||||||
uint n; /* # runes in string or file name */
|
uint n; /* # runes in string or file name */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum { Undosize = sizeof(Undo) / sizeof(Rune) };
|
||||||
{
|
|
||||||
Undosize = sizeof(Undo)/sizeof(Rune)
|
|
||||||
};
|
|
||||||
|
|
||||||
File*
|
File* fileaddtext(File* f, Text* t) {
|
||||||
fileaddtext(File *f, Text *t)
|
if (f == nil) {
|
||||||
{
|
|
||||||
if(f == nil){
|
|
||||||
f = emalloc(sizeof(File));
|
f = emalloc(sizeof(File));
|
||||||
f->unread = TRUE;
|
f->unread = TRUE;
|
||||||
}
|
}
|
||||||
f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
|
f->text = realloc(f->text, (f->ntext + 1) * sizeof(Text*));
|
||||||
f->text[f->ntext++] = t;
|
f->text[f->ntext++] = t;
|
||||||
f->curtext = t;
|
f->curtext = t;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void filedeltext(File* f, Text* t) {
|
||||||
filedeltext(File *f, Text *t)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0; i<f->ntext; i++)
|
for (i = 0; i < f->ntext; i++)
|
||||||
if(f->text[i] == t)
|
if (f->text[i] == t)
|
||||||
goto Found;
|
goto Found;
|
||||||
error("can't find text in filedeltext");
|
error("can't find text in filedeltext");
|
||||||
|
|
||||||
Found:
|
Found:
|
||||||
f->ntext--;
|
f->ntext--;
|
||||||
if(f->ntext == 0){
|
if (f->ntext == 0) {
|
||||||
fileclose(f);
|
fileclose(f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
|
memmove(f->text + i, f->text + i + 1, (f->ntext - i) * sizeof(Text*));
|
||||||
if(f->curtext == t)
|
if (f->curtext == t)
|
||||||
f->curtext = f->text[0];
|
f->curtext = f->text[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fileinsert(File* f, uint p0, Rune* s, uint ns) {
|
||||||
fileinsert(File *f, uint p0, Rune *s, uint ns)
|
if (p0 > f->b.nc)
|
||||||
{
|
|
||||||
if(p0 > f->b.nc)
|
|
||||||
error("internal error: fileinsert");
|
error("internal error: fileinsert");
|
||||||
if(f->seq > 0)
|
if (f->seq > 0)
|
||||||
fileuninsert(f, &f->delta, p0, ns);
|
fileuninsert(f, &f->delta, p0, ns);
|
||||||
bufinsert(&f->b, p0, s, ns);
|
bufinsert(&f->b, p0, s, ns);
|
||||||
if(ns)
|
if (ns)
|
||||||
f->mod = TRUE;
|
f->mod = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fileuninsert(File* f, Buffer* delta, uint p0, uint ns) {
|
||||||
fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
|
|
||||||
{
|
|
||||||
Undo u;
|
Undo u;
|
||||||
|
|
||||||
/* undo an insertion by deleting */
|
/* undo an insertion by deleting */
|
||||||
|
@ -97,23 +85,19 @@ fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
|
||||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void filedelete(File* f, uint p0, uint p1) {
|
||||||
filedelete(File *f, uint p0, uint p1)
|
if (!(p0 <= p1 && p0 <= f->b.nc && p1 <= f->b.nc))
|
||||||
{
|
|
||||||
if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
|
|
||||||
error("internal error: filedelete");
|
error("internal error: filedelete");
|
||||||
if(f->seq > 0)
|
if (f->seq > 0)
|
||||||
fileundelete(f, &f->delta, p0, p1);
|
fileundelete(f, &f->delta, p0, p1);
|
||||||
bufdelete(&f->b, p0, p1);
|
bufdelete(&f->b, p0, p1);
|
||||||
if(p1 > p0)
|
if (p1 > p0)
|
||||||
f->mod = TRUE;
|
f->mod = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fileundelete(File* f, Buffer* delta, uint p0, uint p1) {
|
||||||
fileundelete(File *f, Buffer *delta, uint p0, uint p1)
|
|
||||||
{
|
|
||||||
Undo u;
|
Undo u;
|
||||||
Rune *buf;
|
Rune* buf;
|
||||||
uint i, n;
|
uint i, n;
|
||||||
|
|
||||||
/* undo a deletion by inserting */
|
/* undo a deletion by inserting */
|
||||||
|
@ -121,24 +105,21 @@ fileundelete(File *f, Buffer *delta, uint p0, uint p1)
|
||||||
u.mod = f->mod;
|
u.mod = f->mod;
|
||||||
u.seq = f->seq;
|
u.seq = f->seq;
|
||||||
u.p0 = p0;
|
u.p0 = p0;
|
||||||
u.n = p1-p0;
|
u.n = p1 - p0;
|
||||||
buf = fbufalloc();
|
buf = fbufalloc();
|
||||||
for(i=p0; i<p1; i+=n){
|
for (i = p0; i < p1; i += n) {
|
||||||
n = p1 - i;
|
n = p1 - i;
|
||||||
if(n > RBUFSIZE)
|
if (n > RBUFSIZE)
|
||||||
n = RBUFSIZE;
|
n = RBUFSIZE;
|
||||||
bufread(&f->b, i, buf, n);
|
bufread(&f->b, i, buf, n);
|
||||||
bufinsert(delta, delta->nc, buf, n);
|
bufinsert(delta, delta->nc, buf, n);
|
||||||
}
|
}
|
||||||
fbuffree(buf);
|
fbuffree(buf);
|
||||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void filesetname(File* f, Rune* name, int n) {
|
||||||
filesetname(File *f, Rune *name, int n)
|
if (f->seq > 0)
|
||||||
{
|
|
||||||
if(f->seq > 0)
|
|
||||||
fileunsetname(f, &f->delta);
|
fileunsetname(f, &f->delta);
|
||||||
free(f->name);
|
free(f->name);
|
||||||
f->name = runemalloc(n);
|
f->name = runemalloc(n);
|
||||||
|
@ -147,9 +128,7 @@ filesetname(File *f, Rune *name, int n)
|
||||||
f->unread = TRUE;
|
f->unread = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fileunsetname(File* f, Buffer* delta) {
|
||||||
fileunsetname(File *f, Buffer *delta)
|
|
||||||
{
|
|
||||||
Undo u;
|
Undo u;
|
||||||
|
|
||||||
/* undo a file name change by restoring old name */
|
/* undo a file name change by restoring old name */
|
||||||
|
@ -158,48 +137,42 @@ fileunsetname(File *f, Buffer *delta)
|
||||||
u.seq = f->seq;
|
u.seq = f->seq;
|
||||||
u.p0 = 0; /* unused */
|
u.p0 = 0; /* unused */
|
||||||
u.n = f->nname;
|
u.n = f->nname;
|
||||||
if(f->nname)
|
if (f->nname)
|
||||||
bufinsert(delta, delta->nc, f->name, f->nname);
|
bufinsert(delta, delta->nc, f->name, f->nname);
|
||||||
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint fileload(File* f, uint p0, int fd, int* nulls, DigestState* h) {
|
||||||
fileload(File *f, uint p0, int fd, int *nulls, DigestState *h)
|
if (f->seq > 0)
|
||||||
{
|
|
||||||
if(f->seq > 0)
|
|
||||||
error("undo in file.load unimplemented");
|
error("undo in file.load unimplemented");
|
||||||
return bufload(&f->b, p0, fd, nulls, h);
|
return bufload(&f->b, p0, fd, nulls, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return sequence number of pending redo */
|
/* return sequence number of pending redo */
|
||||||
uint
|
uint fileredoseq(File* f) {
|
||||||
fileredoseq(File *f)
|
|
||||||
{
|
|
||||||
Undo u;
|
Undo u;
|
||||||
Buffer *delta;
|
Buffer* delta;
|
||||||
|
|
||||||
delta = &f->epsilon;
|
delta = &f->epsilon;
|
||||||
if(delta->nc == 0)
|
if (delta->nc == 0)
|
||||||
return 0;
|
return 0;
|
||||||
bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize);
|
bufread(delta, delta->nc - Undosize, (Rune*)&u, Undosize);
|
||||||
return u.seq;
|
return u.seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fileundo(File* f, int isundo, uint* q0p, uint* q1p) {
|
||||||
fileundo(File *f, int isundo, uint *q0p, uint *q1p)
|
|
||||||
{
|
|
||||||
Undo u;
|
Undo u;
|
||||||
Rune *buf;
|
Rune* buf;
|
||||||
uint i, j, n, up;
|
uint i, j, n, up;
|
||||||
uint stop;
|
uint stop;
|
||||||
Buffer *delta, *epsilon;
|
Buffer *delta, *epsilon;
|
||||||
|
|
||||||
if(isundo){
|
if (isundo) {
|
||||||
/* undo; reverse delta onto epsilon, seq decreases */
|
/* undo; reverse delta onto epsilon, seq decreases */
|
||||||
delta = &f->delta;
|
delta = &f->delta;
|
||||||
epsilon = &f->epsilon;
|
epsilon = &f->epsilon;
|
||||||
stop = f->seq;
|
stop = f->seq;
|
||||||
}else{
|
} else {
|
||||||
/* redo; reverse epsilon onto delta, seq increases */
|
/* redo; reverse epsilon onto delta, seq increases */
|
||||||
delta = &f->epsilon;
|
delta = &f->epsilon;
|
||||||
epsilon = &f->delta;
|
epsilon = &f->delta;
|
||||||
|
@ -207,21 +180,21 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = fbufalloc();
|
buf = fbufalloc();
|
||||||
while(delta->nc > 0){
|
while (delta->nc > 0) {
|
||||||
up = delta->nc-Undosize;
|
up = delta->nc - Undosize;
|
||||||
bufread(delta, up, (Rune*)&u, Undosize);
|
bufread(delta, up, (Rune*)&u, Undosize);
|
||||||
if(isundo){
|
if (isundo) {
|
||||||
if(u.seq < stop){
|
if (u.seq < stop) {
|
||||||
f->seq = u.seq;
|
f->seq = u.seq;
|
||||||
goto Return;
|
goto Return;
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
if(stop == 0)
|
if (stop == 0)
|
||||||
stop = u.seq;
|
stop = u.seq;
|
||||||
if(u.seq > stop)
|
if (u.seq > stop)
|
||||||
goto Return;
|
goto Return;
|
||||||
}
|
}
|
||||||
switch(u.type){
|
switch (u.type) {
|
||||||
default:
|
default:
|
||||||
fprint(2, "undo: 0x%ux\n", u.type);
|
fprint(2, "undo: 0x%ux\n", u.type);
|
||||||
abort();
|
abort();
|
||||||
|
@ -229,11 +202,11 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
|
||||||
|
|
||||||
case Delete:
|
case Delete:
|
||||||
f->seq = u.seq;
|
f->seq = u.seq;
|
||||||
fileundelete(f, epsilon, u.p0, u.p0+u.n);
|
fileundelete(f, epsilon, u.p0, u.p0 + u.n);
|
||||||
f->mod = u.mod;
|
f->mod = u.mod;
|
||||||
bufdelete(&f->b, u.p0, u.p0+u.n);
|
bufdelete(&f->b, u.p0, u.p0 + u.n);
|
||||||
for(j=0; j<f->ntext; j++)
|
for (j = 0; j < f->ntext; j++)
|
||||||
textdelete(f->text[j], u.p0, u.p0+u.n, FALSE);
|
textdelete(f->text[j], u.p0, u.p0 + u.n, FALSE);
|
||||||
*q0p = u.p0;
|
*q0p = u.p0;
|
||||||
*q1p = u.p0;
|
*q1p = u.p0;
|
||||||
break;
|
break;
|
||||||
|
@ -243,17 +216,17 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
|
||||||
fileuninsert(f, epsilon, u.p0, u.n);
|
fileuninsert(f, epsilon, u.p0, u.n);
|
||||||
f->mod = u.mod;
|
f->mod = u.mod;
|
||||||
up -= u.n;
|
up -= u.n;
|
||||||
for(i=0; i<u.n; i+=n){
|
for (i = 0; i < u.n; i += n) {
|
||||||
n = u.n - i;
|
n = u.n - i;
|
||||||
if(n > RBUFSIZE)
|
if (n > RBUFSIZE)
|
||||||
n = RBUFSIZE;
|
n = RBUFSIZE;
|
||||||
bufread(delta, up+i, buf, n);
|
bufread(delta, up + i, buf, n);
|
||||||
bufinsert(&f->b, u.p0+i, buf, n);
|
bufinsert(&f->b, u.p0 + i, buf, n);
|
||||||
for(j=0; j<f->ntext; j++)
|
for (j = 0; j < f->ntext; j++)
|
||||||
textinsert(f->text[j], u.p0+i, buf, n, FALSE);
|
textinsert(f->text[j], u.p0 + i, buf, n, FALSE);
|
||||||
}
|
}
|
||||||
*q0p = u.p0;
|
*q0p = u.p0;
|
||||||
*q1p = u.p0+u.n;
|
*q1p = u.p0 + u.n;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Filename:
|
case Filename:
|
||||||
|
@ -262,7 +235,7 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
|
||||||
f->mod = u.mod;
|
f->mod = u.mod;
|
||||||
up -= u.n;
|
up -= u.n;
|
||||||
free(f->name);
|
free(f->name);
|
||||||
if(u.n == 0)
|
if (u.n == 0)
|
||||||
f->name = nil;
|
f->name = nil;
|
||||||
else
|
else
|
||||||
f->name = runemalloc(u.n);
|
f->name = runemalloc(u.n);
|
||||||
|
@ -272,23 +245,19 @@ fileundo(File *f, int isundo, uint *q0p, uint *q1p)
|
||||||
}
|
}
|
||||||
bufdelete(delta, up, delta->nc);
|
bufdelete(delta, up, delta->nc);
|
||||||
}
|
}
|
||||||
if(isundo)
|
if (isundo)
|
||||||
f->seq = 0;
|
f->seq = 0;
|
||||||
Return:
|
Return:
|
||||||
fbuffree(buf);
|
fbuffree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void filereset(File* f) {
|
||||||
filereset(File *f)
|
|
||||||
{
|
|
||||||
bufreset(&f->delta);
|
bufreset(&f->delta);
|
||||||
bufreset(&f->epsilon);
|
bufreset(&f->epsilon);
|
||||||
f->seq = 0;
|
f->seq = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fileclose(File* f) {
|
||||||
fileclose(File *f)
|
|
||||||
{
|
|
||||||
free(f->name);
|
free(f->name);
|
||||||
f->nname = 0;
|
f->nname = 0;
|
||||||
f->name = nil;
|
f->name = nil;
|
||||||
|
@ -302,10 +271,8 @@ fileclose(File *f)
|
||||||
free(f);
|
free(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void filemark(File* f) {
|
||||||
filemark(File *f)
|
if (f->epsilon.nc)
|
||||||
{
|
|
||||||
if(f->epsilon.nc)
|
|
||||||
bufdelete(&f->epsilon, 0, f->epsilon.nc);
|
bufdelete(&f->epsilon, 0, f->epsilon.nc);
|
||||||
f->seq = seq;
|
f->seq = seq;
|
||||||
}
|
}
|
||||||
|
|
1
fns.h
1
fns.h
|
@ -95,6 +95,7 @@ void flushwarnings(void);
|
||||||
void startplumbing(void);
|
void startplumbing(void);
|
||||||
long nlcount(Text*, long, long, long*);
|
long nlcount(Text*, long, long, long*);
|
||||||
long nlcounttopos(Text*, long, long, long);
|
long nlcounttopos(Text*, long, long, long);
|
||||||
|
Rune* parsetag(Window*, int*);
|
||||||
|
|
||||||
Runestr runestr(Rune*, uint);
|
Runestr runestr(Rune*, uint);
|
||||||
Range range(int, int);
|
Range range(int, int);
|
||||||
|
|
411
fsys.c
411
fsys.c
|
@ -14,15 +14,11 @@
|
||||||
|
|
||||||
static int sfd;
|
static int sfd;
|
||||||
|
|
||||||
enum
|
enum { Nhash = 16, DEBUG = 0 };
|
||||||
{
|
|
||||||
Nhash = 16,
|
|
||||||
DEBUG = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static Fid *fids[Nhash];
|
static Fid* fids[Nhash];
|
||||||
|
|
||||||
Fid *newfid(int);
|
Fid* newfid(int);
|
||||||
|
|
||||||
static Xfid* fsysflush(Xfid*, Fid*);
|
static Xfid* fsysflush(Xfid*, Fid*);
|
||||||
static Xfid* fsysauth(Xfid*, Fid*);
|
static Xfid* fsysauth(Xfid*, Fid*);
|
||||||
|
@ -40,9 +36,7 @@ static Xfid* fsyswstat(Xfid*, Fid*);
|
||||||
|
|
||||||
Xfid* (*fcall[Tmax])(Xfid*, Fid*);
|
Xfid* (*fcall[Tmax])(Xfid*, Fid*);
|
||||||
|
|
||||||
static void
|
static void initfcall(void) {
|
||||||
initfcall(void)
|
|
||||||
{
|
|
||||||
fcall[Tflush] = fsysflush;
|
fcall[Tflush] = fsysflush;
|
||||||
fcall[Tversion] = fsysversion;
|
fcall[Tversion] = fsysversion;
|
||||||
fcall[Tauth] = fsysauth;
|
fcall[Tauth] = fsysauth;
|
||||||
|
@ -53,7 +47,7 @@ initfcall(void)
|
||||||
fcall[Tread] = fsysread;
|
fcall[Tread] = fsysread;
|
||||||
fcall[Twrite] = fsyswrite;
|
fcall[Twrite] = fsyswrite;
|
||||||
fcall[Tclunk] = fsysclunk;
|
fcall[Tclunk] = fsysclunk;
|
||||||
fcall[Tremove]= fsysremove;
|
fcall[Tremove] = fsysremove;
|
||||||
fcall[Tstat] = fsysstat;
|
fcall[Tstat] = fsysstat;
|
||||||
fcall[Twstat] = fsyswstat;
|
fcall[Twstat] = fsyswstat;
|
||||||
}
|
}
|
||||||
|
@ -62,44 +56,46 @@ char Eperm[] = "permission denied";
|
||||||
char Eexist[] = "file does not exist";
|
char Eexist[] = "file does not exist";
|
||||||
char Enotdir[] = "not a directory";
|
char Enotdir[] = "not a directory";
|
||||||
|
|
||||||
Dirtab dirtab[]=
|
Dirtab dirtab[] = {
|
||||||
{
|
{".", QTDIR, Qdir, 0500 | DMDIR},
|
||||||
{ ".", QTDIR, Qdir, 0500|DMDIR },
|
{"acme", QTDIR, Qacme, 0500 | DMDIR},
|
||||||
{ "acme", QTDIR, Qacme, 0500|DMDIR },
|
{"cons", QTFILE, Qcons, 0600},
|
||||||
{ "cons", QTFILE, Qcons, 0600 },
|
{"consctl", QTFILE, Qconsctl, 0000},
|
||||||
{ "consctl", QTFILE, Qconsctl, 0000 },
|
{"draw",
|
||||||
{ "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */
|
QTDIR,
|
||||||
{ "editout", QTFILE, Qeditout, 0200 },
|
Qdraw,
|
||||||
{ "index", QTFILE, Qindex, 0400 },
|
0000 | DMDIR}, /* to suppress graphics progs started in acme */
|
||||||
{ "label", QTFILE, Qlabel, 0600 },
|
{"editout", QTFILE, Qeditout, 0200},
|
||||||
{ "log", QTFILE, Qlog, 0400 },
|
{"index", QTFILE, Qindex, 0400},
|
||||||
{ "new", QTDIR, Qnew, 0500|DMDIR },
|
{"label", QTFILE, Qlabel, 0600},
|
||||||
{ nil, }
|
{"log", QTFILE, Qlog, 0400},
|
||||||
};
|
{"new", QTDIR, Qnew, 0500 | DMDIR},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
}};
|
||||||
|
|
||||||
Dirtab dirtabw[]=
|
Dirtab dirtabw[] = {
|
||||||
{
|
{".", QTDIR, Qdir, 0500 | DMDIR},
|
||||||
{ ".", QTDIR, Qdir, 0500|DMDIR },
|
{"addr", QTFILE, QWaddr, 0600},
|
||||||
{ "addr", QTFILE, QWaddr, 0600 },
|
{"body", QTAPPEND, QWbody, 0600 | DMAPPEND},
|
||||||
{ "body", QTAPPEND, QWbody, 0600|DMAPPEND },
|
{"ctl", QTFILE, QWctl, 0600},
|
||||||
{ "ctl", QTFILE, QWctl, 0600 },
|
{"data", QTFILE, QWdata, 0600},
|
||||||
{ "data", QTFILE, QWdata, 0600 },
|
{"editout", QTFILE, QWeditout, 0200},
|
||||||
{ "editout", QTFILE, QWeditout, 0200 },
|
{"errors", QTFILE, QWerrors, 0200},
|
||||||
{ "errors", QTFILE, QWerrors, 0200 },
|
{"event", QTFILE, QWevent, 0600},
|
||||||
{ "event", QTFILE, QWevent, 0600 },
|
{"rdsel", QTFILE, QWrdsel, 0400},
|
||||||
{ "rdsel", QTFILE, QWrdsel, 0400 },
|
{"wrsel", QTFILE, QWwrsel, 0200},
|
||||||
{ "wrsel", QTFILE, QWwrsel, 0200 },
|
{"tag", QTAPPEND, QWtag, 0600 | DMAPPEND},
|
||||||
{ "tag", QTAPPEND, QWtag, 0600|DMAPPEND },
|
{"xdata", QTFILE, QWxdata, 0600},
|
||||||
{ "xdata", QTFILE, QWxdata, 0600 },
|
{
|
||||||
{ nil, }
|
nil,
|
||||||
};
|
}};
|
||||||
|
|
||||||
typedef struct Mnt Mnt;
|
typedef struct Mnt Mnt;
|
||||||
struct Mnt
|
struct Mnt {
|
||||||
{
|
|
||||||
QLock lk;
|
QLock lk;
|
||||||
int id;
|
int id;
|
||||||
Mntdir *md;
|
Mntdir* md;
|
||||||
};
|
};
|
||||||
|
|
||||||
Mnt mnt;
|
Mnt mnt;
|
||||||
|
@ -108,64 +104,62 @@ Xfid* respond(Xfid*, Fcall*, char*);
|
||||||
int dostat(int, Dirtab*, uchar*, int, uint);
|
int dostat(int, Dirtab*, uchar*, int, uint);
|
||||||
uint getclock(void);
|
uint getclock(void);
|
||||||
|
|
||||||
char *user = "Wile E. Coyote";
|
char* user = "Wile E. Coyote";
|
||||||
static int closing = 0;
|
static int closing = 0;
|
||||||
int messagesize = Maxblock+IOHDRSZ; /* good start */
|
int messagesize = Maxblock + IOHDRSZ; /* good start */
|
||||||
|
|
||||||
void fsysproc(void *);
|
void fsysproc(void*);
|
||||||
|
|
||||||
void
|
void fsysinit(void) {
|
||||||
fsysinit(void)
|
|
||||||
{
|
|
||||||
int p[2];
|
int p[2];
|
||||||
char *u;
|
char* u;
|
||||||
|
|
||||||
initfcall();
|
initfcall();
|
||||||
if(pipe(p) < 0)
|
if (pipe(p) < 0)
|
||||||
error("can't create pipe");
|
error("can't create pipe");
|
||||||
if(post9pservice(p[0], "acme", mtpt) < 0)
|
if (post9pservice(p[0], "acme", mtpt) < 0)
|
||||||
error("can't post service");
|
error("can't post service");
|
||||||
sfd = p[1];
|
sfd = p[1];
|
||||||
fmtinstall('F', fcallfmt);
|
fmtinstall('F', fcallfmt);
|
||||||
if((u = getuser()) != nil)
|
if ((u = getuser()) != nil)
|
||||||
user = estrdup(u);
|
user = estrdup(u);
|
||||||
proccreate(fsysproc, nil, STACK);
|
proccreate(fsysproc, nil, STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fsysproc(void* v) {
|
||||||
fsysproc(void *v)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
Xfid *x;
|
Xfid* x;
|
||||||
Fid *f;
|
Fid* f;
|
||||||
Fcall t;
|
Fcall t;
|
||||||
uchar *buf;
|
uchar* buf;
|
||||||
|
|
||||||
threadsetname("fsysproc");
|
threadsetname("fsysproc");
|
||||||
|
|
||||||
USED(v);
|
USED(v);
|
||||||
x = nil;
|
x = nil;
|
||||||
for(;;){
|
for (;;) {
|
||||||
buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
|
buf = emalloc(
|
||||||
|
messagesize +
|
||||||
|
UTFmax); /* overflow for appending partial rune in xfidwrite */
|
||||||
n = read9pmsg(sfd, buf, messagesize);
|
n = read9pmsg(sfd, buf, messagesize);
|
||||||
if(n <= 0){
|
if (n <= 0) {
|
||||||
if(closing)
|
if (closing)
|
||||||
break;
|
break;
|
||||||
error("i/o error on server channel");
|
error("i/o error on server channel");
|
||||||
}
|
}
|
||||||
if(x == nil){
|
if (x == nil) {
|
||||||
sendp(cxfidalloc, nil);
|
sendp(cxfidalloc, nil);
|
||||||
x = recvp(cxfidalloc);
|
x = recvp(cxfidalloc);
|
||||||
}
|
}
|
||||||
x->buf = buf;
|
x->buf = buf;
|
||||||
if(convM2S(buf, n, &x->fcall) != n)
|
if (convM2S(buf, n, &x->fcall) != n)
|
||||||
error("convert error in convM2S");
|
error("convert error in convM2S");
|
||||||
if(DEBUG)
|
if (DEBUG)
|
||||||
fprint(2, "%F\n", &x->fcall);
|
fprint(2, "%F\n", &x->fcall);
|
||||||
if(fcall[x->fcall.type] == nil)
|
if (fcall[x->fcall.type] == nil)
|
||||||
x = respond(x, &t, "bad fcall type");
|
x = respond(x, &t, "bad fcall type");
|
||||||
else{
|
else {
|
||||||
switch(x->fcall.type){
|
switch (x->fcall.type) {
|
||||||
case Tversion:
|
case Tversion:
|
||||||
case Tauth:
|
case Tauth:
|
||||||
case Tflush:
|
case Tflush:
|
||||||
|
@ -176,7 +170,7 @@ fsysproc(void *v)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
f = newfid(x->fcall.fid);
|
f = newfid(x->fcall.fid);
|
||||||
if(!f->busy){
|
if (!f->busy) {
|
||||||
x->f = f;
|
x->f = f;
|
||||||
x = respond(x, &t, "fid not in use");
|
x = respond(x, &t, "fid not in use");
|
||||||
continue;
|
continue;
|
||||||
|
@ -189,10 +183,8 @@ fsysproc(void *v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mntdir*
|
Mntdir* fsysaddid(Rune* dir, int ndir, Rune** incl, int nincl) {
|
||||||
fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
|
Mntdir* m;
|
||||||
{
|
|
||||||
Mntdir *m;
|
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
qlock(&mnt.lk);
|
qlock(&mnt.lk);
|
||||||
|
@ -210,36 +202,32 @@ fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fsysincid(Mntdir* m) {
|
||||||
fsysincid(Mntdir *m)
|
|
||||||
{
|
|
||||||
qlock(&mnt.lk);
|
qlock(&mnt.lk);
|
||||||
m->ref++;
|
m->ref++;
|
||||||
qunlock(&mnt.lk);
|
qunlock(&mnt.lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fsysdelid(Mntdir* idm) {
|
||||||
fsysdelid(Mntdir *idm)
|
|
||||||
{
|
|
||||||
Mntdir *m, *prev;
|
Mntdir *m, *prev;
|
||||||
int i;
|
int i;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
if(idm == nil)
|
if (idm == nil)
|
||||||
return;
|
return;
|
||||||
qlock(&mnt.lk);
|
qlock(&mnt.lk);
|
||||||
if(--idm->ref > 0){
|
if (--idm->ref > 0) {
|
||||||
qunlock(&mnt.lk);
|
qunlock(&mnt.lk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
prev = nil;
|
prev = nil;
|
||||||
for(m=mnt.md; m; m=m->next){
|
for (m = mnt.md; m; m = m->next) {
|
||||||
if(m == idm){
|
if (m == idm) {
|
||||||
if(prev)
|
if (prev)
|
||||||
prev->next = m->next;
|
prev->next = m->next;
|
||||||
else
|
else
|
||||||
mnt.md = m->next;
|
mnt.md = m->next;
|
||||||
for(i=0; i<m->nincl; i++)
|
for (i = 0; i < m->nincl; i++)
|
||||||
free(m->incl[i]);
|
free(m->incl[i]);
|
||||||
free(m->incl);
|
free(m->incl);
|
||||||
free(m->dir);
|
free(m->dir);
|
||||||
|
@ -257,15 +245,11 @@ fsysdelid(Mntdir *idm)
|
||||||
/*
|
/*
|
||||||
* Called only in exec.c:/^run(), from a different FD group
|
* Called only in exec.c:/^run(), from a different FD group
|
||||||
*/
|
*/
|
||||||
Mntdir*
|
Mntdir* fsysmount(Rune* dir, int ndir, Rune** incl, int nincl) {
|
||||||
fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
|
|
||||||
{
|
|
||||||
return fsysaddid(dir, ndir, incl, nincl);
|
return fsysaddid(dir, ndir, incl, nincl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void fsysclose(void) {
|
||||||
fsysclose(void)
|
|
||||||
{
|
|
||||||
closing = 1;
|
closing = 1;
|
||||||
/*
|
/*
|
||||||
* apparently this is not kosher on openbsd.
|
* apparently this is not kosher on openbsd.
|
||||||
|
@ -275,78 +259,64 @@ fsysclose(void)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Xfid*
|
Xfid* respond(Xfid* x, Fcall* t, char* err) {
|
||||||
respond(Xfid *x, Fcall *t, char *err)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if(err){
|
if (err) {
|
||||||
t->type = Rerror;
|
t->type = Rerror;
|
||||||
t->ename = err;
|
t->ename = err;
|
||||||
}else
|
} else
|
||||||
t->type = x->fcall.type+1;
|
t->type = x->fcall.type + 1;
|
||||||
t->fid = x->fcall.fid;
|
t->fid = x->fcall.fid;
|
||||||
t->tag = x->fcall.tag;
|
t->tag = x->fcall.tag;
|
||||||
if(x->buf == nil)
|
if (x->buf == nil)
|
||||||
x->buf = emalloc(messagesize);
|
x->buf = emalloc(messagesize);
|
||||||
n = convS2M(t, x->buf, messagesize);
|
n = convS2M(t, x->buf, messagesize);
|
||||||
if(n <= 0)
|
if (n <= 0)
|
||||||
error("convert error in convS2M");
|
error("convert error in convS2M");
|
||||||
if(write(sfd, x->buf, n) != n)
|
if (write(sfd, x->buf, n) != n)
|
||||||
error("write error in respond");
|
error("write error in respond");
|
||||||
free(x->buf);
|
free(x->buf);
|
||||||
x->buf = nil;
|
x->buf = nil;
|
||||||
if(DEBUG)
|
if (DEBUG)
|
||||||
fprint(2, "r: %F\n", t);
|
fprint(2, "r: %F\n", t);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysversion(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysversion(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
|
|
||||||
USED(f);
|
USED(f);
|
||||||
if(x->fcall.msize < 256)
|
if (x->fcall.msize < 256)
|
||||||
return respond(x, &t, "version: message size too small");
|
return respond(x, &t, "version: message size too small");
|
||||||
messagesize = x->fcall.msize;
|
messagesize = x->fcall.msize;
|
||||||
t.msize = messagesize;
|
t.msize = messagesize;
|
||||||
if(strncmp(x->fcall.version, "9P2000", 6) != 0)
|
if (strncmp(x->fcall.version, "9P2000", 6) != 0)
|
||||||
return respond(x, &t, "unrecognized 9P version");
|
return respond(x, &t, "unrecognized 9P version");
|
||||||
t.version = "9P2000";
|
t.version = "9P2000";
|
||||||
return respond(x, &t, nil);
|
return respond(x, &t, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysauth(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysauth(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
|
|
||||||
USED(f);
|
USED(f);
|
||||||
return respond(x, &t, "acme: authentication not required");
|
return respond(x, &t, "acme: authentication not required");
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysflush(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysflush(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
USED(f);
|
USED(f);
|
||||||
sendp(x->c, (void*)xfidflush);
|
sendp(x->c, (void*)xfidflush);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysattach(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysattach(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
int id;
|
int id;
|
||||||
Mntdir *m;
|
Mntdir* m;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
|
|
||||||
if(strcmp(x->fcall.uname, user) != 0)
|
if (strcmp(x->fcall.uname, user) != 0)
|
||||||
return respond(x, &t, Eperm);
|
return respond(x, &t, Eperm);
|
||||||
f->busy = TRUE;
|
f->busy = TRUE;
|
||||||
f->open = FALSE;
|
f->open = FALSE;
|
||||||
|
@ -360,13 +330,13 @@ fsysattach(Xfid *x, Fid *f)
|
||||||
f->mntdir = nil;
|
f->mntdir = nil;
|
||||||
id = atoi(x->fcall.aname);
|
id = atoi(x->fcall.aname);
|
||||||
qlock(&mnt.lk);
|
qlock(&mnt.lk);
|
||||||
for(m=mnt.md; m; m=m->next)
|
for (m = mnt.md; m; m = m->next)
|
||||||
if(m->id == id){
|
if (m->id == id) {
|
||||||
f->mntdir = m;
|
f->mntdir = m;
|
||||||
m->ref++;
|
m->ref++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(m == nil && x->fcall.aname[0]){
|
if (m == nil && x->fcall.aname[0]) {
|
||||||
snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
|
snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
|
||||||
sendp(cerr, estrdup(buf));
|
sendp(cerr, estrdup(buf));
|
||||||
}
|
}
|
||||||
|
@ -374,38 +344,35 @@ fsysattach(Xfid *x, Fid *f)
|
||||||
return respond(x, &t, nil);
|
return respond(x, &t, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsyswalk(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsyswalk(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
int c, i, j, id;
|
int c, i, j, id;
|
||||||
Qid q;
|
Qid q;
|
||||||
uchar type;
|
uchar type;
|
||||||
ulong path;
|
ulong path;
|
||||||
Fid *nf;
|
Fid* nf;
|
||||||
Dirtab *d, *dir;
|
Dirtab *d, *dir;
|
||||||
Window *w;
|
Window* w;
|
||||||
char *err;
|
char* err;
|
||||||
|
|
||||||
nf = nil;
|
nf = nil;
|
||||||
w = nil;
|
w = nil;
|
||||||
if(f->open)
|
if (f->open)
|
||||||
return respond(x, &t, "walk of open file");
|
return respond(x, &t, "walk of open file");
|
||||||
if(x->fcall.fid != x->fcall.newfid){
|
if (x->fcall.fid != x->fcall.newfid) {
|
||||||
nf = newfid(x->fcall.newfid);
|
nf = newfid(x->fcall.newfid);
|
||||||
if(nf->busy)
|
if (nf->busy)
|
||||||
return respond(x, &t, "newfid already in use");
|
return respond(x, &t, "newfid already in use");
|
||||||
nf->busy = TRUE;
|
nf->busy = TRUE;
|
||||||
nf->open = FALSE;
|
nf->open = FALSE;
|
||||||
nf->mntdir = f->mntdir;
|
nf->mntdir = f->mntdir;
|
||||||
if(f->mntdir)
|
if (f->mntdir)
|
||||||
f->mntdir->ref++;
|
f->mntdir->ref++;
|
||||||
nf->dir = f->dir;
|
nf->dir = f->dir;
|
||||||
nf->qid = f->qid;
|
nf->qid = f->qid;
|
||||||
nf->w = f->w;
|
nf->w = f->w;
|
||||||
nf->nrpart = 0; /* not open, so must be zero */
|
nf->nrpart = 0; /* not open, so must be zero */
|
||||||
if(nf->w)
|
if (nf->w)
|
||||||
incref(&nf->w->ref);
|
incref(&nf->w->ref);
|
||||||
f = nf; /* walk f */
|
f = nf; /* walk f */
|
||||||
}
|
}
|
||||||
|
@ -416,23 +383,23 @@ fsyswalk(Xfid *x, Fid *f)
|
||||||
id = WIN(f->qid);
|
id = WIN(f->qid);
|
||||||
q = f->qid;
|
q = f->qid;
|
||||||
|
|
||||||
if(x->fcall.nwname > 0){
|
if (x->fcall.nwname > 0) {
|
||||||
for(i=0; i<x->fcall.nwname; i++){
|
for (i = 0; i < x->fcall.nwname; i++) {
|
||||||
if((q.type & QTDIR) == 0){
|
if ((q.type & QTDIR) == 0) {
|
||||||
err = Enotdir;
|
err = Enotdir;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(x->fcall.wname[i], "..") == 0){
|
if (strcmp(x->fcall.wname[i], "..") == 0) {
|
||||||
type = QTDIR;
|
type = QTDIR;
|
||||||
path = Qdir;
|
path = Qdir;
|
||||||
id = 0;
|
id = 0;
|
||||||
if(w){
|
if (w) {
|
||||||
winclose(w);
|
winclose(w);
|
||||||
w = nil;
|
w = nil;
|
||||||
}
|
}
|
||||||
Accept:
|
Accept:
|
||||||
if(i == MAXWELEM){
|
if (i == MAXWELEM) {
|
||||||
err = "name too long";
|
err = "name too long";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -444,16 +411,16 @@ fsyswalk(Xfid *x, Fid *f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* is it a numeric name? */
|
/* is it a numeric name? */
|
||||||
for(j=0; (c=x->fcall.wname[i][j]); j++)
|
for (j = 0; (c = x->fcall.wname[i][j]); j++)
|
||||||
if(c<'0' || '9'<c)
|
if (c < '0' || '9' < c)
|
||||||
goto Regular;
|
goto Regular;
|
||||||
/* yes: it's a directory */
|
/* yes: it's a directory */
|
||||||
if(w) /* name has form 27/23; get out before losing w */
|
if (w) /* name has form 27/23; get out before losing w */
|
||||||
break;
|
break;
|
||||||
id = atoi(x->fcall.wname[i]);
|
id = atoi(x->fcall.wname[i]);
|
||||||
qlock(&row.lk);
|
qlock(&row.lk);
|
||||||
w = lookid(id, FALSE);
|
w = lookid(id, FALSE);
|
||||||
if(w == nil){
|
if (w == nil) {
|
||||||
qunlock(&row.lk);
|
qunlock(&row.lk);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -465,8 +432,8 @@ fsyswalk(Xfid *x, Fid *f)
|
||||||
goto Accept;
|
goto Accept;
|
||||||
|
|
||||||
Regular:
|
Regular:
|
||||||
if(strcmp(x->fcall.wname[i], "new") == 0){
|
if (strcmp(x->fcall.wname[i], "new") == 0) {
|
||||||
if(w)
|
if (w)
|
||||||
error("w set in walk to new");
|
error("w set in walk to new");
|
||||||
sendp(cnewwindow, nil); /* signal newwindowthread */
|
sendp(cnewwindow, nil); /* signal newwindowthread */
|
||||||
w = recvp(cnewwindow); /* receive new window */
|
w = recvp(cnewwindow); /* receive new window */
|
||||||
|
@ -478,13 +445,13 @@ fsyswalk(Xfid *x, Fid *f)
|
||||||
goto Accept;
|
goto Accept;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == 0)
|
if (id == 0)
|
||||||
d = dirtab;
|
d = dirtab;
|
||||||
else
|
else
|
||||||
d = dirtabw;
|
d = dirtabw;
|
||||||
d++; /* skip '.' */
|
d++; /* skip '.' */
|
||||||
for(; d->name; d++)
|
for (; d->name; d++)
|
||||||
if(strcmp(x->fcall.wname[i], d->name) == 0){
|
if (strcmp(x->fcall.wname[i], d->name) == 0) {
|
||||||
path = d->qid;
|
path = d->qid;
|
||||||
type = d->type;
|
type = d->type;
|
||||||
dir = d;
|
dir = d;
|
||||||
|
@ -494,44 +461,41 @@ fsyswalk(Xfid *x, Fid *f)
|
||||||
break; /* file not found */
|
break; /* file not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i==0 && err == nil)
|
if (i == 0 && err == nil)
|
||||||
err = Eexist;
|
err = Eexist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(err!=nil || t.nwqid<x->fcall.nwname){
|
if (err != nil || t.nwqid < x->fcall.nwname) {
|
||||||
if(nf){
|
if (nf) {
|
||||||
nf->busy = FALSE;
|
nf->busy = FALSE;
|
||||||
fsysdelid(nf->mntdir);
|
fsysdelid(nf->mntdir);
|
||||||
}
|
}
|
||||||
}else if(t.nwqid == x->fcall.nwname){
|
} else if (t.nwqid == x->fcall.nwname) {
|
||||||
if(w){
|
if (w) {
|
||||||
f->w = w;
|
f->w = w;
|
||||||
w = nil; /* don't drop the reference */
|
w = nil; /* don't drop the reference */
|
||||||
}
|
}
|
||||||
if(dir)
|
if (dir)
|
||||||
f->dir = dir;
|
f->dir = dir;
|
||||||
f->qid = q;
|
f->qid = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(w != nil)
|
if (w != nil)
|
||||||
winclose(w);
|
winclose(w);
|
||||||
|
|
||||||
return respond(x, &t, err);
|
return respond(x, &t, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysopen(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysopen(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
int m;
|
int m;
|
||||||
|
|
||||||
/* can't truncate anything, so just disregard */
|
/* can't truncate anything, so just disregard */
|
||||||
x->fcall.mode &= ~(OTRUNC|OCEXEC);
|
x->fcall.mode &= ~(OTRUNC | OCEXEC);
|
||||||
/* can't execute or remove anything */
|
/* can't execute or remove anything */
|
||||||
if(x->fcall.mode==OEXEC || (x->fcall.mode&ORCLOSE))
|
if (x->fcall.mode == OEXEC || (x->fcall.mode & ORCLOSE))
|
||||||
goto Deny;
|
goto Deny;
|
||||||
switch(x->fcall.mode){
|
switch (x->fcall.mode) {
|
||||||
default:
|
default:
|
||||||
goto Deny;
|
goto Deny;
|
||||||
case OREAD:
|
case OREAD:
|
||||||
|
@ -544,79 +508,68 @@ fsysopen(Xfid *x, Fid *f)
|
||||||
m = 0600;
|
m = 0600;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
|
if (((f->dir->perm & ~(DMDIR | DMAPPEND)) & m) != m)
|
||||||
goto Deny;
|
goto Deny;
|
||||||
|
|
||||||
sendp(x->c, (void*)xfidopen);
|
sendp(x->c, (void*)xfidopen);
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
Deny:
|
Deny:
|
||||||
return respond(x, &t, Eperm);
|
return respond(x, &t, Eperm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsyscreate(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsyscreate(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
|
|
||||||
USED(f);
|
USED(f);
|
||||||
return respond(x, &t, Eperm);
|
return respond(x, &t, Eperm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int idcmp(const void* a, const void* b) { return *(int*)a - *(int*)b; }
|
||||||
int
|
|
||||||
idcmp(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
return *(int*)a - *(int*)b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static Xfid* fsysread(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysread(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
uchar *b;
|
uchar* b;
|
||||||
int i, id, n, o, e, j, k, *ids, nids;
|
int i, id, n, o, e, j, k, *ids, nids;
|
||||||
Dirtab *d, dt;
|
Dirtab *d, dt;
|
||||||
Column *c;
|
Column* c;
|
||||||
uint clock, len;
|
uint clock, len;
|
||||||
char buf[16];
|
char buf[16];
|
||||||
|
|
||||||
if(f->qid.type & QTDIR){
|
if (f->qid.type & QTDIR) {
|
||||||
if(FILE(f->qid) == Qacme){ /* empty dir */
|
if (FILE(f->qid) == Qacme) { /* empty dir */
|
||||||
t.data = nil;
|
t.data = nil;
|
||||||
t.count = 0;
|
t.count = 0;
|
||||||
respond(x, &t, nil);
|
respond(x, &t, nil);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
o = x->fcall.offset;
|
o = x->fcall.offset;
|
||||||
e = x->fcall.offset+x->fcall.count;
|
e = x->fcall.offset + x->fcall.count;
|
||||||
clock = getclock();
|
clock = getclock();
|
||||||
b = emalloc(messagesize);
|
b = emalloc(messagesize);
|
||||||
id = WIN(f->qid);
|
id = WIN(f->qid);
|
||||||
n = 0;
|
n = 0;
|
||||||
if(id > 0)
|
if (id > 0)
|
||||||
d = dirtabw;
|
d = dirtabw;
|
||||||
else
|
else
|
||||||
d = dirtab;
|
d = dirtab;
|
||||||
d++; /* first entry is '.' */
|
d++; /* first entry is '.' */
|
||||||
for(i=0; d->name!=nil && i<e; i+=len){
|
for (i = 0; d->name != nil && i < e; i += len) {
|
||||||
len = dostat(WIN(x->f->qid), d, b+n, x->fcall.count-n, clock);
|
len = dostat(WIN(x->f->qid), d, b + n, x->fcall.count - n, clock);
|
||||||
if(len <= BIT16SZ)
|
if (len <= BIT16SZ)
|
||||||
break;
|
break;
|
||||||
if(i >= o)
|
if (i >= o)
|
||||||
n += len;
|
n += len;
|
||||||
d++;
|
d++;
|
||||||
}
|
}
|
||||||
if(id == 0){
|
if (id == 0) {
|
||||||
qlock(&row.lk);
|
qlock(&row.lk);
|
||||||
nids = 0;
|
nids = 0;
|
||||||
ids = nil;
|
ids = nil;
|
||||||
for(j=0; j<row.ncol; j++){
|
for (j = 0; j < row.ncol; j++) {
|
||||||
c = row.col[j];
|
c = row.col[j];
|
||||||
for(k=0; k<c->nw; k++){
|
for (k = 0; k < c->nw; k++) {
|
||||||
ids = realloc(ids, (nids+1)*sizeof(int));
|
ids = realloc(ids, (nids + 1) * sizeof(int));
|
||||||
ids[nids++] = c->w[k]->id;
|
ids[nids++] = c->w[k]->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -624,16 +577,16 @@ fsysread(Xfid *x, Fid *f)
|
||||||
qsort(ids, nids, sizeof ids[0], idcmp);
|
qsort(ids, nids, sizeof ids[0], idcmp);
|
||||||
j = 0;
|
j = 0;
|
||||||
dt.name = buf;
|
dt.name = buf;
|
||||||
for(; j<nids && i<e; i+=len){
|
for (; j < nids && i < e; i += len) {
|
||||||
k = ids[j];
|
k = ids[j];
|
||||||
sprint(dt.name, "%d", k);
|
sprint(dt.name, "%d", k);
|
||||||
dt.qid = QID(k, Qdir);
|
dt.qid = QID(k, Qdir);
|
||||||
dt.type = QTDIR;
|
dt.type = QTDIR;
|
||||||
dt.perm = DMDIR|0700;
|
dt.perm = DMDIR | 0700;
|
||||||
len = dostat(k, &dt, b+n, x->fcall.count-n, clock);
|
len = dostat(k, &dt, b + n, x->fcall.count - n, clock);
|
||||||
if(len == 0)
|
if (len == 0)
|
||||||
break;
|
break;
|
||||||
if(i >= o)
|
if (i >= o)
|
||||||
n += len;
|
n += len;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
@ -649,70 +602,54 @@ fsysread(Xfid *x, Fid *f)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsyswrite(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsyswrite(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
USED(f);
|
USED(f);
|
||||||
sendp(x->c, (void*)xfidwrite);
|
sendp(x->c, (void*)xfidwrite);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysclunk(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysclunk(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
fsysdelid(f->mntdir);
|
fsysdelid(f->mntdir);
|
||||||
sendp(x->c, (void*)xfidclose);
|
sendp(x->c, (void*)xfidclose);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysremove(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysremove(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
|
|
||||||
USED(f);
|
USED(f);
|
||||||
return respond(x, &t, Eperm);
|
return respond(x, &t, Eperm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsysstat(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsysstat(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
|
|
||||||
t.stat = emalloc(messagesize-IOHDRSZ);
|
t.stat = emalloc(messagesize - IOHDRSZ);
|
||||||
t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
|
t.nstat =
|
||||||
|
dostat(WIN(x->f->qid), f->dir, t.stat, messagesize - IOHDRSZ, getclock());
|
||||||
x = respond(x, &t, nil);
|
x = respond(x, &t, nil);
|
||||||
free(t.stat);
|
free(t.stat);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Xfid* fsyswstat(Xfid* x, Fid* f) {
|
||||||
Xfid*
|
|
||||||
fsyswstat(Xfid *x, Fid *f)
|
|
||||||
{
|
|
||||||
Fcall t;
|
Fcall t;
|
||||||
|
|
||||||
USED(f);
|
USED(f);
|
||||||
return respond(x, &t, Eperm);
|
return respond(x, &t, Eperm);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fid*
|
Fid* newfid(int fid) {
|
||||||
newfid(int fid)
|
|
||||||
{
|
|
||||||
Fid *f, *ff, **fh;
|
Fid *f, *ff, **fh;
|
||||||
|
|
||||||
ff = nil;
|
ff = nil;
|
||||||
fh = &fids[fid&(Nhash-1)];
|
fh = &fids[fid & (Nhash - 1)];
|
||||||
for(f=*fh; f; f=f->next)
|
for (f = *fh; f; f = f->next)
|
||||||
if(f->fid == fid)
|
if (f->fid == fid)
|
||||||
return f;
|
return f;
|
||||||
else if(ff==nil && f->busy==FALSE)
|
else if (ff == nil && f->busy == FALSE)
|
||||||
ff = f;
|
ff = f;
|
||||||
if(ff){
|
if (ff) {
|
||||||
ff->fid = fid;
|
ff->fid = fid;
|
||||||
return ff;
|
return ff;
|
||||||
}
|
}
|
||||||
|
@ -723,15 +660,9 @@ newfid(int fid)
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint getclock(void) { return time(0); }
|
||||||
getclock(void)
|
|
||||||
{
|
|
||||||
return time(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int dostat(int id, Dirtab* dir, uchar* buf, int nbuf, uint clock) {
|
||||||
dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
|
|
||||||
{
|
|
||||||
Dir d;
|
Dir d;
|
||||||
|
|
||||||
d.qid.path = QID(id, dir->qid);
|
d.qid.path = QID(id, dir->qid);
|
||||||
|
|
99
logf.c
99
logf.c
|
@ -14,40 +14,37 @@
|
||||||
|
|
||||||
// State for global log file.
|
// State for global log file.
|
||||||
typedef struct Log Log;
|
typedef struct Log Log;
|
||||||
struct Log
|
struct Log {
|
||||||
{
|
|
||||||
QLock lk;
|
QLock lk;
|
||||||
Rendez r;
|
Rendez r;
|
||||||
|
|
||||||
vlong start; // msg[0] corresponds to 'start' in the global sequence of events
|
vlong start; // msg[0] corresponds to 'start' in the global sequence of events
|
||||||
|
|
||||||
// queued events (nev=entries in ev, mev=capacity of p)
|
// queued events (nev=entries in ev, mev=capacity of p)
|
||||||
char **ev;
|
char** ev;
|
||||||
int nev;
|
int nev;
|
||||||
int mev;
|
int mev;
|
||||||
|
|
||||||
// open acme/put files that need to read events
|
// open acme/put files that need to read events
|
||||||
Fid **f;
|
Fid** f;
|
||||||
int nf;
|
int nf;
|
||||||
int mf;
|
int mf;
|
||||||
|
|
||||||
// active (blocked) reads waiting for events
|
// active (blocked) reads waiting for events
|
||||||
Xfid **read;
|
Xfid** read;
|
||||||
int nread;
|
int nread;
|
||||||
int mread;
|
int mread;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Log eventlog;
|
static Log eventlog;
|
||||||
|
|
||||||
void
|
void xfidlogopen(Xfid* x) {
|
||||||
xfidlogopen(Xfid *x)
|
|
||||||
{
|
|
||||||
qlock(&eventlog.lk);
|
qlock(&eventlog.lk);
|
||||||
if(eventlog.nf >= eventlog.mf) {
|
if (eventlog.nf >= eventlog.mf) {
|
||||||
eventlog.mf = eventlog.mf*2;
|
eventlog.mf = eventlog.mf * 2;
|
||||||
if(eventlog.mf == 0)
|
if (eventlog.mf == 0)
|
||||||
eventlog.mf = 8;
|
eventlog.mf = 8;
|
||||||
eventlog.f = erealloc(eventlog.f, eventlog.mf*sizeof eventlog.f[0]);
|
eventlog.f = erealloc(eventlog.f, eventlog.mf * sizeof eventlog.f[0]);
|
||||||
}
|
}
|
||||||
eventlog.f[eventlog.nf++] = x->f;
|
eventlog.f[eventlog.nf++] = x->f;
|
||||||
x->f->logoff = eventlog.start + eventlog.nev;
|
x->f->logoff = eventlog.start + eventlog.nev;
|
||||||
|
@ -55,14 +52,12 @@ xfidlogopen(Xfid *x)
|
||||||
qunlock(&eventlog.lk);
|
qunlock(&eventlog.lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void xfidlogclose(Xfid* x) {
|
||||||
xfidlogclose(Xfid *x)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
qlock(&eventlog.lk);
|
qlock(&eventlog.lk);
|
||||||
for(i=0; i<eventlog.nf; i++) {
|
for (i = 0; i < eventlog.nf; i++) {
|
||||||
if(eventlog.f[i] == x->f) {
|
if (eventlog.f[i] == x->f) {
|
||||||
eventlog.f[i] = eventlog.f[--eventlog.nf];
|
eventlog.f[i] = eventlog.f[--eventlog.nf];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -70,36 +65,35 @@ xfidlogclose(Xfid *x)
|
||||||
qunlock(&eventlog.lk);
|
qunlock(&eventlog.lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void xfidlogread(Xfid* x) {
|
||||||
xfidlogread(Xfid *x)
|
char* p;
|
||||||
{
|
|
||||||
char *p;
|
|
||||||
int i;
|
int i;
|
||||||
Fcall fc;
|
Fcall fc;
|
||||||
|
|
||||||
qlock(&eventlog.lk);
|
qlock(&eventlog.lk);
|
||||||
if(eventlog.nread >= eventlog.mread) {
|
if (eventlog.nread >= eventlog.mread) {
|
||||||
eventlog.mread = eventlog.mread*2;
|
eventlog.mread = eventlog.mread * 2;
|
||||||
if(eventlog.mread == 0)
|
if (eventlog.mread == 0)
|
||||||
eventlog.mread = 8;
|
eventlog.mread = 8;
|
||||||
eventlog.read = erealloc(eventlog.read, eventlog.mread*sizeof eventlog.read[0]);
|
eventlog.read =
|
||||||
|
erealloc(eventlog.read, eventlog.mread * sizeof eventlog.read[0]);
|
||||||
}
|
}
|
||||||
eventlog.read[eventlog.nread++] = x;
|
eventlog.read[eventlog.nread++] = x;
|
||||||
|
|
||||||
if(eventlog.r.l == nil)
|
if (eventlog.r.l == nil)
|
||||||
eventlog.r.l = &eventlog.lk;
|
eventlog.r.l = &eventlog.lk;
|
||||||
x->flushed = FALSE;
|
x->flushed = FALSE;
|
||||||
while(x->f->logoff >= eventlog.start+eventlog.nev && !x->flushed)
|
while (x->f->logoff >= eventlog.start + eventlog.nev && !x->flushed)
|
||||||
rsleep(&eventlog.r);
|
rsleep(&eventlog.r);
|
||||||
|
|
||||||
for(i=0; i<eventlog.nread; i++) {
|
for (i = 0; i < eventlog.nread; i++) {
|
||||||
if(eventlog.read[i] == x) {
|
if (eventlog.read[i] == x) {
|
||||||
eventlog.read[i] = eventlog.read[--eventlog.nread];
|
eventlog.read[i] = eventlog.read[--eventlog.nread];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(x->flushed) {
|
if (x->flushed) {
|
||||||
qunlock(&eventlog.lk);
|
qunlock(&eventlog.lk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -115,16 +109,14 @@ xfidlogread(Xfid *x)
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void xfidlogflush(Xfid* x) {
|
||||||
xfidlogflush(Xfid *x)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
Xfid *rx;
|
Xfid* rx;
|
||||||
|
|
||||||
qlock(&eventlog.lk);
|
qlock(&eventlog.lk);
|
||||||
for(i=0; i<eventlog.nread; i++) {
|
for (i = 0; i < eventlog.nread; i++) {
|
||||||
rx = eventlog.read[i];
|
rx = eventlog.read[i];
|
||||||
if(rx->fcall.tag == x->fcall.oldtag) {
|
if (rx->fcall.tag == x->fcall.oldtag) {
|
||||||
rx->flushed = TRUE;
|
rx->flushed = TRUE;
|
||||||
rwakeupall(&eventlog.r);
|
rwakeupall(&eventlog.r);
|
||||||
}
|
}
|
||||||
|
@ -153,46 +145,47 @@ xfidlogflush(Xfid *x)
|
||||||
* op == "del" for deleted window
|
* op == "del" for deleted window
|
||||||
* - called from winclose
|
* - called from winclose
|
||||||
*/
|
*/
|
||||||
void
|
void xfidlog(Window* w, char* op) {
|
||||||
xfidlog(Window *w, char *op)
|
|
||||||
{
|
|
||||||
int i, n;
|
int i, n;
|
||||||
vlong min;
|
vlong min;
|
||||||
File *f;
|
File* f;
|
||||||
char *name;
|
char* name;
|
||||||
|
|
||||||
qlock(&eventlog.lk);
|
qlock(&eventlog.lk);
|
||||||
if(eventlog.nev >= eventlog.mev) {
|
if (eventlog.nev >= eventlog.mev) {
|
||||||
// Remove and free any entries that all readers have read.
|
// Remove and free any entries that all readers have read.
|
||||||
min = eventlog.start + eventlog.nev;
|
min = eventlog.start + eventlog.nev;
|
||||||
for(i=0; i<eventlog.nf; i++) {
|
for (i = 0; i < eventlog.nf; i++) {
|
||||||
if(min > eventlog.f[i]->logoff)
|
if (min > eventlog.f[i]->logoff)
|
||||||
min = eventlog.f[i]->logoff;
|
min = eventlog.f[i]->logoff;
|
||||||
}
|
}
|
||||||
if(min > eventlog.start) {
|
if (min > eventlog.start) {
|
||||||
n = min - eventlog.start;
|
n = min - eventlog.start;
|
||||||
for(i=0; i<n; i++)
|
for (i = 0; i < n; i++)
|
||||||
free(eventlog.ev[i]);
|
free(eventlog.ev[i]);
|
||||||
eventlog.nev -= n;
|
eventlog.nev -= n;
|
||||||
eventlog.start += n;
|
eventlog.start += n;
|
||||||
memmove(eventlog.ev, eventlog.ev+n, eventlog.nev*sizeof eventlog.ev[0]);
|
memmove(
|
||||||
|
eventlog.ev,
|
||||||
|
eventlog.ev + n,
|
||||||
|
eventlog.nev * sizeof eventlog.ev[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise grow.
|
// Otherwise grow.
|
||||||
if(eventlog.nev >= eventlog.mev) {
|
if (eventlog.nev >= eventlog.mev) {
|
||||||
eventlog.mev = eventlog.mev*2;
|
eventlog.mev = eventlog.mev * 2;
|
||||||
if(eventlog.mev == 0)
|
if (eventlog.mev == 0)
|
||||||
eventlog.mev = 8;
|
eventlog.mev = 8;
|
||||||
eventlog.ev = erealloc(eventlog.ev, eventlog.mev*sizeof eventlog.ev[0]);
|
eventlog.ev = erealloc(eventlog.ev, eventlog.mev * sizeof eventlog.ev[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f = w->body.file;
|
f = w->body.file;
|
||||||
name = runetobyte(f->name, f->nname);
|
name = runetobyte(f->name, f->nname);
|
||||||
if(name == nil)
|
if (name == nil)
|
||||||
name = estrdup("");
|
name = estrdup("");
|
||||||
eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name);
|
eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name);
|
||||||
free(name);
|
free(name);
|
||||||
if(eventlog.r.l == nil)
|
if (eventlog.r.l == nil)
|
||||||
eventlog.r.l = &eventlog.lk;
|
eventlog.r.l = &eventlog.lk;
|
||||||
rwakeupall(&eventlog.r);
|
rwakeupall(&eventlog.r);
|
||||||
qunlock(&eventlog.lk);
|
qunlock(&eventlog.lk);
|
||||||
|
|
32
mail/html.c
32
mail/html.c
|
@ -7,23 +7,21 @@
|
||||||
#include <9pclient.h>
|
#include <9pclient.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
|
|
||||||
char*
|
char* formathtml(char* body, int* np) {
|
||||||
formathtml(char *body, int *np)
|
|
||||||
{
|
|
||||||
int i, j, p[2], q[2];
|
int i, j, p[2], q[2];
|
||||||
Exec *e;
|
Exec* e;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
Channel *sync;
|
Channel* sync;
|
||||||
|
|
||||||
e = emalloc(sizeof(struct Exec));
|
e = emalloc(sizeof(struct Exec));
|
||||||
if(pipe(p) < 0 || pipe(q) < 0)
|
if (pipe(p) < 0 || pipe(q) < 0)
|
||||||
error("can't create pipe: %r");
|
error("can't create pipe: %r");
|
||||||
|
|
||||||
e->p[0] = p[0];
|
e->p[0] = p[0];
|
||||||
e->p[1] = p[1];
|
e->p[1] = p[1];
|
||||||
e->q[0] = q[0];
|
e->q[0] = q[0];
|
||||||
e->q[1] = q[1];
|
e->q[1] = q[1];
|
||||||
e->argv = emalloc(3*sizeof(char*));
|
e->argv = emalloc(3 * sizeof(char*));
|
||||||
e->argv[0] = estrdup("htmlfmt");
|
e->argv[0] = estrdup("htmlfmt");
|
||||||
e->argv[1] = estrdup("-cutf-8");
|
e->argv[1] = estrdup("-cutf-8");
|
||||||
e->argv[2] = nil;
|
e->argv[2] = nil;
|
||||||
|
@ -35,7 +33,7 @@ formathtml(char *body, int *np)
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
close(q[1]);
|
close(q[1]);
|
||||||
|
|
||||||
if((i=write(p[1], body, *np)) != *np){
|
if ((i = write(p[1], body, *np)) != *np) {
|
||||||
fprint(2, "Mail: warning: htmlfmt failed: wrote %d of %d: %r\n", i, *np);
|
fprint(2, "Mail: warning: htmlfmt failed: wrote %d of %d: %r\n", i, *np);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
close(q[0]);
|
close(q[0]);
|
||||||
|
@ -46,14 +44,14 @@ formathtml(char *body, int *np)
|
||||||
free(body);
|
free(body);
|
||||||
body = nil;
|
body = nil;
|
||||||
i = 0;
|
i = 0;
|
||||||
for(;;){
|
for (;;) {
|
||||||
j = read(q[0], buf, sizeof buf);
|
j = read(q[0], buf, sizeof buf);
|
||||||
if(j <= 0)
|
if (j <= 0)
|
||||||
break;
|
break;
|
||||||
body = realloc(body, i+j+1);
|
body = realloc(body, i + j + 1);
|
||||||
if(body == nil)
|
if (body == nil)
|
||||||
error("realloc failed: %r");
|
error("realloc failed: %r");
|
||||||
memmove(body+i, buf, j);
|
memmove(body + i, buf, j);
|
||||||
i += j;
|
i += j;
|
||||||
body[i] = '\0';
|
body[i] = '\0';
|
||||||
}
|
}
|
||||||
|
@ -63,13 +61,11 @@ formathtml(char *body, int *np)
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* readbody(char* type, char* dir, int* np) {
|
||||||
readbody(char *type, char *dir, int *np)
|
char* body;
|
||||||
{
|
|
||||||
char *body;
|
|
||||||
|
|
||||||
body = readfile(dir, "body", np);
|
body = readfile(dir, "body", np);
|
||||||
if(body != nil && strcmp(type, "text/html") == 0)
|
if (body != nil && strcmp(type, "text/html") == 0)
|
||||||
return formathtml(body, np);
|
return formathtml(body, np);
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
BIN
mail/html.o
BIN
mail/html.o
Binary file not shown.
392
mail/mail.c
392
mail/mail.c
|
@ -7,25 +7,25 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
|
|
||||||
char *maildir = "Mail/"; /* mountpoint of mail file system */
|
char* maildir = "Mail/"; /* mountpoint of mail file system */
|
||||||
char *mboxname = "mbox"; /* mailboxdir/mboxname is mail spool file */
|
char* mboxname = "mbox"; /* mailboxdir/mboxname is mail spool file */
|
||||||
char *mailboxdir = nil; /* nil == /mail/box/$user */
|
char* mailboxdir = nil; /* nil == /mail/box/$user */
|
||||||
char *fsname; /* filesystem for mailboxdir/mboxname is at maildir/fsname */
|
char* fsname; /* filesystem for mailboxdir/mboxname is at maildir/fsname */
|
||||||
char *user;
|
char* user;
|
||||||
char *outgoing;
|
char* outgoing;
|
||||||
char *srvname;
|
char* srvname;
|
||||||
|
|
||||||
Window *wbox;
|
Window* wbox;
|
||||||
Message mbox;
|
Message mbox;
|
||||||
Message replies;
|
Message replies;
|
||||||
char *home;
|
char* home;
|
||||||
CFid *plumbsendfd;
|
CFid* plumbsendfd;
|
||||||
CFid *plumbseemailfd;
|
CFid* plumbseemailfd;
|
||||||
CFid *plumbshowmailfd;
|
CFid* plumbshowmailfd;
|
||||||
CFid *plumbsendmailfd;
|
CFid* plumbsendmailfd;
|
||||||
Channel *cplumb;
|
Channel* cplumb;
|
||||||
Channel *cplumbshow;
|
Channel* cplumbshow;
|
||||||
Channel *cplumbsend;
|
Channel* cplumbsend;
|
||||||
int wctlfd;
|
int wctlfd;
|
||||||
void mainctl(void*);
|
void mainctl(void*);
|
||||||
void plumbproc(void*);
|
void plumbproc(void*);
|
||||||
|
@ -37,44 +37,39 @@ void plumbsendthread(void*);
|
||||||
|
|
||||||
int shortmenu;
|
int shortmenu;
|
||||||
|
|
||||||
CFsys *mailfs;
|
CFsys* mailfs;
|
||||||
CFsys *acmefs;
|
CFsys* acmefs;
|
||||||
|
|
||||||
void
|
void usage(void) {
|
||||||
usage(void)
|
fprint(
|
||||||
{
|
2,
|
||||||
fprint(2, "usage: Mail [-sS] [-n srvname] [-o outgoing] [mailboxname [directoryname]]\n");
|
"usage: Mail [-sS] [-n srvname] [-o outgoing] [mailboxname "
|
||||||
|
"[directoryname]]\n");
|
||||||
threadexitsall("usage");
|
threadexitsall("usage");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void removeupasfs(void) {
|
||||||
removeupasfs(void)
|
|
||||||
{
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
if(strcmp(mboxname, "mbox") == 0)
|
if (strcmp(mboxname, "mbox") == 0)
|
||||||
return;
|
return;
|
||||||
snprint(buf, sizeof buf, "close %s", mboxname);
|
snprint(buf, sizeof buf, "close %s", mboxname);
|
||||||
fswrite(mbox.ctlfd, buf, strlen(buf));
|
fswrite(mbox.ctlfd, buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int ismaildir(char* s) {
|
||||||
ismaildir(char *s)
|
Dir* d;
|
||||||
{
|
|
||||||
Dir *d;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
d = fsdirstat(mailfs, s);
|
d = fsdirstat(mailfs, s);
|
||||||
if(d == nil)
|
if (d == nil)
|
||||||
return 0;
|
return 0;
|
||||||
ret = d->qid.type & QTDIR;
|
ret = d->qid.type & QTDIR;
|
||||||
free(d);
|
free(d);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void threadmain(int argc, char* argv[]) {
|
||||||
threadmain(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char *s, *name;
|
char *s, *name;
|
||||||
char err[ERRMAX], *cmd;
|
char err[ERRMAX], *cmd;
|
||||||
int i, newdir;
|
int i, newdir;
|
||||||
|
@ -83,17 +78,18 @@ threadmain(int argc, char *argv[])
|
||||||
doquote = needsrcquote;
|
doquote = needsrcquote;
|
||||||
quotefmtinstall();
|
quotefmtinstall();
|
||||||
|
|
||||||
/* open these early so we won't miss notification of new mail messages while we read mbox */
|
/* open these early so we won't miss notification of new mail messages while
|
||||||
if((plumbsendfd = plumbopenfid("send", OWRITE|OCEXEC)) == nil)
|
* we read mbox */
|
||||||
|
if ((plumbsendfd = plumbopenfid("send", OWRITE | OCEXEC)) == nil)
|
||||||
fprint(2, "warning: open plumb/send: %r\n");
|
fprint(2, "warning: open plumb/send: %r\n");
|
||||||
if((plumbseemailfd = plumbopenfid("seemail", OREAD|OCEXEC)) == nil)
|
if ((plumbseemailfd = plumbopenfid("seemail", OREAD | OCEXEC)) == nil)
|
||||||
fprint(2, "warning: open plumb/seemail: %r\n");
|
fprint(2, "warning: open plumb/seemail: %r\n");
|
||||||
if((plumbshowmailfd = plumbopenfid("showmail", OREAD|OCEXEC)) == nil)
|
if ((plumbshowmailfd = plumbopenfid("showmail", OREAD | OCEXEC)) == nil)
|
||||||
fprint(2, "warning: open plumb/showmail: %r\n");
|
fprint(2, "warning: open plumb/showmail: %r\n");
|
||||||
|
|
||||||
shortmenu = 0;
|
shortmenu = 0;
|
||||||
srvname = "mail";
|
srvname = "mail";
|
||||||
ARGBEGIN{
|
ARGBEGIN {
|
||||||
case 's':
|
case 's':
|
||||||
shortmenu = 1;
|
shortmenu = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -111,41 +107,42 @@ threadmain(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}ARGEND
|
}
|
||||||
|
ARGEND
|
||||||
|
|
||||||
acmefs = nsmount("acme",nil);
|
acmefs = nsmount("acme", nil);
|
||||||
if(acmefs == nil)
|
if (acmefs == nil)
|
||||||
error("cannot mount acme: %r");
|
error("cannot mount acme: %r");
|
||||||
mailfs = nsmount(srvname, nil);
|
mailfs = nsmount(srvname, nil);
|
||||||
if(mailfs == nil)
|
if (mailfs == nil)
|
||||||
error("cannot mount %s: %r", srvname);
|
error("cannot mount %s: %r", srvname);
|
||||||
|
|
||||||
name = "mbox";
|
name = "mbox";
|
||||||
|
|
||||||
newdir = 1;
|
newdir = 1;
|
||||||
if(argc > 0){
|
if (argc > 0) {
|
||||||
i = strlen(argv[0]);
|
i = strlen(argv[0]);
|
||||||
if(argc>2 || i==0)
|
if (argc > 2 || i == 0)
|
||||||
usage();
|
usage();
|
||||||
/* see if the name is that of an existing /mail/fs directory */
|
/* see if the name is that of an existing /mail/fs directory */
|
||||||
if(argc==1 && argv[0][0] != '/' && ismaildir(argv[0])){
|
if (argc == 1 && argv[0][0] != '/' && ismaildir(argv[0])) {
|
||||||
name = argv[0];
|
name = argv[0];
|
||||||
mboxname = estrdup(name);
|
mboxname = estrdup(name);
|
||||||
newdir = 0;
|
newdir = 0;
|
||||||
}else{
|
} else {
|
||||||
if(argv[0][i-1] == '/')
|
if (argv[0][i - 1] == '/')
|
||||||
argv[0][i-1] = '\0';
|
argv[0][i - 1] = '\0';
|
||||||
s = strrchr(argv[0], '/');
|
s = strrchr(argv[0], '/');
|
||||||
if(s == nil)
|
if (s == nil)
|
||||||
mboxname = estrdup(argv[0]);
|
mboxname = estrdup(argv[0]);
|
||||||
else{
|
else {
|
||||||
*s++ = '\0';
|
*s++ = '\0';
|
||||||
if(*s == '\0')
|
if (*s == '\0')
|
||||||
usage();
|
usage();
|
||||||
mailboxdir = argv[0];
|
mailboxdir = argv[0];
|
||||||
mboxname = estrdup(s);
|
mboxname = estrdup(s);
|
||||||
}
|
}
|
||||||
if(argc > 1)
|
if (argc > 1)
|
||||||
name = argv[1];
|
name = argv[1];
|
||||||
else
|
else
|
||||||
name = mboxname;
|
name = mboxname;
|
||||||
|
@ -153,64 +150,65 @@ threadmain(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
user = getenv("user");
|
user = getenv("user");
|
||||||
if(user == nil)
|
if (user == nil)
|
||||||
user = "none";
|
user = "none";
|
||||||
home = getenv("home");
|
home = getenv("home");
|
||||||
if(home == nil)
|
if (home == nil)
|
||||||
home = getenv("HOME");
|
home = getenv("HOME");
|
||||||
if(home == nil)
|
if (home == nil)
|
||||||
error("can't find $home");
|
error("can't find $home");
|
||||||
if(mailboxdir == nil)
|
if (mailboxdir == nil)
|
||||||
mailboxdir = estrstrdup(home, "/mail");
|
mailboxdir = estrstrdup(home, "/mail");
|
||||||
if(outgoing == nil)
|
if (outgoing == nil)
|
||||||
outgoing = estrstrdup(mailboxdir, "/outgoing");
|
outgoing = estrstrdup(mailboxdir, "/outgoing");
|
||||||
|
|
||||||
mbox.ctlfd = fsopen(mailfs, estrstrdup(mboxname, "/ctl"), OWRITE);
|
mbox.ctlfd = fsopen(mailfs, estrstrdup(mboxname, "/ctl"), OWRITE);
|
||||||
if(mbox.ctlfd == nil)
|
if (mbox.ctlfd == nil)
|
||||||
error("can't open %s: %r", estrstrdup(mboxname, "/ctl"));
|
error("can't open %s: %r", estrstrdup(mboxname, "/ctl"));
|
||||||
|
|
||||||
fsname = estrdup(name);
|
fsname = estrdup(name);
|
||||||
if(newdir && argc > 0){
|
if (newdir && argc > 0) {
|
||||||
s = emalloc(5+strlen(mailboxdir)+strlen(mboxname)+strlen(name)+10+1);
|
s = emalloc(
|
||||||
for(i=0; i<10; i++){
|
5 + strlen(mailboxdir) + strlen(mboxname) + strlen(name) + 10 + 1);
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
sprint(s, "open %s/%s %s", mailboxdir, mboxname, fsname);
|
sprint(s, "open %s/%s %s", mailboxdir, mboxname, fsname);
|
||||||
if(fswrite(mbox.ctlfd, s, strlen(s)) >= 0)
|
if (fswrite(mbox.ctlfd, s, strlen(s)) >= 0)
|
||||||
break;
|
break;
|
||||||
err[0] = '\0';
|
err[0] = '\0';
|
||||||
errstr(err, sizeof err);
|
errstr(err, sizeof err);
|
||||||
if(strstr(err, "mbox name in use") == nil)
|
if (strstr(err, "mbox name in use") == nil)
|
||||||
error("can't create directory %s for mail: %s", name, err);
|
error("can't create directory %s for mail: %s", name, err);
|
||||||
free(fsname);
|
free(fsname);
|
||||||
fsname = emalloc(strlen(name)+10);
|
fsname = emalloc(strlen(name) + 10);
|
||||||
sprint(fsname, "%s-%d", name, i);
|
sprint(fsname, "%s-%d", name, i);
|
||||||
}
|
}
|
||||||
if(i == 10)
|
if (i == 10)
|
||||||
error("can't open %s/%s: %r", mailboxdir, mboxname);
|
error("can't open %s/%s: %r", mailboxdir, mboxname);
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = estrstrdup(fsname, "/");
|
s = estrstrdup(fsname, "/");
|
||||||
mbox.name = estrstrdup(maildir, s);
|
mbox.name = estrstrdup(maildir, s);
|
||||||
mbox.level= 0;
|
mbox.level = 0;
|
||||||
readmbox(&mbox, maildir, s);
|
readmbox(&mbox, maildir, s);
|
||||||
home = getenv("home");
|
home = getenv("home");
|
||||||
if(home == nil)
|
if (home == nil)
|
||||||
home = "/";
|
home = "/";
|
||||||
|
|
||||||
wbox = newwindow();
|
wbox = newwindow();
|
||||||
winname(wbox, mbox.name);
|
winname(wbox, mbox.name);
|
||||||
wintagwrite(wbox, "Put Mail Delmesg ", 3+1+4+1+7+1);
|
wintagwrite(wbox, "Put Mail Delmesg ", 3 + 1 + 4 + 1 + 7 + 1);
|
||||||
threadcreate(mainctl, wbox, STACK);
|
threadcreate(mainctl, wbox, STACK);
|
||||||
|
|
||||||
fmtstrinit(&fmt);
|
fmtstrinit(&fmt);
|
||||||
fmtprint(&fmt, "Mail");
|
fmtprint(&fmt, "Mail");
|
||||||
if(shortmenu)
|
if (shortmenu)
|
||||||
fmtprint(&fmt, " -%c", "sS"[shortmenu-1]);
|
fmtprint(&fmt, " -%c", "sS"[shortmenu - 1]);
|
||||||
if(outgoing)
|
if (outgoing)
|
||||||
fmtprint(&fmt, " -o %s", outgoing);
|
fmtprint(&fmt, " -o %s", outgoing);
|
||||||
fmtprint(&fmt, " %s", name);
|
fmtprint(&fmt, " %s", name);
|
||||||
cmd = fmtstrflush(&fmt);
|
cmd = fmtstrflush(&fmt);
|
||||||
if(cmd == nil)
|
if (cmd == nil)
|
||||||
sysfatal("out of memory");
|
sysfatal("out of memory");
|
||||||
winsetdump(wbox, "/acme/mail", cmd);
|
winsetdump(wbox, "/acme/mail", cmd);
|
||||||
mbox.w = wbox;
|
mbox.w = wbox;
|
||||||
|
@ -218,16 +216,16 @@ threadmain(int argc, char *argv[])
|
||||||
mesgmenu(wbox, &mbox);
|
mesgmenu(wbox, &mbox);
|
||||||
winclean(wbox);
|
winclean(wbox);
|
||||||
|
|
||||||
/* wctlfd = open("/dev/wctl", OWRITE|OCEXEC); /* for acme window */
|
/* wctlfd = open("/dev/wctl", OWRITE|OCEXEC); /* for acme window */
|
||||||
wctlfd = -1;
|
wctlfd = -1;
|
||||||
cplumb = chancreate(sizeof(Plumbmsg*), 0);
|
cplumb = chancreate(sizeof(Plumbmsg*), 0);
|
||||||
cplumbshow = chancreate(sizeof(Plumbmsg*), 0);
|
cplumbshow = chancreate(sizeof(Plumbmsg*), 0);
|
||||||
if(strcmp(name, "mbox") == 0){
|
if (strcmp(name, "mbox") == 0) {
|
||||||
/*
|
/*
|
||||||
* Avoid creating multiple windows to send mail by only accepting
|
* Avoid creating multiple windows to send mail by only accepting
|
||||||
* sendmail plumb messages if we're reading the main mailbox.
|
* sendmail plumb messages if we're reading the main mailbox.
|
||||||
*/
|
*/
|
||||||
plumbsendmailfd = plumbopenfid("sendmail", OREAD|OCEXEC);
|
plumbsendmailfd = plumbopenfid("sendmail", OREAD | OCEXEC);
|
||||||
cplumbsend = chancreate(sizeof(Plumbmsg*), 0);
|
cplumbsend = chancreate(sizeof(Plumbmsg*), 0);
|
||||||
proccreate(plumbsendproc, nil, STACK);
|
proccreate(plumbsendproc, nil, STACK);
|
||||||
threadcreate(plumbsendthread, nil, STACK);
|
threadcreate(plumbsendthread, nil, STACK);
|
||||||
|
@ -241,120 +239,106 @@ threadmain(int argc, char *argv[])
|
||||||
plumbthread();
|
plumbthread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void plumbproc(void* v) {
|
||||||
plumbproc(void* v)
|
Plumbmsg* m;
|
||||||
{
|
|
||||||
Plumbmsg *m;
|
|
||||||
|
|
||||||
threadsetname("plumbproc");
|
threadsetname("plumbproc");
|
||||||
for(;;){
|
for (;;) {
|
||||||
m = plumbrecvfid(plumbseemailfd);
|
m = plumbrecvfid(plumbseemailfd);
|
||||||
sendp(cplumb, m);
|
sendp(cplumb, m);
|
||||||
if(m == nil)
|
if (m == nil)
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void plumbshowproc(void* v) {
|
||||||
plumbshowproc(void* v)
|
Plumbmsg* m;
|
||||||
{
|
|
||||||
Plumbmsg *m;
|
|
||||||
|
|
||||||
threadsetname("plumbshowproc");
|
threadsetname("plumbshowproc");
|
||||||
for(;;){
|
for (;;) {
|
||||||
m = plumbrecvfid(plumbshowmailfd);
|
m = plumbrecvfid(plumbshowmailfd);
|
||||||
sendp(cplumbshow, m);
|
sendp(cplumbshow, m);
|
||||||
if(m == nil)
|
if (m == nil)
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void plumbsendproc(void* v) {
|
||||||
plumbsendproc(void* v)
|
Plumbmsg* m;
|
||||||
{
|
|
||||||
Plumbmsg *m;
|
|
||||||
|
|
||||||
threadsetname("plumbsendproc");
|
threadsetname("plumbsendproc");
|
||||||
for(;;){
|
for (;;) {
|
||||||
m = plumbrecvfid(plumbsendmailfd);
|
m = plumbrecvfid(plumbsendmailfd);
|
||||||
sendp(cplumbsend, m);
|
sendp(cplumbsend, m);
|
||||||
if(m == nil)
|
if (m == nil)
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void newmesg(char* name, char* digest) {
|
||||||
newmesg(char *name, char *digest)
|
Dir* d;
|
||||||
{
|
|
||||||
Dir *d;
|
|
||||||
|
|
||||||
if(strncmp(name, mbox.name, strlen(mbox.name)) != 0)
|
if (strncmp(name, mbox.name, strlen(mbox.name)) != 0)
|
||||||
return; /* message is about another mailbox */
|
return; /* message is about another mailbox */
|
||||||
if(mesglookupfile(&mbox, name, digest) != nil)
|
if (mesglookupfile(&mbox, name, digest) != nil)
|
||||||
return;
|
return;
|
||||||
if(strncmp(name, "Mail/", 5) == 0)
|
if (strncmp(name, "Mail/", 5) == 0)
|
||||||
name += 5;
|
name += 5;
|
||||||
d = fsdirstat(mailfs, name);
|
d = fsdirstat(mailfs, name);
|
||||||
if(d == nil)
|
if (d == nil)
|
||||||
return;
|
return;
|
||||||
if(mesgadd(&mbox, mbox.name, d, digest))
|
if (mesgadd(&mbox, mbox.name, d, digest))
|
||||||
mesgmenunew(wbox, &mbox);
|
mesgmenunew(wbox, &mbox);
|
||||||
free(d);
|
free(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void showmesg(char* name, char* digest) {
|
||||||
showmesg(char *name, char *digest)
|
char* n;
|
||||||
{
|
char* mb;
|
||||||
char *n;
|
|
||||||
char *mb;
|
|
||||||
|
|
||||||
mb = mbox.name;
|
mb = mbox.name;
|
||||||
if(strncmp(name, mb, strlen(mb)) != 0)
|
if (strncmp(name, mb, strlen(mb)) != 0)
|
||||||
return; /* message is about another mailbox */
|
return; /* message is about another mailbox */
|
||||||
n = estrdup(name+strlen(mb));
|
n = estrdup(name + strlen(mb));
|
||||||
if(n[strlen(n)-1] != '/')
|
if (n[strlen(n) - 1] != '/')
|
||||||
n = egrow(n, "/", nil);
|
n = egrow(n, "/", nil);
|
||||||
mesgopen(&mbox, mbox.name, name+strlen(mb), nil, 1, digest);
|
mesgopen(&mbox, mbox.name, name + strlen(mb), nil, 1, digest);
|
||||||
free(n);
|
free(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void delmesg(char* name, char* digest, int dodel, char* save) {
|
||||||
delmesg(char *name, char *digest, int dodel, char *save)
|
Message* m;
|
||||||
{
|
|
||||||
Message *m;
|
|
||||||
|
|
||||||
m = mesglookupfile(&mbox, name, digest);
|
m = mesglookupfile(&mbox, name, digest);
|
||||||
if(m != nil){
|
if (m != nil) {
|
||||||
if(save)
|
if (save)
|
||||||
mesgcommand(m, estrstrdup("Save ", save));
|
mesgcommand(m, estrstrdup("Save ", save));
|
||||||
if(dodel)
|
if (dodel)
|
||||||
mesgmenumarkdel(wbox, &mbox, m, 1);
|
mesgmenumarkdel(wbox, &mbox, m, 1);
|
||||||
else{
|
else {
|
||||||
/* notification came from plumber - message is gone */
|
/* notification came from plumber - message is gone */
|
||||||
mesgmenudel(wbox, &mbox, m);
|
mesgmenudel(wbox, &mbox, m);
|
||||||
if(!m->opened)
|
if (!m->opened)
|
||||||
mesgdel(&mbox, m);
|
mesgdel(&mbox, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void plumbthread(void) {
|
||||||
plumbthread(void)
|
Plumbmsg* m;
|
||||||
{
|
Plumbattr* a;
|
||||||
Plumbmsg *m;
|
|
||||||
Plumbattr *a;
|
|
||||||
char *type, *digest;
|
char *type, *digest;
|
||||||
|
|
||||||
threadsetname("plumbthread");
|
threadsetname("plumbthread");
|
||||||
while((m = recvp(cplumb)) != nil){
|
while ((m = recvp(cplumb)) != nil) {
|
||||||
a = m->attr;
|
a = m->attr;
|
||||||
digest = plumblookup(a, "digest");
|
digest = plumblookup(a, "digest");
|
||||||
type = plumblookup(a, "mailtype");
|
type = plumblookup(a, "mailtype");
|
||||||
if(type == nil)
|
if (type == nil)
|
||||||
fprint(2, "Mail: plumb message with no mailtype attribute\n");
|
fprint(2, "Mail: plumb message with no mailtype attribute\n");
|
||||||
else if(strcmp(type, "new") == 0)
|
else if (strcmp(type, "new") == 0)
|
||||||
newmesg(m->data, digest);
|
newmesg(m->data, digest);
|
||||||
else if(strcmp(type, "delete") == 0)
|
else if (strcmp(type, "delete") == 0)
|
||||||
delmesg(m->data, digest, 0, nil);
|
delmesg(m->data, digest, 0, nil);
|
||||||
else
|
else
|
||||||
fprint(2, "Mail: unknown plumb attribute %s\n", type);
|
fprint(2, "Mail: unknown plumb attribute %s\n", type);
|
||||||
|
@ -363,116 +347,111 @@ plumbthread(void)
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void plumbshowthread(void* v) {
|
||||||
plumbshowthread(void *v)
|
Plumbmsg* m;
|
||||||
{
|
|
||||||
Plumbmsg *m;
|
|
||||||
|
|
||||||
USED(v);
|
USED(v);
|
||||||
threadsetname("plumbshowthread");
|
threadsetname("plumbshowthread");
|
||||||
while((m = recvp(cplumbshow)) != nil){
|
while ((m = recvp(cplumbshow)) != nil) {
|
||||||
showmesg(m->data, plumblookup(m->attr, "digest"));
|
showmesg(m->data, plumblookup(m->attr, "digest"));
|
||||||
plumbfree(m);
|
plumbfree(m);
|
||||||
}
|
}
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void plumbsendthread(void* v) {
|
||||||
plumbsendthread(void *v)
|
Plumbmsg* m;
|
||||||
{
|
|
||||||
Plumbmsg *m;
|
|
||||||
|
|
||||||
USED(v);
|
USED(v);
|
||||||
threadsetname("plumbsendthread");
|
threadsetname("plumbsendthread");
|
||||||
while((m = recvp(cplumbsend)) != nil){
|
while ((m = recvp(cplumbsend)) != nil) {
|
||||||
mkreply(nil, "Mail", m->data, m->attr, nil);
|
mkreply(nil, "Mail", m->data, m->attr, nil);
|
||||||
plumbfree(m);
|
plumbfree(m);
|
||||||
}
|
}
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int mboxcommand(Window* w, char* s) {
|
||||||
mboxcommand(Window *w, char *s)
|
|
||||||
{
|
|
||||||
char *args[10], **targs, *save;
|
char *args[10], **targs, *save;
|
||||||
Window *sbox;
|
Window* sbox;
|
||||||
Message *m, *next;
|
Message *m, *next;
|
||||||
int ok, nargs, i, j;
|
int ok, nargs, i, j;
|
||||||
CFid *searchfd;
|
CFid* searchfd;
|
||||||
char buf[128], *res;
|
char buf[128], *res;
|
||||||
|
|
||||||
nargs = tokenize(s, args, nelem(args));
|
nargs = tokenize(s, args, nelem(args));
|
||||||
if(nargs == 0)
|
if (nargs == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if(strcmp(args[0], "Mail") == 0){
|
if (strcmp(args[0], "Mail") == 0) {
|
||||||
if(nargs == 1)
|
if (nargs == 1)
|
||||||
mkreply(nil, "Mail", "", nil, nil);
|
mkreply(nil, "Mail", "", nil, nil);
|
||||||
else
|
else
|
||||||
mkreply(nil, "Mail", args[1], nil, nil);
|
mkreply(nil, "Mail", args[1], nil, nil);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(strcmp(s, "Del") == 0){
|
if (strcmp(s, "Del") == 0) {
|
||||||
if(mbox.dirty){
|
if (mbox.dirty) {
|
||||||
mbox.dirty = 0;
|
mbox.dirty = 0;
|
||||||
fprint(2, "mail: mailbox not written\n");
|
fprint(2, "mail: mailbox not written\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(w != mbox.w){
|
if (w != mbox.w) {
|
||||||
windel(w, 1);
|
windel(w, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
ok = 1;
|
ok = 1;
|
||||||
for(m=mbox.head; m!=nil; m=next){
|
for (m = mbox.head; m != nil; m = next) {
|
||||||
next = m->next;
|
next = m->next;
|
||||||
if(m->w){
|
if (m->w) {
|
||||||
if(windel(m->w, 0))
|
if (windel(m->w, 0))
|
||||||
m->w = nil;
|
m->w = nil;
|
||||||
else
|
else
|
||||||
ok = 0;
|
ok = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(m=replies.head; m!=nil; m=next){
|
for (m = replies.head; m != nil; m = next) {
|
||||||
next = m->next;
|
next = m->next;
|
||||||
if(m->w){
|
if (m->w) {
|
||||||
if(windel(m->w, 0))
|
if (windel(m->w, 0))
|
||||||
m->w = nil;
|
m->w = nil;
|
||||||
else
|
else
|
||||||
ok = 0;
|
ok = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ok){
|
if (ok) {
|
||||||
windel(w, 1);
|
windel(w, 1);
|
||||||
removeupasfs();
|
removeupasfs();
|
||||||
threadexitsall(nil);
|
threadexitsall(nil);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(strcmp(s, "Put") == 0){
|
if (strcmp(s, "Put") == 0) {
|
||||||
rewritembox(wbox, &mbox);
|
rewritembox(wbox, &mbox);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(strcmp(s, "Get") == 0){
|
if (strcmp(s, "Get") == 0) {
|
||||||
fswrite(mbox.ctlfd, "refresh", 7);
|
fswrite(mbox.ctlfd, "refresh", 7);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(strcmp(s, "Delmesg") == 0){
|
if (strcmp(s, "Delmesg") == 0) {
|
||||||
save = nil;
|
save = nil;
|
||||||
if(nargs > 1)
|
if (nargs > 1)
|
||||||
save = args[1];
|
save = args[1];
|
||||||
s = winselection(w);
|
s = winselection(w);
|
||||||
if(s == nil)
|
if (s == nil)
|
||||||
return 1;
|
return 1;
|
||||||
nargs = 1;
|
nargs = 1;
|
||||||
for(i=0; s[i]; i++)
|
for (i = 0; s[i]; i++)
|
||||||
if(s[i] == '\n')
|
if (s[i] == '\n')
|
||||||
nargs++;
|
nargs++;
|
||||||
targs = emalloc(nargs*sizeof(char*)); /* could be too many for a local array */
|
targs =
|
||||||
|
emalloc(nargs * sizeof(char*)); /* could be too many for a local array */
|
||||||
nargs = getfields(s, targs, nargs, 1, "\n");
|
nargs = getfields(s, targs, nargs, 1, "\n");
|
||||||
for(i=0; i<nargs; i++){
|
for (i = 0; i < nargs; i++) {
|
||||||
if(!isdigit(targs[i][0]))
|
if (!isdigit(targs[i][0]))
|
||||||
continue;
|
continue;
|
||||||
j = atoi(targs[i]); /* easy way to parse the number! */
|
j = atoi(targs[i]); /* easy way to parse the number! */
|
||||||
if(j == 0)
|
if (j == 0)
|
||||||
continue;
|
continue;
|
||||||
snprint(buf, sizeof buf, "%s%d", mbox.name, j);
|
snprint(buf, sizeof buf, "%s%d", mbox.name, j);
|
||||||
delmesg(buf, nil, 1, save);
|
delmesg(buf, nil, 1, save);
|
||||||
|
@ -481,20 +460,20 @@ mboxcommand(Window *w, char *s)
|
||||||
free(targs);
|
free(targs);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(strcmp(s, "Search") == 0){
|
if (strcmp(s, "Search") == 0) {
|
||||||
if(nargs <= 1)
|
if (nargs <= 1)
|
||||||
return 1;
|
return 1;
|
||||||
s = estrstrdup(mboxname, "/search");
|
s = estrstrdup(mboxname, "/search");
|
||||||
searchfd = fsopen(mailfs, s, ORDWR);
|
searchfd = fsopen(mailfs, s, ORDWR);
|
||||||
if(searchfd == nil)
|
if (searchfd == nil)
|
||||||
return 1;
|
return 1;
|
||||||
save = estrdup(args[1]);
|
save = estrdup(args[1]);
|
||||||
for(i=2; i<nargs; i++)
|
for (i = 2; i < nargs; i++)
|
||||||
save = eappend(save, " ", args[i]);
|
save = eappend(save, " ", args[i]);
|
||||||
fswrite(searchfd, save, strlen(save));
|
fswrite(searchfd, save, strlen(save));
|
||||||
fsseek(searchfd, 0, 0);
|
fsseek(searchfd, 0, 0);
|
||||||
j = fsread(searchfd, buf, sizeof buf - 1);
|
j = fsread(searchfd, buf, sizeof buf - 1);
|
||||||
if(j == 0){
|
if (j == 0) {
|
||||||
fprint(2, "[%s] search %s: no results found\n", mboxname, save);
|
fprint(2, "[%s] search %s: no results found\n", mboxname, save);
|
||||||
fsclose(searchfd);
|
fsclose(searchfd);
|
||||||
free(save);
|
free(save);
|
||||||
|
@ -504,7 +483,7 @@ mboxcommand(Window *w, char *s)
|
||||||
buf[j] = '\0';
|
buf[j] = '\0';
|
||||||
res = estrdup(buf);
|
res = estrdup(buf);
|
||||||
j = fsread(searchfd, buf, sizeof buf - 1);
|
j = fsread(searchfd, buf, sizeof buf - 1);
|
||||||
for(; j != 0; j = fsread(searchfd, buf, sizeof buf - 1), buf[j] = '\0')
|
for (; j != 0; j = fsread(searchfd, buf, sizeof buf - 1), buf[j] = '\0')
|
||||||
res = eappend(res, "", buf);
|
res = eappend(res, "", buf);
|
||||||
fsclose(searchfd);
|
fsclose(searchfd);
|
||||||
|
|
||||||
|
@ -517,16 +496,18 @@ mboxcommand(Window *w, char *s)
|
||||||
/* show results in reverse order */
|
/* show results in reverse order */
|
||||||
m = mbox.tail;
|
m = mbox.tail;
|
||||||
save = nil;
|
save = nil;
|
||||||
for(s=strrchr(res, ' '); s!=nil || save!=res; s=strrchr(res, ' ')){
|
for (s = strrchr(res, ' '); s != nil || save != res;
|
||||||
if(s != nil){
|
s = strrchr(res, ' ')) {
|
||||||
save = s+1;
|
if (s != nil) {
|
||||||
|
save = s + 1;
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
}
|
} else
|
||||||
else save = res;
|
save = res;
|
||||||
save = estrstrdup(save, "/");
|
save = estrstrdup(save, "/");
|
||||||
for(; m && strcmp(save, m->name) != 0; m=m->prev);
|
for (; m && strcmp(save, m->name) != 0; m = m->prev)
|
||||||
|
;
|
||||||
free(save);
|
free(save);
|
||||||
if(m == nil)
|
if (m == nil)
|
||||||
break;
|
break;
|
||||||
fsprint(sbox->body, "%s%s\n", m->name, info(m, 0, 0));
|
fsprint(sbox->body, "%s%s\n", m->name, info(m, 0, 0));
|
||||||
m = m->prev;
|
m = m->prev;
|
||||||
|
@ -539,10 +520,8 @@ mboxcommand(Window *w, char *s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void mainctl(void* v) {
|
||||||
mainctl(void *v)
|
Window* w;
|
||||||
{
|
|
||||||
Window *w;
|
|
||||||
Event *e, *e2, *eq, *ea;
|
Event *e, *e2, *eq, *ea;
|
||||||
int na, nopen;
|
int na, nopen;
|
||||||
char *s, *t, *buf;
|
char *s, *t, *buf;
|
||||||
|
@ -551,9 +530,9 @@ mainctl(void *v)
|
||||||
winincref(w);
|
winincref(w);
|
||||||
proccreate(wineventproc, w, STACK);
|
proccreate(wineventproc, w, STACK);
|
||||||
|
|
||||||
for(;;){
|
for (;;) {
|
||||||
e = recvp(w->cevent);
|
e = recvp(w->cevent);
|
||||||
switch(e->c1){
|
switch (e->c1) {
|
||||||
default:
|
default:
|
||||||
Unknown:
|
Unknown:
|
||||||
print("unknown message %c%c\n", e->c1, e->c2);
|
print("unknown message %c%c\n", e->c1, e->c2);
|
||||||
|
@ -569,32 +548,32 @@ mainctl(void *v)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
switch(e->c2){
|
switch (e->c2) {
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
ea = nil;
|
ea = nil;
|
||||||
e2 = nil;
|
e2 = nil;
|
||||||
if(e->flag & 2)
|
if (e->flag & 2)
|
||||||
e2 = recvp(w->cevent);
|
e2 = recvp(w->cevent);
|
||||||
if(e->flag & 8){
|
if (e->flag & 8) {
|
||||||
ea = recvp(w->cevent);
|
ea = recvp(w->cevent);
|
||||||
na = ea->nb;
|
na = ea->nb;
|
||||||
recvp(w->cevent);
|
recvp(w->cevent);
|
||||||
}else
|
} else
|
||||||
na = 0;
|
na = 0;
|
||||||
s = e->b;
|
s = e->b;
|
||||||
/* if it's a known command, do it */
|
/* if it's a known command, do it */
|
||||||
if((e->flag&2) && e->nb==0)
|
if ((e->flag & 2) && e->nb == 0)
|
||||||
s = e2->b;
|
s = e2->b;
|
||||||
if(na){
|
if (na) {
|
||||||
t = emalloc(strlen(s)+1+na+1);
|
t = emalloc(strlen(s) + 1 + na + 1);
|
||||||
sprint(t, "%s %s", s, ea->b);
|
sprint(t, "%s %s", s, ea->b);
|
||||||
s = t;
|
s = t;
|
||||||
}
|
}
|
||||||
/* if it's a long message, it can't be for us anyway */
|
/* if it's a long message, it can't be for us anyway */
|
||||||
if(!mboxcommand(w, s)) /* send it back */
|
if (!mboxcommand(w, s)) /* send it back */
|
||||||
winwriteevent(w, e);
|
winwriteevent(w, e);
|
||||||
if(na)
|
if (na)
|
||||||
free(s);
|
free(s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -602,29 +581,29 @@ mainctl(void *v)
|
||||||
case 'L':
|
case 'L':
|
||||||
buf = nil;
|
buf = nil;
|
||||||
eq = e;
|
eq = e;
|
||||||
if(e->flag & 2){
|
if (e->flag & 2) {
|
||||||
e2 = recvp(w->cevent);
|
e2 = recvp(w->cevent);
|
||||||
eq = e2;
|
eq = e2;
|
||||||
}
|
}
|
||||||
s = eq->b;
|
s = eq->b;
|
||||||
if(eq->q1>eq->q0 && eq->nb==0){
|
if (eq->q1 > eq->q0 && eq->nb == 0) {
|
||||||
buf = emalloc((eq->q1-eq->q0)*UTFmax+1);
|
buf = emalloc((eq->q1 - eq->q0) * UTFmax + 1);
|
||||||
winread(w, eq->q0, eq->q1, buf);
|
winread(w, eq->q0, eq->q1, buf);
|
||||||
s = buf;
|
s = buf;
|
||||||
}
|
}
|
||||||
nopen = 0;
|
nopen = 0;
|
||||||
do{
|
do {
|
||||||
/* skip 'deleted' string if present' */
|
/* skip 'deleted' string if present' */
|
||||||
if(strncmp(s, deleted, strlen(deleted)) == 0)
|
if (strncmp(s, deleted, strlen(deleted)) == 0)
|
||||||
s += strlen(deleted);
|
s += strlen(deleted);
|
||||||
/* skip mail box name if present */
|
/* skip mail box name if present */
|
||||||
if(strncmp(s, mbox.name, strlen(mbox.name)) == 0)
|
if (strncmp(s, mbox.name, strlen(mbox.name)) == 0)
|
||||||
s += strlen(mbox.name);
|
s += strlen(mbox.name);
|
||||||
nopen += mesgopen(&mbox, mbox.name, s, nil, 0, nil);
|
nopen += mesgopen(&mbox, mbox.name, s, nil, 0, nil);
|
||||||
while(*s!='\0' && *s++!='\n')
|
while (*s != '\0' && *s++ != '\n')
|
||||||
;
|
;
|
||||||
}while(*s);
|
} while (*s);
|
||||||
if(nopen == 0) /* send it back */
|
if (nopen == 0) /* send it back */
|
||||||
winwriteevent(w, e);
|
winwriteevent(w, e);
|
||||||
free(buf);
|
free(buf);
|
||||||
break;
|
break;
|
||||||
|
@ -641,4 +620,3 @@ mainctl(void *v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
mail/mail.o
BIN
mail/mail.o
Binary file not shown.
958
mail/mesg.c
958
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.
354
mail/reply.c
354
mail/reply.c
|
@ -9,56 +9,56 @@
|
||||||
|
|
||||||
static int replyid;
|
static int replyid;
|
||||||
|
|
||||||
int
|
int quote(Message* m, CFid* fid, char* dir, char* quotetext) {
|
||||||
quote(Message *m, CFid *fid, char *dir, char *quotetext)
|
|
||||||
{
|
|
||||||
char *body, *type;
|
char *body, *type;
|
||||||
int i, n, nlines;
|
int i, n, nlines;
|
||||||
char **lines;
|
char** lines;
|
||||||
|
|
||||||
if(quotetext){
|
if (quotetext) {
|
||||||
body = quotetext;
|
body = quotetext;
|
||||||
n = strlen(body);
|
n = strlen(body);
|
||||||
type = nil;
|
type = nil;
|
||||||
}else{
|
} else {
|
||||||
/* look for first textual component to quote */
|
/* look for first textual component to quote */
|
||||||
type = readfile(dir, "type", &n);
|
type = readfile(dir, "type", &n);
|
||||||
if(type == nil){
|
if (type == nil) {
|
||||||
print("no type in %s\n", dir);
|
print("no type in %s\n", dir);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(strncmp(type, "multipart/", 10)==0 || strncmp(type, "message/", 8)==0){
|
if (
|
||||||
|
strncmp(type, "multipart/", 10) == 0 ||
|
||||||
|
strncmp(type, "message/", 8) == 0) {
|
||||||
dir = estrstrdup(dir, "1/");
|
dir = estrstrdup(dir, "1/");
|
||||||
if(quote(m, fid, dir, nil)){
|
if (quote(m, fid, dir, nil)) {
|
||||||
free(type);
|
free(type);
|
||||||
free(dir);
|
free(dir);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
free(dir);
|
free(dir);
|
||||||
}
|
}
|
||||||
if(strncmp(type, "text", 4) != 0){
|
if (strncmp(type, "text", 4) != 0) {
|
||||||
free(type);
|
free(type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
body = readbody(m->type, dir, &n);
|
body = readbody(m->type, dir, &n);
|
||||||
if(body == nil)
|
if (body == nil)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
nlines = 0;
|
nlines = 0;
|
||||||
for(i=0; i<n; i++)
|
for (i = 0; i < n; i++)
|
||||||
if(body[i] == '\n')
|
if (body[i] == '\n')
|
||||||
nlines++;
|
nlines++;
|
||||||
nlines++;
|
nlines++;
|
||||||
lines = emalloc(nlines*sizeof(char*));
|
lines = emalloc(nlines * sizeof(char*));
|
||||||
nlines = getfields(body, lines, nlines, 0, "\n");
|
nlines = getfields(body, lines, nlines, 0, "\n");
|
||||||
/* delete leading and trailing blank lines */
|
/* delete leading and trailing blank lines */
|
||||||
i = 0;
|
i = 0;
|
||||||
while(i<nlines && lines[i][0]=='\0')
|
while (i < nlines && lines[i][0] == '\0')
|
||||||
i++;
|
i++;
|
||||||
while(i<nlines && lines[nlines-1][0]=='\0')
|
while (i < nlines && lines[nlines - 1][0] == '\0')
|
||||||
nlines--;
|
nlines--;
|
||||||
while(i < nlines){
|
while (i < nlines) {
|
||||||
fsprint(fid, ">%s%s\n", lines[i][0]=='>'? "" : " ", lines[i]);
|
fsprint(fid, ">%s%s\n", lines[i][0] == '>' ? "" : " ", lines[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
free(lines);
|
free(lines);
|
||||||
|
@ -67,21 +67,20 @@ quote(Message *m, CFid *fid, char *dir, char *quotetext)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void mkreply(
|
||||||
mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext)
|
Message* m, char* label, char* to, Plumbattr* attr, char* quotetext) {
|
||||||
{
|
|
||||||
char buf[100];
|
char buf[100];
|
||||||
CFid *fd;
|
CFid* fd;
|
||||||
Message *r;
|
Message* r;
|
||||||
char *dir, *t;
|
char *dir, *t;
|
||||||
int quotereply;
|
int quotereply;
|
||||||
Plumbattr *a;
|
Plumbattr* a;
|
||||||
|
|
||||||
quotereply = (label[0] == 'Q');
|
quotereply = (label[0] == 'Q');
|
||||||
|
|
||||||
if(quotereply && m && m->replywinid > 0){
|
if (quotereply && m && m->replywinid > 0) {
|
||||||
snprint(buf, sizeof buf, "%d/body", m->replywinid);
|
snprint(buf, sizeof buf, "%d/body", m->replywinid);
|
||||||
if((fd = fsopen(acmefs, buf, OWRITE)) != nil){
|
if ((fd = fsopen(acmefs, buf, OWRITE)) != nil) {
|
||||||
dir = estrstrdup(mbox.name, m->name);
|
dir = estrstrdup(mbox.name, m->name);
|
||||||
quote(m, fd, dir, quotetext);
|
quote(m, fd, dir, quotetext);
|
||||||
free(dir);
|
free(dir);
|
||||||
|
@ -91,67 +90,69 @@ mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext)
|
||||||
|
|
||||||
r = emalloc(sizeof(Message));
|
r = emalloc(sizeof(Message));
|
||||||
r->isreply = 1;
|
r->isreply = 1;
|
||||||
if(m != nil)
|
if (m != nil)
|
||||||
r->replyname = estrdup(m->name);
|
r->replyname = estrdup(m->name);
|
||||||
r->next = replies.head;
|
r->next = replies.head;
|
||||||
r->prev = nil;
|
r->prev = nil;
|
||||||
if(replies.head != nil)
|
if (replies.head != nil)
|
||||||
replies.head->prev = r;
|
replies.head->prev = r;
|
||||||
replies.head = r;
|
replies.head = r;
|
||||||
if(replies.tail == nil)
|
if (replies.tail == nil)
|
||||||
replies.tail = r;
|
replies.tail = r;
|
||||||
r->name = emalloc(strlen(mbox.name)+strlen(label)+10);
|
r->name = emalloc(strlen(mbox.name) + strlen(label) + 10);
|
||||||
sprint(r->name, "%s%s%d", mbox.name, label, ++replyid);
|
sprint(r->name, "%s%s%d", mbox.name, label, ++replyid);
|
||||||
r->w = newwindow();
|
r->w = newwindow();
|
||||||
if(m)
|
if (m)
|
||||||
m->replywinid = r->w->id;
|
m->replywinid = r->w->id;
|
||||||
winname(r->w, r->name);
|
winname(r->w, r->name);
|
||||||
ctlprint(r->w->ctl, "cleartag");
|
ctlprint(r->w->ctl, "cleartag");
|
||||||
wintagwrite(r->w, "fmt Look Post Undo", 4+5+5+4);
|
wintagwrite(r->w, "fmt Look Post Undo", 4 + 5 + 5 + 4);
|
||||||
r->tagposted = 1;
|
r->tagposted = 1;
|
||||||
threadcreate(mesgctl, r, STACK);
|
threadcreate(mesgctl, r, STACK);
|
||||||
winopenbody(r->w, OWRITE);
|
winopenbody(r->w, OWRITE);
|
||||||
if(to!=nil && to[0]!='\0')
|
if (to != nil && to[0] != '\0')
|
||||||
fsprint(r->w->body, "%s\n", to);
|
fsprint(r->w->body, "%s\n", to);
|
||||||
for(a=attr; a; a=a->next)
|
for (a = attr; a; a = a->next)
|
||||||
fsprint(r->w->body, "%s: %s\n", a->name, a->value);
|
fsprint(r->w->body, "%s: %s\n", a->name, a->value);
|
||||||
dir = nil;
|
dir = nil;
|
||||||
if(m != nil){
|
if (m != nil) {
|
||||||
dir = estrstrdup(mbox.name, m->name);
|
dir = estrstrdup(mbox.name, m->name);
|
||||||
if(to == nil && attr == nil){
|
if (to == nil && attr == nil) {
|
||||||
/* Reply goes to replyto; Reply all goes to From and To and CC */
|
/* Reply goes to replyto; Reply all goes to From and To and CC */
|
||||||
if(strstr(label, "all") == nil)
|
if (strstr(label, "all") == nil)
|
||||||
fsprint(r->w->body, "To: %s\n", m->replyto);
|
fsprint(r->w->body, "To: %s\n", m->replyto);
|
||||||
else{ /* Replyall */
|
else { /* Replyall */
|
||||||
if(strlen(m->from) > 0)
|
if (strlen(m->from) > 0)
|
||||||
fsprint(r->w->body, "To: %s\n", m->from);
|
fsprint(r->w->body, "To: %s\n", m->from);
|
||||||
if(strlen(m->to) > 0)
|
if (strlen(m->to) > 0)
|
||||||
fsprint(r->w->body, "To: %s\n", m->to);
|
fsprint(r->w->body, "To: %s\n", m->to);
|
||||||
if(strlen(m->cc) > 0)
|
if (strlen(m->cc) > 0)
|
||||||
fsprint(r->w->body, "CC: %s\n", m->cc);
|
fsprint(r->w->body, "CC: %s\n", m->cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(strlen(m->subject) > 0){
|
if (strlen(m->subject) > 0) {
|
||||||
t = "Subject: Re: ";
|
t = "Subject: Re: ";
|
||||||
if(strlen(m->subject) >= 3)
|
if (strlen(m->subject) >= 3)
|
||||||
if(tolower(m->subject[0])=='r' && tolower(m->subject[1])=='e' && m->subject[2]==':')
|
if (
|
||||||
|
tolower(m->subject[0]) == 'r' && tolower(m->subject[1]) == 'e' &&
|
||||||
|
m->subject[2] == ':')
|
||||||
t = "Subject: ";
|
t = "Subject: ";
|
||||||
fsprint(r->w->body, "%s%s\n", t, m->subject);
|
fsprint(r->w->body, "%s%s\n", t, m->subject);
|
||||||
}
|
}
|
||||||
if(!quotereply){
|
if (!quotereply) {
|
||||||
fsprint(r->w->body, "Include: %sraw\n", dir);
|
fsprint(r->w->body, "Include: %sraw\n", dir);
|
||||||
free(dir);
|
free(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fsprint(r->w->body, "\n");
|
fsprint(r->w->body, "\n");
|
||||||
if(m == nil)
|
if (m == nil)
|
||||||
fsprint(r->w->body, "\n");
|
fsprint(r->w->body, "\n");
|
||||||
else if(quotereply){
|
else if (quotereply) {
|
||||||
quote(m, r->w->body, dir, quotetext);
|
quote(m, r->w->body, dir, quotetext);
|
||||||
free(dir);
|
free(dir);
|
||||||
}
|
}
|
||||||
winclosebody(r->w);
|
winclosebody(r->w);
|
||||||
if(m==nil && (to==nil || to[0]=='\0'))
|
if (m == nil && (to == nil || to[0] == '\0'))
|
||||||
winselect(r->w, "0", 0);
|
winselect(r->w, "0", 0);
|
||||||
else
|
else
|
||||||
winselect(r->w, "$", 0);
|
winselect(r->w, "$", 0);
|
||||||
|
@ -159,14 +160,12 @@ mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext)
|
||||||
windormant(r->w);
|
windormant(r->w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void delreply(Message* m) {
|
||||||
delreply(Message *m)
|
if (m->next == nil)
|
||||||
{
|
|
||||||
if(m->next == nil)
|
|
||||||
replies.tail = m->prev;
|
replies.tail = m->prev;
|
||||||
else
|
else
|
||||||
m->next->prev = m->prev;
|
m->next->prev = m->prev;
|
||||||
if(m->prev == nil)
|
if (m->prev == nil)
|
||||||
replies.head = m->next;
|
replies.head = m->next;
|
||||||
else
|
else
|
||||||
m->prev->next = m->next;
|
m->prev->next = m->next;
|
||||||
|
@ -174,20 +173,19 @@ delreply(Message *m)
|
||||||
free(m);
|
free(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy argv to stack and free the incoming strings, so we don't leak argument vectors */
|
/* copy argv to stack and free the incoming strings, so we don't leak argument
|
||||||
void
|
* vectors */
|
||||||
buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
|
void buildargv(char** inargv, char* argv[NARGS + 1], char args[NARGCHAR]) {
|
||||||
{
|
|
||||||
int i, n;
|
int i, n;
|
||||||
char *s, *a;
|
char *s, *a;
|
||||||
|
|
||||||
s = args;
|
s = args;
|
||||||
for(i=0; i<NARGS; i++){
|
for (i = 0; i < NARGS; i++) {
|
||||||
a = inargv[i];
|
a = inargv[i];
|
||||||
if(a == nil)
|
if (a == nil)
|
||||||
break;
|
break;
|
||||||
n = strlen(a)+1;
|
n = strlen(a) + 1;
|
||||||
if((s-args)+n >= NARGCHAR) /* too many characters */
|
if ((s - args) + n >= NARGCHAR) /* too many characters */
|
||||||
break;
|
break;
|
||||||
argv[i] = s;
|
argv[i] = s;
|
||||||
memmove(s, a, n);
|
memmove(s, a, n);
|
||||||
|
@ -197,13 +195,11 @@ buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
|
||||||
argv[i] = nil;
|
argv[i] = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void execproc(void* v) {
|
||||||
execproc(void *v)
|
struct Exec* e;
|
||||||
{
|
|
||||||
struct Exec *e;
|
|
||||||
int p[2], q[2];
|
int p[2], q[2];
|
||||||
char *prog;
|
char* prog;
|
||||||
char *argv[NARGS+1], args[NARGCHAR];
|
char *argv[NARGS + 1], args[NARGCHAR];
|
||||||
int fd[3];
|
int fd[3];
|
||||||
|
|
||||||
e = v;
|
e = v;
|
||||||
|
@ -214,7 +210,7 @@ execproc(void *v)
|
||||||
prog = e->prog; /* known not to be malloc'ed */
|
prog = e->prog; /* known not to be malloc'ed */
|
||||||
|
|
||||||
fd[0] = dup(p[0], -1);
|
fd[0] = dup(p[0], -1);
|
||||||
if(q[0])
|
if (q[0])
|
||||||
fd[1] = dup(q[1], -1);
|
fd[1] = dup(q[1], -1);
|
||||||
else
|
else
|
||||||
fd[1] = dup(1, -1);
|
fd[1] = dup(1, -1);
|
||||||
|
@ -234,76 +230,53 @@ execproc(void *v)
|
||||||
threadexits("can't exec");
|
threadexits("can't exec");
|
||||||
}
|
}
|
||||||
|
|
||||||
enum{
|
enum { ATTACH, BCC, CC, FROM, INCLUDE, TO };
|
||||||
ATTACH,
|
|
||||||
BCC,
|
|
||||||
CC,
|
|
||||||
FROM,
|
|
||||||
INCLUDE,
|
|
||||||
TO
|
|
||||||
};
|
|
||||||
|
|
||||||
char *headers[] = {
|
char* headers[] = {"attach:", "bcc:", "cc:", "from:", "include:", "to:", nil};
|
||||||
"attach:",
|
|
||||||
"bcc:",
|
|
||||||
"cc:",
|
|
||||||
"from:",
|
|
||||||
"include:",
|
|
||||||
"to:",
|
|
||||||
nil
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
int whichheader(char* h) {
|
||||||
whichheader(char *h)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0; headers[i]!=nil; i++)
|
for (i = 0; headers[i] != nil; i++)
|
||||||
if(cistrcmp(h, headers[i]) == 0)
|
if (cistrcmp(h, headers[i]) == 0)
|
||||||
return i;
|
return i;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *tolist[200];
|
char* tolist[200];
|
||||||
char *cclist[200];
|
char* cclist[200];
|
||||||
char *bcclist[200];
|
char* bcclist[200];
|
||||||
int ncc, nbcc, nto;
|
int ncc, nbcc, nto;
|
||||||
char *attlist[200];
|
char* attlist[200];
|
||||||
char included[200];
|
char included[200];
|
||||||
|
|
||||||
int
|
int addressed(char* name) {
|
||||||
addressed(char *name)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0; i<nto; i++)
|
for (i = 0; i < nto; i++)
|
||||||
if(strcmp(name, tolist[i]) == 0)
|
if (strcmp(name, tolist[i]) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
for(i=0; i<ncc; i++)
|
for (i = 0; i < ncc; i++)
|
||||||
if(strcmp(name, cclist[i]) == 0)
|
if (strcmp(name, cclist[i]) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
for(i=0; i<nbcc; i++)
|
for (i = 0; i < nbcc; i++)
|
||||||
if(strcmp(name, bcclist[i]) == 0)
|
if (strcmp(name, bcclist[i]) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* skipbl(char* s, char* e) {
|
||||||
skipbl(char *s, char *e)
|
while (s < e) {
|
||||||
{
|
if (*s != ' ' && *s != '\t' && *s != ',')
|
||||||
while(s < e){
|
|
||||||
if(*s!=' ' && *s!='\t' && *s!=',')
|
|
||||||
break;
|
break;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* findbl(char* s, char* e) {
|
||||||
findbl(char *s, char *e)
|
while (s < e) {
|
||||||
{
|
if (*s == ' ' || *s == '\t' || *s == ',')
|
||||||
while(s < e){
|
|
||||||
if(*s==' ' || *s=='\t' || *s==',')
|
|
||||||
break;
|
break;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
@ -311,75 +284,70 @@ findbl(char *s, char *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* comma-separate possibly blank-separated strings in line; e points before newline
|
* comma-separate possibly blank-separated strings in line; e points before
|
||||||
|
* newline
|
||||||
*/
|
*/
|
||||||
void
|
void commas(char* s, char* e) {
|
||||||
commas(char *s, char *e)
|
char* t;
|
||||||
{
|
|
||||||
char *t;
|
|
||||||
|
|
||||||
/* may have initial blanks */
|
/* may have initial blanks */
|
||||||
s = skipbl(s, e);
|
s = skipbl(s, e);
|
||||||
while(s < e){
|
while (s < e) {
|
||||||
s = findbl(s, e);
|
s = findbl(s, e);
|
||||||
if(s == e)
|
if (s == e)
|
||||||
break;
|
break;
|
||||||
t = skipbl(s, e);
|
t = skipbl(s, e);
|
||||||
if(t == e) /* no more words */
|
if (t == e) /* no more words */
|
||||||
break;
|
break;
|
||||||
/* patch comma */
|
/* patch comma */
|
||||||
*s++ = ',';
|
*s++ = ',';
|
||||||
while(s < t)
|
while (s < t)
|
||||||
*s++ = ' ';
|
*s++ = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int print2(int fd, int ofd, char* fmt, ...) {
|
||||||
print2(int fd, int ofd, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int m, n;
|
int m, n;
|
||||||
char *s;
|
char* s;
|
||||||
va_list arg;
|
va_list arg;
|
||||||
|
|
||||||
va_start(arg, fmt);
|
va_start(arg, fmt);
|
||||||
s = vsmprint(fmt, arg);
|
s = vsmprint(fmt, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
if(s == nil)
|
if (s == nil)
|
||||||
return -1;
|
return -1;
|
||||||
m = strlen(s);
|
m = strlen(s);
|
||||||
n = write(fd, s, m);
|
n = write(fd, s, m);
|
||||||
if(ofd > 0)
|
if (ofd > 0)
|
||||||
write(ofd, s, m);
|
write(ofd, s, m);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void write2(int fd, int ofd, char* buf, int n, int nofrom) {
|
||||||
write2(int fd, int ofd, char *buf, int n, int nofrom)
|
|
||||||
{
|
|
||||||
char *from, *p;
|
char *from, *p;
|
||||||
int m;
|
int m;
|
||||||
|
|
||||||
write(fd, buf, n);
|
write(fd, buf, n);
|
||||||
|
|
||||||
if(ofd <= 0)
|
if (ofd <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(nofrom == 0){
|
if (nofrom == 0) {
|
||||||
write(ofd, buf, n);
|
write(ofd, buf, n);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* need to escape leading From lines to avoid corrupting 'outgoing' mailbox */
|
/* need to escape leading From lines to avoid corrupting 'outgoing' mailbox */
|
||||||
for(p=buf; *p; p+=m){
|
for (p = buf; *p; p += m) {
|
||||||
from = cistrstr(p, "from");
|
from = cistrstr(p, "from");
|
||||||
if(from == nil)
|
if (from == nil)
|
||||||
m = n;
|
m = n;
|
||||||
else
|
else
|
||||||
m = from - p;
|
m = from - p;
|
||||||
if(m > 0)
|
if (m > 0)
|
||||||
write(ofd, p, m);
|
write(ofd, p, m);
|
||||||
if(from){
|
if (from) {
|
||||||
if(p==buf || from[-1]=='\n')
|
if (p == buf || from[-1] == '\n')
|
||||||
write(ofd, " ", 1); /* escape with space if From is at start of line */
|
write(ofd, " ", 1); /* escape with space if From is at start of line */
|
||||||
write(ofd, from, 4);
|
write(ofd, from, 4);
|
||||||
m += 4;
|
m += 4;
|
||||||
|
@ -388,13 +356,11 @@ write2(int fd, int ofd, char *buf, int n, int nofrom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void mesgsend(Message* m) {
|
||||||
mesgsend(Message *m)
|
|
||||||
{
|
|
||||||
char *s, *body, *to;
|
char *s, *body, *to;
|
||||||
int i, j, h, n, natt, p[2];
|
int i, j, h, n, natt, p[2];
|
||||||
struct Exec *e;
|
struct Exec* e;
|
||||||
Channel *sync;
|
Channel* sync;
|
||||||
int first, nfld, delit, ofd;
|
int first, nfld, delit, ofd;
|
||||||
char *copy, *fld[100], *now;
|
char *copy, *fld[100], *now;
|
||||||
|
|
||||||
|
@ -406,83 +372,83 @@ mesgsend(Message *m)
|
||||||
nbcc = 0;
|
nbcc = 0;
|
||||||
first = 1;
|
first = 1;
|
||||||
to = body;
|
to = body;
|
||||||
for(;;){
|
for (;;) {
|
||||||
for(s=to; *s!='\n'; s++)
|
for (s = to; *s != '\n'; s++)
|
||||||
if(*s == '\0'){
|
if (*s == '\0') {
|
||||||
free(body);
|
free(body);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(s++ == to) /* blank line */
|
if (s++ == to) /* blank line */
|
||||||
break;
|
break;
|
||||||
/* make copy of line to tokenize */
|
/* make copy of line to tokenize */
|
||||||
copy = emalloc(s-to);
|
copy = emalloc(s - to);
|
||||||
memmove(copy, to, s-to);
|
memmove(copy, to, s - to);
|
||||||
copy[s-to-1] = '\0';
|
copy[s - to - 1] = '\0';
|
||||||
nfld = tokenizec(copy, fld, nelem(fld), ", \t");
|
nfld = tokenizec(copy, fld, nelem(fld), ", \t");
|
||||||
if(nfld == 0){
|
if (nfld == 0) {
|
||||||
free(copy);
|
free(copy);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n -= s-to;
|
n -= s - to;
|
||||||
switch(h = whichheader(fld[0])){
|
switch (h = whichheader(fld[0])) {
|
||||||
case TO:
|
case TO:
|
||||||
case FROM:
|
case FROM:
|
||||||
delit = 1;
|
delit = 1;
|
||||||
commas(to+strlen(fld[0]), s-1);
|
commas(to + strlen(fld[0]), s - 1);
|
||||||
for(i=1; i<nfld && nto<nelem(tolist); i++)
|
for (i = 1; i < nfld && nto < nelem(tolist); i++)
|
||||||
if(!addressed(fld[i]))
|
if (!addressed(fld[i]))
|
||||||
tolist[nto++] = estrdup(fld[i]);
|
tolist[nto++] = estrdup(fld[i]);
|
||||||
break;
|
break;
|
||||||
case BCC:
|
case BCC:
|
||||||
delit = 1;
|
delit = 1;
|
||||||
commas(to+strlen(fld[0]), s-1);
|
commas(to + strlen(fld[0]), s - 1);
|
||||||
for(i=1; i<nfld && nbcc<nelem(bcclist); i++)
|
for (i = 1; i < nfld && nbcc < nelem(bcclist); i++)
|
||||||
if(!addressed(fld[i]))
|
if (!addressed(fld[i]))
|
||||||
bcclist[nbcc++] = estrdup(fld[i]);
|
bcclist[nbcc++] = estrdup(fld[i]);
|
||||||
break;
|
break;
|
||||||
case CC:
|
case CC:
|
||||||
delit = 1;
|
delit = 1;
|
||||||
commas(to+strlen(fld[0]), s-1);
|
commas(to + strlen(fld[0]), s - 1);
|
||||||
for(i=1; i<nfld && ncc<nelem(cclist); i++)
|
for (i = 1; i < nfld && ncc < nelem(cclist); i++)
|
||||||
if(!addressed(fld[i]))
|
if (!addressed(fld[i]))
|
||||||
cclist[ncc++] = estrdup(fld[i]);
|
cclist[ncc++] = estrdup(fld[i]);
|
||||||
break;
|
break;
|
||||||
case ATTACH:
|
case ATTACH:
|
||||||
case INCLUDE:
|
case INCLUDE:
|
||||||
delit = 1;
|
delit = 1;
|
||||||
for(i=1; i<nfld && natt<nelem(attlist); i++){
|
for (i = 1; i < nfld && natt < nelem(attlist); i++) {
|
||||||
attlist[natt] = estrdup(fld[i]);
|
attlist[natt] = estrdup(fld[i]);
|
||||||
included[natt++] = (h == INCLUDE);
|
included[natt++] = (h == INCLUDE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(first){
|
if (first) {
|
||||||
delit = 1;
|
delit = 1;
|
||||||
for(i=0; i<nfld && nto<nelem(tolist); i++)
|
for (i = 0; i < nfld && nto < nelem(tolist); i++)
|
||||||
tolist[nto++] = estrdup(fld[i]);
|
tolist[nto++] = estrdup(fld[i]);
|
||||||
}else /* ignore it */
|
} else /* ignore it */
|
||||||
delit = 0;
|
delit = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(delit){
|
if (delit) {
|
||||||
/* delete line from body */
|
/* delete line from body */
|
||||||
memmove(to, s, n+1);
|
memmove(to, s, n + 1);
|
||||||
}else
|
} else
|
||||||
to = s;
|
to = s;
|
||||||
free(copy);
|
free(copy);
|
||||||
first = 0;
|
first = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ofd = open(outgoing, OWRITE|OCEXEC); /* no error check necessary */
|
ofd = open(outgoing, OWRITE | OCEXEC); /* no error check necessary */
|
||||||
if(ofd > 0){
|
if (ofd > 0) {
|
||||||
/* From dhog Fri Aug 24 22:13:00 EDT 2001 */
|
/* From dhog Fri Aug 24 22:13:00 EDT 2001 */
|
||||||
now = ctime(time(0));
|
now = ctime(time(0));
|
||||||
seek(ofd, 0, 2);
|
seek(ofd, 0, 2);
|
||||||
fprint(ofd, "From %s %s", user, now);
|
fprint(ofd, "From %s %s", user, now);
|
||||||
fprint(ofd, "From: %s\n", user);
|
fprint(ofd, "From: %s\n", user);
|
||||||
fprint(ofd, "Date: %s", now);
|
fprint(ofd, "Date: %s", now);
|
||||||
for(i=0; i<natt; i++)
|
for (i = 0; i < natt; i++)
|
||||||
if(included[i])
|
if (included[i])
|
||||||
fprint(ofd, "Include: %s\n", attlist[i]);
|
fprint(ofd, "Include: %s\n", attlist[i]);
|
||||||
else
|
else
|
||||||
fprint(ofd, "Attach: %s\n", attlist[i]);
|
fprint(ofd, "Attach: %s\n", attlist[i]);
|
||||||
|
@ -492,21 +458,21 @@ mesgsend(Message *m)
|
||||||
}
|
}
|
||||||
|
|
||||||
e = emalloc(sizeof(struct Exec));
|
e = emalloc(sizeof(struct Exec));
|
||||||
if(pipe(p) < 0)
|
if (pipe(p) < 0)
|
||||||
error("can't create pipe: %r");
|
error("can't create pipe: %r");
|
||||||
e->p[0] = p[0];
|
e->p[0] = p[0];
|
||||||
e->p[1] = p[1];
|
e->p[1] = p[1];
|
||||||
e->prog = unsharp("#9/bin/upas/marshal");
|
e->prog = unsharp("#9/bin/upas/marshal");
|
||||||
e->argv = emalloc((1+1+2+4*natt+1)*sizeof(char*));
|
e->argv = emalloc((1 + 1 + 2 + 4 * natt + 1) * sizeof(char*));
|
||||||
e->argv[0] = estrdup("marshal");
|
e->argv[0] = estrdup("marshal");
|
||||||
e->argv[1] = estrdup("-8");
|
e->argv[1] = estrdup("-8");
|
||||||
j = 2;
|
j = 2;
|
||||||
if(m->replyname){
|
if (m->replyname) {
|
||||||
e->argv[j++] = estrdup("-R");
|
e->argv[j++] = estrdup("-R");
|
||||||
e->argv[j++] = estrstrdup(mbox.name, m->replyname);
|
e->argv[j++] = estrstrdup(mbox.name, m->replyname);
|
||||||
}
|
}
|
||||||
for(i=0; i<natt; i++){
|
for (i = 0; i < natt; i++) {
|
||||||
if(included[i])
|
if (included[i])
|
||||||
e->argv[j++] = estrdup("-A");
|
e->argv[j++] = estrdup("-A");
|
||||||
else
|
else
|
||||||
e->argv[j++] = estrdup("-a");
|
e->argv[j++] = estrdup("-a");
|
||||||
|
@ -519,55 +485,55 @@ mesgsend(Message *m)
|
||||||
/* close(p[0]); */
|
/* close(p[0]); */
|
||||||
|
|
||||||
/* using marshal -8, so generate rfc822 headers */
|
/* using marshal -8, so generate rfc822 headers */
|
||||||
if(nto > 0){
|
if (nto > 0) {
|
||||||
print2(p[1], ofd, "To: ");
|
print2(p[1], ofd, "To: ");
|
||||||
for(i=0; i<nto-1; i++)
|
for (i = 0; i < nto - 1; i++)
|
||||||
print2(p[1], ofd, "%s, ", tolist[i]);
|
print2(p[1], ofd, "%s, ", tolist[i]);
|
||||||
print2(p[1], ofd, "%s\n", tolist[i]);
|
print2(p[1], ofd, "%s\n", tolist[i]);
|
||||||
}
|
}
|
||||||
if(ncc > 0){
|
if (ncc > 0) {
|
||||||
print2(p[1], ofd, "CC: ");
|
print2(p[1], ofd, "CC: ");
|
||||||
for(i=0; i<ncc-1; i++)
|
for (i = 0; i < ncc - 1; i++)
|
||||||
print2(p[1], ofd, "%s, ", cclist[i]);
|
print2(p[1], ofd, "%s, ", cclist[i]);
|
||||||
print2(p[1], ofd, "%s\n", cclist[i]);
|
print2(p[1], ofd, "%s\n", cclist[i]);
|
||||||
}
|
}
|
||||||
if(nbcc > 0){
|
if (nbcc > 0) {
|
||||||
print2(p[1], ofd, "BCC: ");
|
print2(p[1], ofd, "BCC: ");
|
||||||
for(i=0; i<nbcc-1; i++)
|
for (i = 0; i < nbcc - 1; i++)
|
||||||
print2(p[1], ofd, "%s, ", bcclist[i]);
|
print2(p[1], ofd, "%s, ", bcclist[i]);
|
||||||
print2(p[1], ofd, "%s\n", bcclist[i]);
|
print2(p[1], ofd, "%s\n", bcclist[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = strlen(body);
|
i = strlen(body);
|
||||||
if(i > 0)
|
if (i > 0)
|
||||||
write2(p[1], ofd, body, i, 1);
|
write2(p[1], ofd, body, i, 1);
|
||||||
|
|
||||||
/* guarantee a blank line, to ensure attachments are separated from body */
|
/* guarantee a blank line, to ensure attachments are separated from body */
|
||||||
if(i==0 || body[i-1]!='\n')
|
if (i == 0 || body[i - 1] != '\n')
|
||||||
write2(p[1], ofd, "\n\n", 2, 0);
|
write2(p[1], ofd, "\n\n", 2, 0);
|
||||||
else if(i>1 && body[i-2]!='\n')
|
else if (i > 1 && body[i - 2] != '\n')
|
||||||
write2(p[1], ofd, "\n", 1, 0);
|
write2(p[1], ofd, "\n", 1, 0);
|
||||||
|
|
||||||
/* these look like pseudo-attachments in the "outgoing" box */
|
/* these look like pseudo-attachments in the "outgoing" box */
|
||||||
if(ofd>0 && natt>0){
|
if (ofd > 0 && natt > 0) {
|
||||||
for(i=0; i<natt; i++)
|
for (i = 0; i < natt; i++)
|
||||||
if(included[i])
|
if (included[i])
|
||||||
fprint(ofd, "=====> Include: %s\n", attlist[i]);
|
fprint(ofd, "=====> Include: %s\n", attlist[i]);
|
||||||
else
|
else
|
||||||
fprint(ofd, "=====> Attach: %s\n", attlist[i]);
|
fprint(ofd, "=====> Attach: %s\n", attlist[i]);
|
||||||
}
|
}
|
||||||
if(ofd > 0)
|
if (ofd > 0)
|
||||||
write(ofd, "\n", 1);
|
write(ofd, "\n", 1);
|
||||||
|
|
||||||
for(i=0; i<natt; i++)
|
for (i = 0; i < natt; i++)
|
||||||
free(attlist[i]);
|
free(attlist[i]);
|
||||||
close(ofd);
|
close(ofd);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
free(body);
|
free(body);
|
||||||
|
|
||||||
if(m->replyname != nil)
|
if (m->replyname != nil)
|
||||||
mesgmenumark(mbox.w, m->replyname, "\t[replied]");
|
mesgmenumark(mbox.w, m->replyname, "\t[replied]");
|
||||||
if(m->name[0] == '/')
|
if (m->name[0] == '/')
|
||||||
s = estrdup(m->name);
|
s = estrdup(m->name);
|
||||||
else
|
else
|
||||||
s = estrstrdup(mbox.name, m->name);
|
s = estrstrdup(mbox.name, m->name);
|
||||||
|
|
BIN
mail/reply.o
BIN
mail/reply.o
Binary file not shown.
57
mail/util.c
57
mail/util.c
|
@ -6,59 +6,49 @@
|
||||||
#include <9pclient.h>
|
#include <9pclient.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
|
|
||||||
void*
|
void* emalloc(uint n) {
|
||||||
emalloc(uint n)
|
void* p;
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
p = malloc(n);
|
p = malloc(n);
|
||||||
if(p == nil)
|
if (p == nil)
|
||||||
error("can't malloc: %r");
|
error("can't malloc: %r");
|
||||||
memset(p, 0, n);
|
memset(p, 0, n);
|
||||||
setmalloctag(p, getcallerpc(&n));
|
setmalloctag(p, getcallerpc(&n));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void* erealloc(void* p, uint n) {
|
||||||
erealloc(void *p, uint n)
|
|
||||||
{
|
|
||||||
p = realloc(p, n);
|
p = realloc(p, n);
|
||||||
if(p == nil)
|
if (p == nil)
|
||||||
error("can't realloc: %r");
|
error("can't realloc: %r");
|
||||||
setmalloctag(p, getcallerpc(&n));
|
setmalloctag(p, getcallerpc(&n));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* estrdup(char* s) {
|
||||||
estrdup(char *s)
|
char* t;
|
||||||
{
|
|
||||||
char *t;
|
|
||||||
|
|
||||||
t = emalloc(strlen(s)+1);
|
t = emalloc(strlen(s) + 1);
|
||||||
strcpy(t, s);
|
strcpy(t, s);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* estrstrdup(char* s, char* t) {
|
||||||
estrstrdup(char *s, char *t)
|
char* u;
|
||||||
{
|
|
||||||
char *u;
|
|
||||||
|
|
||||||
u = emalloc(strlen(s)+strlen(t)+1);
|
u = emalloc(strlen(s) + strlen(t) + 1);
|
||||||
strcpy(u, s);
|
strcpy(u, s);
|
||||||
strcat(u, t);
|
strcat(u, t);
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* eappend(char* s, char* sep, char* t) {
|
||||||
eappend(char *s, char *sep, char *t)
|
char* u;
|
||||||
{
|
|
||||||
char *u;
|
|
||||||
|
|
||||||
if(t == nil)
|
if (t == nil)
|
||||||
u = estrstrdup(s, sep);
|
u = estrstrdup(s, sep);
|
||||||
else{
|
else {
|
||||||
u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1);
|
u = emalloc(strlen(s) + strlen(sep) + strlen(t) + 1);
|
||||||
strcpy(u, s);
|
strcpy(u, s);
|
||||||
strcat(u, sep);
|
strcat(u, sep);
|
||||||
strcat(u, t);
|
strcat(u, t);
|
||||||
|
@ -67,17 +57,13 @@ eappend(char *s, char *sep, char *t)
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* egrow(char* s, char* sep, char* t) {
|
||||||
egrow(char *s, char *sep, char *t)
|
|
||||||
{
|
|
||||||
s = eappend(s, sep, t);
|
s = eappend(s, sep, t);
|
||||||
free(t);
|
free(t);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void error(char* fmt, ...) {
|
||||||
error(char *fmt, ...)
|
|
||||||
{
|
|
||||||
Fmt f;
|
Fmt f;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
va_list arg;
|
va_list arg;
|
||||||
|
@ -92,16 +78,13 @@ error(char *fmt, ...)
|
||||||
threadexitsall(fmt);
|
threadexitsall(fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ctlprint(CFid* fd, char* fmt, ...) {
|
||||||
ctlprint(CFid *fd, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
va_list arg;
|
va_list arg;
|
||||||
|
|
||||||
va_start(arg, fmt);
|
va_start(arg, fmt);
|
||||||
n = fsvprint(fd, fmt, arg);
|
n = fsvprint(fd, fmt, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
if(n <= 0)
|
if (n <= 0)
|
||||||
error("control file write error: %r");
|
error("control file write error: %r");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
mail/util.o
BIN
mail/util.o
Binary file not shown.
237
mail/win.c
237
mail/win.c
|
@ -6,15 +6,13 @@
|
||||||
#include <9pclient.h>
|
#include <9pclient.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
|
|
||||||
Window*
|
Window* newwindow(void) {
|
||||||
newwindow(void)
|
|
||||||
{
|
|
||||||
char buf[12];
|
char buf[12];
|
||||||
Window *w;
|
Window* w;
|
||||||
|
|
||||||
w = emalloc(sizeof(Window));
|
w = emalloc(sizeof(Window));
|
||||||
w->ctl = fsopen(acmefs, "new/ctl", ORDWR|OCEXEC);
|
w->ctl = fsopen(acmefs, "new/ctl", ORDWR | OCEXEC);
|
||||||
if(w->ctl == nil || fsread(w->ctl, buf, 12)!=12)
|
if (w->ctl == nil || fsread(w->ctl, buf, 12) != 12)
|
||||||
error("can't open window ctl file: %r");
|
error("can't open window ctl file: %r");
|
||||||
|
|
||||||
w->id = atoi(buf);
|
w->id = atoi(buf);
|
||||||
|
@ -27,19 +25,15 @@ newwindow(void)
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winincref(Window* w) {
|
||||||
winincref(Window *w)
|
|
||||||
{
|
|
||||||
qlock(&w->lk);
|
qlock(&w->lk);
|
||||||
++w->ref;
|
++w->ref;
|
||||||
qunlock(&w->lk);
|
qunlock(&w->lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void windecref(Window* w) {
|
||||||
windecref(Window *w)
|
|
||||||
{
|
|
||||||
qlock(&w->lk);
|
qlock(&w->lk);
|
||||||
if(--w->ref > 0){
|
if (--w->ref > 0) {
|
||||||
qunlock(&w->lk);
|
qunlock(&w->lk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -48,119 +42,98 @@ windecref(Window *w)
|
||||||
free(w);
|
free(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winsetdump(Window* w, char* dir, char* cmd) {
|
||||||
winsetdump(Window *w, char *dir, char *cmd)
|
if (dir != nil)
|
||||||
{
|
|
||||||
if(dir != nil)
|
|
||||||
ctlprint(w->ctl, "dumpdir %s\n", dir);
|
ctlprint(w->ctl, "dumpdir %s\n", dir);
|
||||||
if(cmd != nil)
|
if (cmd != nil)
|
||||||
ctlprint(w->ctl, "dump %s\n", cmd);
|
ctlprint(w->ctl, "dump %s\n", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void wineventproc(void* v) {
|
||||||
wineventproc(void *v)
|
Window* w;
|
||||||
{
|
|
||||||
Window *w;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
w = v;
|
w = v;
|
||||||
for(i=0; ; i++){
|
for (i = 0;; i++) {
|
||||||
if(i >= NEVENT)
|
if (i >= NEVENT)
|
||||||
i = 0;
|
i = 0;
|
||||||
wingetevent(w, &w->e[i]);
|
wingetevent(w, &w->e[i]);
|
||||||
sendp(w->cevent, &w->e[i]);
|
sendp(w->cevent, &w->e[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CFid*
|
static CFid* winopenfile1(Window* w, char* f, int m) {
|
||||||
winopenfile1(Window *w, char *f, int m)
|
|
||||||
{
|
|
||||||
char buf[64];
|
char buf[64];
|
||||||
CFid* fd;
|
CFid* fd;
|
||||||
|
|
||||||
sprint(buf, "%d/%s", w->id, f);
|
sprint(buf, "%d/%s", w->id, f);
|
||||||
fd = fsopen(acmefs, buf, m|OCEXEC);
|
fd = fsopen(acmefs, buf, m | OCEXEC);
|
||||||
if(fd == nil)
|
if (fd == nil)
|
||||||
error("can't open window file %s: %r", f);
|
error("can't open window file %s: %r", f);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFid*
|
CFid* winopenfile(Window* w, char* f) { return winopenfile1(w, f, ORDWR); }
|
||||||
winopenfile(Window *w, char *f)
|
|
||||||
{
|
|
||||||
return winopenfile1(w, f, ORDWR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void wintagwrite(Window* w, char* s, int n) {
|
||||||
wintagwrite(Window *w, char *s, int n)
|
|
||||||
{
|
|
||||||
CFid* fid;
|
CFid* fid;
|
||||||
|
|
||||||
fid = winopenfile(w, "tag");
|
fid = winopenfile(w, "tag");
|
||||||
if(fswrite(fid, s, n) != n)
|
if (fswrite(fid, s, n) != n)
|
||||||
error("tag write: %r");
|
error("tag write: %r");
|
||||||
fsclose(fid);
|
fsclose(fid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winname(Window* w, char* s) {
|
||||||
winname(Window *w, char *s)
|
|
||||||
{
|
|
||||||
int len;
|
int len;
|
||||||
char *ns, *sp;
|
char *ns, *sp;
|
||||||
Rune r = L'␣'; /* visible space */
|
Rune r = L'␣'; /* visible space */
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
ns = emalloc(strlen(s)*runelen(r) + 1);
|
ns = emalloc(strlen(s) * runelen(r) + 1);
|
||||||
for(sp = s; *sp != '\0'; sp++, len++){
|
for (sp = s; *sp != '\0'; sp++, len++) {
|
||||||
if(isspace(*sp)){
|
if (isspace(*sp)) {
|
||||||
len += runetochar(ns+len, &r)-1;
|
len += runetochar(ns + len, &r) - 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*(ns+len) = *sp;
|
*(ns + len) = *sp;
|
||||||
}
|
}
|
||||||
ctlprint(w->ctl, "name %s\n", ns);
|
ctlprint(w->ctl, "name %s\n", ns);
|
||||||
free(ns);
|
free(ns);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winopenbody(Window* w, int mode) {
|
||||||
winopenbody(Window *w, int mode)
|
|
||||||
{
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
CFid* fid;
|
CFid* fid;
|
||||||
|
|
||||||
sprint(buf, "%d/body", w->id);
|
sprint(buf, "%d/body", w->id);
|
||||||
fid = fsopen(acmefs, buf, mode|OCEXEC);
|
fid = fsopen(acmefs, buf, mode | OCEXEC);
|
||||||
w->body = fid;
|
w->body = fid;
|
||||||
if(w->body == nil)
|
if (w->body == nil)
|
||||||
error("can't open window body file: %r");
|
error("can't open window body file: %r");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winclosebody(Window* w) {
|
||||||
winclosebody(Window *w)
|
if (w->body != nil) {
|
||||||
{
|
|
||||||
if(w->body != nil){
|
|
||||||
fsclose(w->body);
|
fsclose(w->body);
|
||||||
w->body = nil;
|
w->body = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winwritebody(Window* w, char* s, int n) {
|
||||||
winwritebody(Window *w, char *s, int n)
|
if (w->body == nil)
|
||||||
{
|
|
||||||
if(w->body == nil)
|
|
||||||
winopenbody(w, OWRITE);
|
winopenbody(w, OWRITE);
|
||||||
if(fswrite(w->body, s, n) != n)
|
if (fswrite(w->body, s, n) != n)
|
||||||
error("write error to window: %r");
|
error("write error to window: %r");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int wingetec(Window* w) {
|
||||||
wingetec(Window *w)
|
if (w->nbuf == 0) {
|
||||||
{
|
|
||||||
if(w->nbuf == 0){
|
|
||||||
w->nbuf = fsread(w->event, w->buf, sizeof w->buf);
|
w->nbuf = fsread(w->event, w->buf, sizeof w->buf);
|
||||||
if(w->nbuf <= 0){
|
if (w->nbuf <= 0) {
|
||||||
/* probably because window has exited, and only called by wineventproc, so just shut down */
|
/* probably because window has exited, and only called by wineventproc, so
|
||||||
|
* just shut down */
|
||||||
windecref(w);
|
windecref(w);
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
|
@ -170,30 +143,26 @@ wingetec(Window *w)
|
||||||
return *w->bufp++;
|
return *w->bufp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int wingeten(Window* w) {
|
||||||
wingeten(Window *w)
|
|
||||||
{
|
|
||||||
int n, c;
|
int n, c;
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
while('0'<=(c=wingetec(w)) && c<='9')
|
while ('0' <= (c = wingetec(w)) && c <= '9')
|
||||||
n = n*10+(c-'0');
|
n = n * 10 + (c - '0');
|
||||||
if(c != ' ')
|
if (c != ' ')
|
||||||
error("event number syntax");
|
error("event number syntax");
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int wingeter(Window* w, char* buf, int* nb) {
|
||||||
wingeter(Window *w, char *buf, int *nb)
|
|
||||||
{
|
|
||||||
Rune r;
|
Rune r;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
r = wingetec(w);
|
r = wingetec(w);
|
||||||
buf[0] = r;
|
buf[0] = r;
|
||||||
n = 1;
|
n = 1;
|
||||||
if(r >= Runeself) {
|
if (r >= Runeself) {
|
||||||
while(!fullrune(buf, n))
|
while (!fullrune(buf, n))
|
||||||
buf[n++] = wingetec(w);
|
buf[n++] = wingetec(w);
|
||||||
chartorune(&r, buf);
|
chartorune(&r, buf);
|
||||||
}
|
}
|
||||||
|
@ -201,9 +170,7 @@ wingeter(Window *w, char *buf, int *nb)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void wingetevent(Window* w, Event* e) {
|
||||||
wingetevent(Window *w, Event *e)
|
|
||||||
{
|
|
||||||
int i, nb;
|
int i, nb;
|
||||||
|
|
||||||
e->c1 = wingetec(w);
|
e->c1 = wingetec(w);
|
||||||
|
@ -212,49 +179,47 @@ wingetevent(Window *w, Event *e)
|
||||||
e->q1 = wingeten(w);
|
e->q1 = wingeten(w);
|
||||||
e->flag = wingeten(w);
|
e->flag = wingeten(w);
|
||||||
e->nr = wingeten(w);
|
e->nr = wingeten(w);
|
||||||
if(e->nr > EVENTSIZE)
|
if (e->nr > EVENTSIZE)
|
||||||
error("event string too long");
|
error("event string too long");
|
||||||
e->nb = 0;
|
e->nb = 0;
|
||||||
for(i=0; i<e->nr; i++){
|
for (i = 0; i < e->nr; i++) {
|
||||||
e->r[i] = wingeter(w, e->b+e->nb, &nb);
|
e->r[i] = wingeter(w, e->b + e->nb, &nb);
|
||||||
e->nb += nb;
|
e->nb += nb;
|
||||||
}
|
}
|
||||||
e->r[e->nr] = 0;
|
e->r[e->nr] = 0;
|
||||||
e->b[e->nb] = 0;
|
e->b[e->nb] = 0;
|
||||||
if(wingetec(w) != '\n')
|
if (wingetec(w) != '\n')
|
||||||
error("event syntax error");
|
error("event syntax error");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winwriteevent(Window* w, Event* e) {
|
||||||
winwriteevent(Window *w, Event *e)
|
|
||||||
{
|
|
||||||
fsprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
|
fsprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winread(Window* w, uint q0, uint q1, char* data) {
|
||||||
winread(Window *w, uint q0, uint q1, char *data)
|
|
||||||
{
|
|
||||||
int m, n, nr;
|
int m, n, nr;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
if(w->addr == nil)
|
if (w->addr == nil)
|
||||||
w->addr = winopenfile(w, "addr");
|
w->addr = winopenfile(w, "addr");
|
||||||
if(w->data == nil)
|
if (w->data == nil)
|
||||||
w->data = winopenfile(w, "data");
|
w->data = winopenfile(w, "data");
|
||||||
m = q0;
|
m = q0;
|
||||||
while(m < q1){
|
while (m < q1) {
|
||||||
n = sprint(buf, "#%d", m);
|
n = sprint(buf, "#%d", m);
|
||||||
if(fswrite(w->addr, buf, n) != n)
|
if (fswrite(w->addr, buf, n) != n)
|
||||||
error("error writing addr: %r");
|
error("error writing addr: %r");
|
||||||
n = fsread(w->data, buf, sizeof buf);
|
n = fsread(w->data, buf, sizeof buf);
|
||||||
if(n <= 0)
|
if (n <= 0)
|
||||||
error("reading data: %r");
|
error("reading data: %r");
|
||||||
nr = utfnlen(buf, n);
|
nr = utfnlen(buf, n);
|
||||||
while(m+nr >q1){
|
while (m + nr > q1) {
|
||||||
do; while(n>0 && (buf[--n]&0xC0)==0x80);
|
do
|
||||||
|
;
|
||||||
|
while (n > 0 && (buf[--n] & 0xC0) == 0x80);
|
||||||
--nr;
|
--nr;
|
||||||
}
|
}
|
||||||
if(n == 0)
|
if (n == 0)
|
||||||
break;
|
break;
|
||||||
memmove(data, buf, n);
|
memmove(data, buf, n);
|
||||||
data += n;
|
data += n;
|
||||||
|
@ -263,30 +228,25 @@ winread(Window *w, uint q0, uint q1, char *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void windormant(Window* w) {
|
||||||
windormant(Window *w)
|
if (w->addr != nil) {
|
||||||
{
|
|
||||||
if(w->addr != nil){
|
|
||||||
fsclose(w->addr);
|
fsclose(w->addr);
|
||||||
w->addr = nil;
|
w->addr = nil;
|
||||||
}
|
}
|
||||||
if(w->body != nil){
|
if (w->body != nil) {
|
||||||
fsclose(w->body);
|
fsclose(w->body);
|
||||||
w->body = nil;
|
w->body = nil;
|
||||||
}
|
}
|
||||||
if(w->data != nil){
|
if (w->data != nil) {
|
||||||
fsclose(w->data);
|
fsclose(w->data);
|
||||||
w->data = nil;
|
w->data = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int windel(Window* w, int sure) {
|
||||||
int
|
if (sure)
|
||||||
windel(Window *w, int sure)
|
|
||||||
{
|
|
||||||
if(sure)
|
|
||||||
fswrite(w->ctl, "delete\n", 7);
|
fswrite(w->ctl, "delete\n", 7);
|
||||||
else if(fswrite(w->ctl, "del\n", 4) != 4)
|
else if (fswrite(w->ctl, "del\n", 4) != 4)
|
||||||
return 0;
|
return 0;
|
||||||
/* event proc will die due to read error from event file */
|
/* event proc will die due to read error from event file */
|
||||||
windormant(w);
|
windormant(w);
|
||||||
|
@ -295,54 +255,47 @@ windel(Window *w, int sure)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winclean(Window* w) { ctlprint(w->ctl, "clean\n"); }
|
||||||
winclean(Window *w)
|
|
||||||
{
|
|
||||||
ctlprint(w->ctl, "clean\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int winsetaddr(Window* w, char* addr, int errok) {
|
||||||
winsetaddr(Window *w, char *addr, int errok)
|
if (w->addr == nil)
|
||||||
{
|
|
||||||
if(w->addr == nil)
|
|
||||||
w->addr = winopenfile(w, "addr");
|
w->addr = winopenfile(w, "addr");
|
||||||
if(fswrite(w->addr, addr, strlen(addr)) < 0){
|
if (fswrite(w->addr, addr, strlen(addr)) < 0) {
|
||||||
if(!errok)
|
if (!errok)
|
||||||
error("error writing addr(%s): %r", addr);
|
error("error writing addr(%s): %r", addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int winselect(Window* w, char* addr, int errok) {
|
||||||
winselect(Window *w, char *addr, int errok)
|
if (winsetaddr(w, addr, errok)) {
|
||||||
{
|
|
||||||
if(winsetaddr(w, addr, errok)){
|
|
||||||
ctlprint(w->ctl, "dot=addr\n");
|
ctlprint(w->ctl, "dot=addr\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* winreadbody(
|
||||||
winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */
|
Window* w,
|
||||||
|
int* np) /* can't use readfile because acme doesn't report the length */
|
||||||
{
|
{
|
||||||
char *s;
|
char* s;
|
||||||
int m, na, n;
|
int m, na, n;
|
||||||
|
|
||||||
if(w->body != nil)
|
if (w->body != nil)
|
||||||
winclosebody(w);
|
winclosebody(w);
|
||||||
winopenbody(w, OREAD);
|
winopenbody(w, OREAD);
|
||||||
s = nil;
|
s = nil;
|
||||||
na = 0;
|
na = 0;
|
||||||
n = 0;
|
n = 0;
|
||||||
for(;;){
|
for (;;) {
|
||||||
if(na < n+512){
|
if (na < n + 512) {
|
||||||
na += 1024;
|
na += 1024;
|
||||||
s = realloc(s, na+1);
|
s = realloc(s, na + 1);
|
||||||
}
|
}
|
||||||
m = fsread(w->body, s+n, na-n);
|
m = fsread(w->body, s + n, na - n);
|
||||||
if(m <= 0)
|
if (m <= 0)
|
||||||
break;
|
break;
|
||||||
n += m;
|
n += m;
|
||||||
}
|
}
|
||||||
|
@ -352,25 +305,23 @@ winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't repor
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* winselection(Window* w) {
|
||||||
winselection(Window *w)
|
|
||||||
{
|
|
||||||
int m, n;
|
int m, n;
|
||||||
char *buf;
|
char* buf;
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
CFid* fid;
|
CFid* fid;
|
||||||
|
|
||||||
fid = winopenfile1(w, "rdsel", OREAD);
|
fid = winopenfile1(w, "rdsel", OREAD);
|
||||||
if(fid == nil)
|
if (fid == nil)
|
||||||
error("can't open rdsel: %r");
|
error("can't open rdsel: %r");
|
||||||
n = 0;
|
n = 0;
|
||||||
buf = nil;
|
buf = nil;
|
||||||
for(;;){
|
for (;;) {
|
||||||
m = fsread(fid, tmp, sizeof tmp);
|
m = fsread(fid, tmp, sizeof tmp);
|
||||||
if(m <= 0)
|
if (m <= 0)
|
||||||
break;
|
break;
|
||||||
buf = erealloc(buf, n+m+1);
|
buf = erealloc(buf, n + m + 1);
|
||||||
memmove(buf+n, tmp, m);
|
memmove(buf + n, tmp, m);
|
||||||
n += m;
|
n += m;
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
}
|
}
|
||||||
|
|
BIN
mail/win.o
BIN
mail/win.o
Binary file not shown.
459
regx.c
459
regx.c
|
@ -13,39 +13,37 @@
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
Rangeset sel;
|
Rangeset sel;
|
||||||
Rune *lastregexp;
|
Rune* lastregexp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Machine Information
|
* Machine Information
|
||||||
*/
|
*/
|
||||||
typedef struct Inst Inst;
|
typedef struct Inst Inst;
|
||||||
struct Inst
|
struct Inst {
|
||||||
{
|
|
||||||
uint type; /* < OPERATOR ==> literal, otherwise action */
|
uint type; /* < OPERATOR ==> literal, otherwise action */
|
||||||
union {
|
union {
|
||||||
int sid;
|
int sid;
|
||||||
int subid;
|
int subid;
|
||||||
int class;
|
int class;
|
||||||
Inst *other;
|
Inst* other;
|
||||||
Inst *right;
|
Inst* right;
|
||||||
} u;
|
} u;
|
||||||
union{
|
union {
|
||||||
Inst *left;
|
Inst* left;
|
||||||
Inst *next;
|
Inst* next;
|
||||||
} u1;
|
} u1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NPROG 1024
|
#define NPROG 1024
|
||||||
Inst program[NPROG];
|
Inst program[NPROG];
|
||||||
Inst *progp;
|
Inst* progp;
|
||||||
Inst *startinst; /* First inst. of program; might not be program[0] */
|
Inst* startinst; /* First inst. of program; might not be program[0] */
|
||||||
Inst *bstartinst; /* same for backwards machine */
|
Inst* bstartinst; /* same for backwards machine */
|
||||||
Channel *rechan; /* chan(Inst*) */
|
Channel* rechan; /* chan(Inst*) */
|
||||||
|
|
||||||
typedef struct Ilist Ilist;
|
typedef struct Ilist Ilist;
|
||||||
struct Ilist
|
struct Ilist {
|
||||||
{
|
Inst* inst; /* Instruction of the thread */
|
||||||
Inst *inst; /* Instruction of the thread */
|
|
||||||
Rangeset se;
|
Rangeset se;
|
||||||
uint startp; /* first char of match */
|
uint startp; /* first char of match */
|
||||||
};
|
};
|
||||||
|
@ -53,7 +51,7 @@ struct Ilist
|
||||||
#define NLIST 127
|
#define NLIST 127
|
||||||
|
|
||||||
Ilist *tl, *nl; /* This list, next list */
|
Ilist *tl, *nl; /* This list, next list */
|
||||||
Ilist list[2][NLIST+1]; /* +1 for trailing null */
|
Ilist list[2][NLIST + 1]; /* +1 for trailing null */
|
||||||
static Rangeset sempty;
|
static Rangeset sempty;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -63,21 +61,21 @@ static Rangeset sempty;
|
||||||
* 0x20000xx are tokens, i.e. operands for operators
|
* 0x20000xx are tokens, i.e. operands for operators
|
||||||
*/
|
*/
|
||||||
#define OPERATOR 0x1000000 /* Bit set in all operators */
|
#define OPERATOR 0x1000000 /* Bit set in all operators */
|
||||||
#define START (OPERATOR+0) /* Start, used for marker on stack */
|
#define START (OPERATOR + 0) /* Start, used for marker on stack */
|
||||||
#define RBRA (OPERATOR+1) /* Right bracket, ) */
|
#define RBRA (OPERATOR + 1) /* Right bracket, ) */
|
||||||
#define LBRA (OPERATOR+2) /* Left bracket, ( */
|
#define LBRA (OPERATOR + 2) /* Left bracket, ( */
|
||||||
#define OR (OPERATOR+3) /* Alternation, | */
|
#define OR (OPERATOR + 3) /* Alternation, | */
|
||||||
#define CAT (OPERATOR+4) /* Concatentation, implicit operator */
|
#define CAT (OPERATOR + 4) /* Concatentation, implicit operator */
|
||||||
#define STAR (OPERATOR+5) /* Closure, * */
|
#define STAR (OPERATOR + 5) /* Closure, * */
|
||||||
#define PLUS (OPERATOR+6) /* a+ == aa* */
|
#define PLUS (OPERATOR + 6) /* a+ == aa* */
|
||||||
#define QUEST (OPERATOR+7) /* a? == a|nothing, i.e. 0 or 1 a's */
|
#define QUEST (OPERATOR + 7) /* a? == a|nothing, i.e. 0 or 1 a's */
|
||||||
#define ANY 0x2000000 /* Any character but newline, . */
|
#define ANY 0x2000000 /* Any character but newline, . */
|
||||||
#define NOP (ANY+1) /* No operation, internal use only */
|
#define NOP (ANY + 1) /* No operation, internal use only */
|
||||||
#define BOL (ANY+2) /* Beginning of line, ^ */
|
#define BOL (ANY + 2) /* Beginning of line, ^ */
|
||||||
#define EOL (ANY+3) /* End of line, $ */
|
#define EOL (ANY + 3) /* End of line, $ */
|
||||||
#define CCLASS (ANY+4) /* Character class, [] */
|
#define CCLASS (ANY + 4) /* Character class, [] */
|
||||||
#define NCCLASS (ANY+5) /* Negated character class, [^] */
|
#define NCCLASS (ANY + 5) /* Negated character class, [^] */
|
||||||
#define END (ANY+0x77) /* Terminate: match found */
|
#define END (ANY + 0x77) /* Terminate: match found */
|
||||||
|
|
||||||
#define ISATOR OPERATOR
|
#define ISATOR OPERATOR
|
||||||
#define ISAND ANY
|
#define ISAND ANY
|
||||||
|
@ -88,36 +86,35 @@ static Rangeset sempty;
|
||||||
* Parser Information
|
* Parser Information
|
||||||
*/
|
*/
|
||||||
typedef struct Node Node;
|
typedef struct Node Node;
|
||||||
struct Node
|
struct Node {
|
||||||
{
|
Inst* first;
|
||||||
Inst *first;
|
Inst* last;
|
||||||
Inst *last;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NSTACK 20
|
#define NSTACK 20
|
||||||
Node andstack[NSTACK];
|
Node andstack[NSTACK];
|
||||||
Node *andp;
|
Node* andp;
|
||||||
int atorstack[NSTACK];
|
int atorstack[NSTACK];
|
||||||
int *atorp;
|
int* atorp;
|
||||||
int lastwasand; /* Last token was operand */
|
int lastwasand; /* Last token was operand */
|
||||||
int cursubid;
|
int cursubid;
|
||||||
int subidstack[NSTACK];
|
int subidstack[NSTACK];
|
||||||
int *subidp;
|
int* subidp;
|
||||||
int backwards;
|
int backwards;
|
||||||
int nbra;
|
int nbra;
|
||||||
Rune *exprp; /* pointer to next character in source expression */
|
Rune* exprp; /* pointer to next character in source expression */
|
||||||
#define DCLASS 10 /* allocation increment */
|
#define DCLASS 10 /* allocation increment */
|
||||||
int nclass; /* number active */
|
int nclass; /* number active */
|
||||||
int Nclass; /* high water mark */
|
int Nclass; /* high water mark */
|
||||||
Rune **class;
|
Rune** class;
|
||||||
int negateclass;
|
int negateclass;
|
||||||
|
|
||||||
int addinst(Ilist *l, Inst *inst, Rangeset *sep);
|
int addinst(Ilist* l, Inst* inst, Rangeset* sep);
|
||||||
void newmatch(Rangeset*);
|
void newmatch(Rangeset*);
|
||||||
void bnewmatch(Rangeset*);
|
void bnewmatch(Rangeset*);
|
||||||
void pushand(Inst*, Inst*);
|
void pushand(Inst*, Inst*);
|
||||||
void pushator(int);
|
void pushator(int);
|
||||||
Node *popand(int);
|
Node* popand(int);
|
||||||
int popator(void);
|
int popator(void);
|
||||||
void startlex(Rune*);
|
void startlex(Rune*);
|
||||||
int lex(void);
|
int lex(void);
|
||||||
|
@ -127,27 +124,21 @@ void evaluntil(int);
|
||||||
void optimize(Inst*);
|
void optimize(Inst*);
|
||||||
void bldcclass(void);
|
void bldcclass(void);
|
||||||
|
|
||||||
void
|
void rxinit(void) {
|
||||||
rxinit(void)
|
|
||||||
{
|
|
||||||
rechan = chancreate(sizeof(Inst*), 0);
|
rechan = chancreate(sizeof(Inst*), 0);
|
||||||
chansetname(rechan, "rechan");
|
chansetname(rechan, "rechan");
|
||||||
lastregexp = runemalloc(1);
|
lastregexp = runemalloc(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void regerror(char* e) {
|
||||||
regerror(char *e)
|
|
||||||
{
|
|
||||||
lastregexp[0] = 0;
|
lastregexp[0] = 0;
|
||||||
warning(nil, "regexp: %s\n", e);
|
warning(nil, "regexp: %s\n", e);
|
||||||
sendp(rechan, nil);
|
sendp(rechan, nil);
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
Inst *
|
Inst* newinst(int t) {
|
||||||
newinst(int t)
|
if (progp >= &program[NPROG])
|
||||||
{
|
|
||||||
if(progp >= &program[NPROG])
|
|
||||||
regerror("expression too long");
|
regerror("expression too long");
|
||||||
progp->type = t;
|
progp->type = t;
|
||||||
progp->u1.left = nil;
|
progp->u1.left = nil;
|
||||||
|
@ -155,11 +146,9 @@ newinst(int t)
|
||||||
return progp++;
|
return progp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void realcompile(void* arg) {
|
||||||
realcompile(void *arg)
|
|
||||||
{
|
|
||||||
int token;
|
int token;
|
||||||
Rune *s;
|
Rune* s;
|
||||||
|
|
||||||
threadsetname("regcomp");
|
threadsetname("regcomp");
|
||||||
s = arg;
|
s = arg;
|
||||||
|
@ -170,9 +159,9 @@ realcompile(void *arg)
|
||||||
cursubid = 0;
|
cursubid = 0;
|
||||||
lastwasand = FALSE;
|
lastwasand = FALSE;
|
||||||
/* Start with a low priority operator to prime parser */
|
/* Start with a low priority operator to prime parser */
|
||||||
pushator(START-1);
|
pushator(START - 1);
|
||||||
while((token=lex()) != END){
|
while ((token = lex()) != END) {
|
||||||
if((token&ISATOR) == OPERATOR)
|
if ((token & ISATOR) == OPERATOR)
|
||||||
operator(token);
|
operator(token);
|
||||||
else
|
else
|
||||||
operand(token);
|
operand(token);
|
||||||
|
@ -182,7 +171,7 @@ realcompile(void *arg)
|
||||||
/* Force END */
|
/* Force END */
|
||||||
operand(END);
|
operand(END);
|
||||||
evaluntil(START);
|
evaluntil(START);
|
||||||
if(nbra)
|
if (nbra)
|
||||||
regerror("unmatched `('");
|
regerror("unmatched `('");
|
||||||
--andp; /* points to first and only operand */
|
--andp; /* points to first and only operand */
|
||||||
sendp(rechan, andp->first);
|
sendp(rechan, andp->first);
|
||||||
|
@ -190,17 +179,15 @@ realcompile(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* r is null terminated */
|
/* r is null terminated */
|
||||||
int
|
int rxcompile(Rune* r) {
|
||||||
rxcompile(Rune *r)
|
|
||||||
{
|
|
||||||
int i, nr;
|
int i, nr;
|
||||||
Inst *oprogp;
|
Inst* oprogp;
|
||||||
|
|
||||||
nr = runestrlen(r)+1;
|
nr = runestrlen(r) + 1;
|
||||||
if(runeeq(lastregexp, runestrlen(lastregexp)+1, r, nr)==TRUE)
|
if (runeeq(lastregexp, runestrlen(lastregexp) + 1, r, nr) == TRUE)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
lastregexp[0] = 0;
|
lastregexp[0] = 0;
|
||||||
for(i=0; i<nclass; i++)
|
for (i = 0; i < nclass; i++)
|
||||||
free(class[i]);
|
free(class[i]);
|
||||||
nclass = 0;
|
nclass = 0;
|
||||||
progp = program;
|
progp = program;
|
||||||
|
@ -208,14 +195,14 @@ rxcompile(Rune *r)
|
||||||
bstartinst = nil;
|
bstartinst = nil;
|
||||||
threadcreate(realcompile, r, STACK);
|
threadcreate(realcompile, r, STACK);
|
||||||
startinst = recvp(rechan);
|
startinst = recvp(rechan);
|
||||||
if(startinst == nil)
|
if (startinst == nil)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
optimize(program);
|
optimize(program);
|
||||||
oprogp = progp;
|
oprogp = progp;
|
||||||
backwards = TRUE;
|
backwards = TRUE;
|
||||||
threadcreate(realcompile, r, STACK);
|
threadcreate(realcompile, r, STACK);
|
||||||
bstartinst = recvp(rechan);
|
bstartinst = recvp(rechan);
|
||||||
if(bstartinst == nil)
|
if (bstartinst == nil)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
optimize(oprogp);
|
optimize(oprogp);
|
||||||
lastregexp = runerealloc(lastregexp, nr);
|
lastregexp = runerealloc(lastregexp, nr);
|
||||||
|
@ -223,94 +210,80 @@ rxcompile(Rune *r)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void operand(int t) {
|
||||||
operand(int t)
|
Inst* i;
|
||||||
{
|
if (lastwasand)
|
||||||
Inst *i;
|
|
||||||
if(lastwasand)
|
|
||||||
operator(CAT); /* catenate is implicit */
|
operator(CAT); /* catenate is implicit */
|
||||||
i = newinst(t);
|
i = newinst(t);
|
||||||
if(t == CCLASS){
|
if (t == CCLASS) {
|
||||||
if(negateclass)
|
if (negateclass)
|
||||||
i->type = NCCLASS; /* UGH */
|
i->type = NCCLASS; /* UGH */
|
||||||
i->u.class = nclass-1; /* UGH */
|
i->u.class = nclass - 1; /* UGH */
|
||||||
}
|
}
|
||||||
pushand(i, i);
|
pushand(i, i);
|
||||||
lastwasand = TRUE;
|
lastwasand = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void operator(int t) {
|
||||||
operator(int t)
|
if (t == RBRA && --nbra < 0)
|
||||||
{
|
|
||||||
if(t==RBRA && --nbra<0)
|
|
||||||
regerror("unmatched `)'");
|
regerror("unmatched `)'");
|
||||||
if(t==LBRA){
|
if (t == LBRA) {
|
||||||
cursubid++; /* silently ignored */
|
cursubid++; /* silently ignored */
|
||||||
nbra++;
|
nbra++;
|
||||||
if(lastwasand)
|
if (lastwasand)
|
||||||
operator(CAT);
|
operator(CAT);
|
||||||
}else
|
} else
|
||||||
evaluntil(t);
|
evaluntil(t);
|
||||||
if(t!=RBRA)
|
if (t != RBRA)
|
||||||
pushator(t);
|
pushator(t);
|
||||||
lastwasand = FALSE;
|
lastwasand = FALSE;
|
||||||
if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
|
if (t == STAR || t == QUEST || t == PLUS || t == RBRA)
|
||||||
lastwasand = TRUE; /* these look like operands */
|
lastwasand = TRUE; /* these look like operands */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void pushand(Inst* f, Inst* l) {
|
||||||
pushand(Inst *f, Inst *l)
|
if (andp >= &andstack[NSTACK])
|
||||||
{
|
|
||||||
if(andp >= &andstack[NSTACK])
|
|
||||||
error("operand stack overflow");
|
error("operand stack overflow");
|
||||||
andp->first = f;
|
andp->first = f;
|
||||||
andp->last = l;
|
andp->last = l;
|
||||||
andp++;
|
andp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void pushator(int t) {
|
||||||
pushator(int t)
|
if (atorp >= &atorstack[NSTACK])
|
||||||
{
|
|
||||||
if(atorp >= &atorstack[NSTACK])
|
|
||||||
error("operator stack overflow");
|
error("operator stack overflow");
|
||||||
*atorp++=t;
|
*atorp++ = t;
|
||||||
if(cursubid >= NRange)
|
if (cursubid >= NRange)
|
||||||
*subidp++= -1;
|
*subidp++ = -1;
|
||||||
else
|
else
|
||||||
*subidp++=cursubid;
|
*subidp++ = cursubid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *
|
Node* popand(int op) {
|
||||||
popand(int op)
|
|
||||||
{
|
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
if(andp <= &andstack[0])
|
if (andp <= &andstack[0])
|
||||||
if(op){
|
if (op) {
|
||||||
sprint(buf, "missing operand for %c", op);
|
sprint(buf, "missing operand for %c", op);
|
||||||
regerror(buf);
|
regerror(buf);
|
||||||
}else
|
} else
|
||||||
regerror("malformed regexp");
|
regerror("malformed regexp");
|
||||||
return --andp;
|
return --andp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int popator() {
|
||||||
popator()
|
if (atorp <= &atorstack[0])
|
||||||
{
|
|
||||||
if(atorp <= &atorstack[0])
|
|
||||||
error("operator stack underflow");
|
error("operator stack underflow");
|
||||||
--subidp;
|
--subidp;
|
||||||
return *--atorp;
|
return *--atorp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void evaluntil(int pri) {
|
||||||
evaluntil(int pri)
|
|
||||||
{
|
|
||||||
Node *op1, *op2, *t;
|
Node *op1, *op2, *t;
|
||||||
Inst *inst1, *inst2;
|
Inst *inst1, *inst2;
|
||||||
|
|
||||||
while(pri==RBRA || atorp[-1]>=pri){
|
while (pri == RBRA || atorp[-1] >= pri) {
|
||||||
switch(popator()){
|
switch (popator()) {
|
||||||
case LBRA:
|
case LBRA:
|
||||||
op1 = popand('(');
|
op1 = popand('(');
|
||||||
inst2 = newinst(RBRA);
|
inst2 = newinst(RBRA);
|
||||||
|
@ -338,7 +311,7 @@ evaluntil(int pri)
|
||||||
case CAT:
|
case CAT:
|
||||||
op2 = popand(0);
|
op2 = popand(0);
|
||||||
op1 = popand(0);
|
op1 = popand(0);
|
||||||
if(backwards && op2->first->type!=END){
|
if (backwards && op2->first->type != END) {
|
||||||
t = op1;
|
t = op1;
|
||||||
op1 = op2;
|
op1 = op2;
|
||||||
op2 = t;
|
op2 = t;
|
||||||
|
@ -373,38 +346,31 @@ evaluntil(int pri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void optimize(Inst* start) {
|
||||||
void
|
|
||||||
optimize(Inst *start)
|
|
||||||
{
|
|
||||||
Inst *inst, *target;
|
Inst *inst, *target;
|
||||||
|
|
||||||
for(inst=start; inst->type!=END; inst++){
|
for (inst = start; inst->type != END; inst++) {
|
||||||
target = inst->u1.next;
|
target = inst->u1.next;
|
||||||
while(target->type == NOP)
|
while (target->type == NOP)
|
||||||
target = target->u1.next;
|
target = target->u1.next;
|
||||||
inst->u1.next = target;
|
inst->u1.next = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void startlex(Rune* s) {
|
||||||
startlex(Rune *s)
|
|
||||||
{
|
|
||||||
exprp = s;
|
exprp = s;
|
||||||
nbra = 0;
|
nbra = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lex(void) {
|
||||||
int
|
|
||||||
lex(void){
|
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
c = *exprp++;
|
c = *exprp++;
|
||||||
switch(c){
|
switch (c) {
|
||||||
case '\\':
|
case '\\':
|
||||||
if(*exprp)
|
if (*exprp)
|
||||||
if((c= *exprp++)=='n')
|
if ((c = *exprp++) == 'n')
|
||||||
c='\n';
|
c = '\n';
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
c = END;
|
c = END;
|
||||||
|
@ -445,79 +411,73 @@ lex(void){
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int nextrec(void) {
|
||||||
nextrec(void)
|
if (exprp[0] == 0 || (exprp[0] == '\\' && exprp[1] == 0))
|
||||||
{
|
|
||||||
if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0))
|
|
||||||
regerror("malformed `[]'");
|
regerror("malformed `[]'");
|
||||||
if(exprp[0] == '\\'){
|
if (exprp[0] == '\\') {
|
||||||
exprp++;
|
exprp++;
|
||||||
if(*exprp=='n'){
|
if (*exprp == 'n') {
|
||||||
exprp++;
|
exprp++;
|
||||||
return '\n';
|
return '\n';
|
||||||
}
|
}
|
||||||
return *exprp++|QUOTED;
|
return *exprp++ | QUOTED;
|
||||||
}
|
}
|
||||||
return *exprp++;
|
return *exprp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void bldcclass(void) {
|
||||||
bldcclass(void)
|
|
||||||
{
|
|
||||||
int c1, c2, n, na;
|
int c1, c2, n, na;
|
||||||
Rune *classp;
|
Rune* classp;
|
||||||
|
|
||||||
classp = runemalloc(DCLASS);
|
classp = runemalloc(DCLASS);
|
||||||
n = 0;
|
n = 0;
|
||||||
na = DCLASS;
|
na = DCLASS;
|
||||||
/* we have already seen the '[' */
|
/* we have already seen the '[' */
|
||||||
if(*exprp == '^'){
|
if (*exprp == '^') {
|
||||||
classp[n++] = '\n'; /* don't match newline in negate case */
|
classp[n++] = '\n'; /* don't match newline in negate case */
|
||||||
negateclass = TRUE;
|
negateclass = TRUE;
|
||||||
exprp++;
|
exprp++;
|
||||||
}else
|
} else
|
||||||
negateclass = FALSE;
|
negateclass = FALSE;
|
||||||
while((c1 = nextrec()) != ']'){
|
while ((c1 = nextrec()) != ']') {
|
||||||
if(c1 == '-'){
|
if (c1 == '-') {
|
||||||
Error:
|
Error:
|
||||||
free(classp);
|
free(classp);
|
||||||
regerror("malformed `[]'");
|
regerror("malformed `[]'");
|
||||||
}
|
}
|
||||||
if(n+4 >= na){ /* 3 runes plus NUL */
|
if (n + 4 >= na) { /* 3 runes plus NUL */
|
||||||
na += DCLASS;
|
na += DCLASS;
|
||||||
classp = runerealloc(classp, na);
|
classp = runerealloc(classp, na);
|
||||||
}
|
}
|
||||||
if(*exprp == '-'){
|
if (*exprp == '-') {
|
||||||
exprp++; /* eat '-' */
|
exprp++; /* eat '-' */
|
||||||
if((c2 = nextrec()) == ']')
|
if ((c2 = nextrec()) == ']')
|
||||||
goto Error;
|
goto Error;
|
||||||
classp[n+0] = Runemax;
|
classp[n + 0] = Runemax;
|
||||||
classp[n+1] = c1;
|
classp[n + 1] = c1;
|
||||||
classp[n+2] = c2;
|
classp[n + 2] = c2;
|
||||||
n += 3;
|
n += 3;
|
||||||
}else
|
} else
|
||||||
classp[n++] = c1 & ~QUOTED;
|
classp[n++] = c1 & ~QUOTED;
|
||||||
}
|
}
|
||||||
classp[n] = 0;
|
classp[n] = 0;
|
||||||
if(nclass == Nclass){
|
if (nclass == Nclass) {
|
||||||
Nclass += DCLASS;
|
Nclass += DCLASS;
|
||||||
class = realloc(class, Nclass*sizeof(Rune*));
|
class = realloc(class, Nclass * sizeof(Rune*));
|
||||||
}
|
}
|
||||||
class[nclass++] = classp;
|
class[nclass++] = classp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int classmatch(int classno, int c, int negate) {
|
||||||
classmatch(int classno, int c, int negate)
|
Rune* p;
|
||||||
{
|
|
||||||
Rune *p;
|
|
||||||
|
|
||||||
p = class[classno];
|
p = class[classno];
|
||||||
while(*p){
|
while (*p) {
|
||||||
if(*p == Runemax){
|
if (*p == Runemax) {
|
||||||
if(p[1]<=c && c<=p[2])
|
if (p[1] <= c && c <= p[2])
|
||||||
return !negate;
|
return !negate;
|
||||||
p += 3;
|
p += 3;
|
||||||
}else if(*p++ == c)
|
} else if (*p++ == c)
|
||||||
return !negate;
|
return !negate;
|
||||||
}
|
}
|
||||||
return negate;
|
return negate;
|
||||||
|
@ -528,37 +488,29 @@ classmatch(int classno, int c, int negate)
|
||||||
* *l must be pending when addinst called; if *l has been looked
|
* *l must be pending when addinst called; if *l has been looked
|
||||||
* at already, the optimization is a bug.
|
* at already, the optimization is a bug.
|
||||||
*/
|
*/
|
||||||
int
|
int addinst(Ilist* l, Inst* inst, Rangeset* sep) {
|
||||||
addinst(Ilist *l, Inst *inst, Rangeset *sep)
|
Ilist* p;
|
||||||
{
|
|
||||||
Ilist *p;
|
|
||||||
|
|
||||||
for(p = l; p->inst; p++){
|
for (p = l; p->inst; p++) {
|
||||||
if(p->inst==inst){
|
if (p->inst == inst) {
|
||||||
if((sep)->r[0].q0 < p->se.r[0].q0)
|
if ((sep)->r[0].q0 < p->se.r[0].q0)
|
||||||
p->se= *sep; /* this would be bug */
|
p->se = *sep; /* this would be bug */
|
||||||
return 0; /* It's already there */
|
return 0; /* It's already there */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p->inst = inst;
|
p->inst = inst;
|
||||||
p->se= *sep;
|
p->se = *sep;
|
||||||
(p+1)->inst = nil;
|
(p + 1)->inst = nil;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int rxnull(void) { return startinst == nil || bstartinst == nil; }
|
||||||
rxnull(void)
|
|
||||||
{
|
|
||||||
return startinst==nil || bstartinst==nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* either t!=nil or r!=nil, and we match the string in the appropriate place */
|
/* either t!=nil or r!=nil, and we match the string in the appropriate place */
|
||||||
int
|
int rxexecute(Text* t, Rune* r, uint startp, uint eof, Rangeset* rp) {
|
||||||
rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
|
|
||||||
{
|
|
||||||
int flag;
|
int flag;
|
||||||
Inst *inst;
|
Inst* inst;
|
||||||
Ilist *tlp;
|
Ilist* tlp;
|
||||||
uint p;
|
uint p;
|
||||||
int nnl, ntl;
|
int nnl, ntl;
|
||||||
int nc, c;
|
int nc, c;
|
||||||
|
@ -570,24 +522,24 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
|
||||||
startchar = 0;
|
startchar = 0;
|
||||||
wrapped = 0;
|
wrapped = 0;
|
||||||
nnl = 0;
|
nnl = 0;
|
||||||
if(startinst->type<OPERATOR)
|
if (startinst->type < OPERATOR)
|
||||||
startchar = startinst->type;
|
startchar = startinst->type;
|
||||||
list[0][0].inst = list[1][0].inst = nil;
|
list[0][0].inst = list[1][0].inst = nil;
|
||||||
sel.r[0].q0 = -1;
|
sel.r[0].q0 = -1;
|
||||||
if(t != nil)
|
if (t != nil)
|
||||||
nc = t->file->b.nc;
|
nc = t->file->b.nc;
|
||||||
else
|
else
|
||||||
nc = runestrlen(r);
|
nc = runestrlen(r);
|
||||||
/* Execute machine once for each character */
|
/* Execute machine once for each character */
|
||||||
for(;;p++){
|
for (;; p++) {
|
||||||
doloop:
|
doloop:
|
||||||
if(p>=eof || p>=nc){
|
if (p >= eof || p >= nc) {
|
||||||
switch(wrapped++){
|
switch (wrapped++) {
|
||||||
case 0: /* let loop run one more click */
|
case 0: /* let loop run one more click */
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
case 1: /* expired; wrap to beginning */
|
case 1: /* expired; wrap to beginning */
|
||||||
if(sel.r[0].q0>=0 || eof!=Infinity)
|
if (sel.r[0].q0 >= 0 || eof != Infinity)
|
||||||
goto Return;
|
goto Return;
|
||||||
list[0][0].inst = list[1][0].inst = nil;
|
list[0][0].inst = list[1][0].inst = nil;
|
||||||
p = 0;
|
p = 0;
|
||||||
|
@ -596,27 +548,27 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
|
||||||
goto Return;
|
goto Return;
|
||||||
}
|
}
|
||||||
c = 0;
|
c = 0;
|
||||||
}else{
|
} else {
|
||||||
if(((wrapped && p>=startp) || sel.r[0].q0>0) && nnl==0)
|
if (((wrapped && p >= startp) || sel.r[0].q0 > 0) && nnl == 0)
|
||||||
break;
|
break;
|
||||||
if(t != nil)
|
if (t != nil)
|
||||||
c = textreadc(t, p);
|
c = textreadc(t, p);
|
||||||
else
|
else
|
||||||
c = r[p];
|
c = r[p];
|
||||||
}
|
}
|
||||||
/* fast check for first char */
|
/* fast check for first char */
|
||||||
if(startchar && nnl==0 && c!=startchar)
|
if (startchar && nnl == 0 && c != startchar)
|
||||||
continue;
|
continue;
|
||||||
tl = list[flag];
|
tl = list[flag];
|
||||||
nl = list[flag^=1];
|
nl = list[flag ^= 1];
|
||||||
nl->inst = nil;
|
nl->inst = nil;
|
||||||
ntl = nnl;
|
ntl = nnl;
|
||||||
nnl = 0;
|
nnl = 0;
|
||||||
if(sel.r[0].q0<0 && (!wrapped || p<startp || startp==eof)){
|
if (sel.r[0].q0 < 0 && (!wrapped || p < startp || startp == eof)) {
|
||||||
/* Add first instruction to this list */
|
/* Add first instruction to this list */
|
||||||
sempty.r[0].q0 = p;
|
sempty.r[0].q0 = p;
|
||||||
if(addinst(tl, startinst, &sempty))
|
if (addinst(tl, startinst, &sempty))
|
||||||
if(++ntl >= NLIST){
|
if (++ntl >= NLIST) {
|
||||||
Overflow:
|
Overflow:
|
||||||
warning(nil, "regexp list overflow\n");
|
warning(nil, "regexp list overflow\n");
|
||||||
sel.r[0].q0 = -1;
|
sel.r[0].q0 = -1;
|
||||||
|
@ -624,54 +576,56 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Execute machine until this list is empty */
|
/* Execute machine until this list is empty */
|
||||||
for(tlp = tl; inst = tlp->inst; tlp++){ /* assignment = */
|
for (tlp = tl; inst = tlp->inst; tlp++) { /* assignment = */
|
||||||
Switchstmt:
|
Switchstmt:
|
||||||
switch(inst->type){
|
switch (inst->type) {
|
||||||
default: /* regular character */
|
default: /* regular character */
|
||||||
if(inst->type==c){
|
if (inst->type == c) {
|
||||||
Addinst:
|
Addinst:
|
||||||
if(addinst(nl, inst->u1.next, &tlp->se))
|
if (addinst(nl, inst->u1.next, &tlp->se))
|
||||||
if(++nnl >= NLIST)
|
if (++nnl >= NLIST)
|
||||||
goto Overflow;
|
goto Overflow;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LBRA:
|
case LBRA:
|
||||||
if(inst->u.subid>=0)
|
if (inst->u.subid >= 0)
|
||||||
tlp->se.r[inst->u.subid].q0 = p;
|
tlp->se.r[inst->u.subid].q0 = p;
|
||||||
inst = inst->u1.next;
|
inst = inst->u1.next;
|
||||||
goto Switchstmt;
|
goto Switchstmt;
|
||||||
case RBRA:
|
case RBRA:
|
||||||
if(inst->u.subid>=0)
|
if (inst->u.subid >= 0)
|
||||||
tlp->se.r[inst->u.subid].q1 = p;
|
tlp->se.r[inst->u.subid].q1 = p;
|
||||||
inst = inst->u1.next;
|
inst = inst->u1.next;
|
||||||
goto Switchstmt;
|
goto Switchstmt;
|
||||||
case ANY:
|
case ANY:
|
||||||
if(c!='\n')
|
if (c != '\n')
|
||||||
goto Addinst;
|
goto Addinst;
|
||||||
break;
|
break;
|
||||||
case BOL:
|
case BOL:
|
||||||
if(p==0 || (t!=nil && textreadc(t, p-1)=='\n') || (r!=nil && r[p-1]=='\n')){
|
if (
|
||||||
|
p == 0 || (t != nil && textreadc(t, p - 1) == '\n') ||
|
||||||
|
(r != nil && r[p - 1] == '\n')) {
|
||||||
Step:
|
Step:
|
||||||
inst = inst->u1.next;
|
inst = inst->u1.next;
|
||||||
goto Switchstmt;
|
goto Switchstmt;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EOL:
|
case EOL:
|
||||||
if(c == '\n')
|
if (c == '\n')
|
||||||
goto Step;
|
goto Step;
|
||||||
break;
|
break;
|
||||||
case CCLASS:
|
case CCLASS:
|
||||||
if(c>=0 && classmatch(inst->u.class, c, 0))
|
if (c >= 0 && classmatch(inst->u.class, c, 0))
|
||||||
goto Addinst;
|
goto Addinst;
|
||||||
break;
|
break;
|
||||||
case NCCLASS:
|
case NCCLASS:
|
||||||
if(c>=0 && classmatch(inst->u.class, c, 1))
|
if (c >= 0 && classmatch(inst->u.class, c, 1))
|
||||||
goto Addinst;
|
goto Addinst;
|
||||||
break;
|
break;
|
||||||
case OR:
|
case OR:
|
||||||
/* evaluate right choice later */
|
/* evaluate right choice later */
|
||||||
if(addinst(tlp, inst->u.right, &tlp->se))
|
if (addinst(tlp, inst->u.right, &tlp->se))
|
||||||
if(++ntl >= NLIST)
|
if (++ntl >= NLIST)
|
||||||
goto Overflow;
|
goto Overflow;
|
||||||
/* efficiency: advance and re-evaluate */
|
/* efficiency: advance and re-evaluate */
|
||||||
inst = inst->u1.left;
|
inst = inst->u1.left;
|
||||||
|
@ -683,25 +637,22 @@ rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Return:
|
Return:
|
||||||
*rp = sel;
|
*rp = sel;
|
||||||
return sel.r[0].q0 >= 0;
|
return sel.r[0].q0 >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void newmatch(Rangeset* sp) {
|
||||||
newmatch(Rangeset *sp)
|
if (
|
||||||
{
|
sel.r[0].q0 < 0 || sp->r[0].q0 < sel.r[0].q0 ||
|
||||||
if(sel.r[0].q0<0 || sp->r[0].q0<sel.r[0].q0 ||
|
(sp->r[0].q0 == sel.r[0].q0 && sp->r[0].q1 > sel.r[0].q1))
|
||||||
(sp->r[0].q0==sel.r[0].q0 && sp->r[0].q1>sel.r[0].q1))
|
|
||||||
sel = *sp;
|
sel = *sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int rxbexecute(Text* t, uint startp, Rangeset* rp) {
|
||||||
rxbexecute(Text *t, uint startp, Rangeset *rp)
|
|
||||||
{
|
|
||||||
int flag;
|
int flag;
|
||||||
Inst *inst;
|
Inst* inst;
|
||||||
Ilist *tlp;
|
Ilist* tlp;
|
||||||
int p;
|
int p;
|
||||||
int nnl, ntl;
|
int nnl, ntl;
|
||||||
int c;
|
int c;
|
||||||
|
@ -713,20 +664,20 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
|
||||||
wrapped = 0;
|
wrapped = 0;
|
||||||
p = startp;
|
p = startp;
|
||||||
startchar = 0;
|
startchar = 0;
|
||||||
if(bstartinst->type<OPERATOR)
|
if (bstartinst->type < OPERATOR)
|
||||||
startchar = bstartinst->type;
|
startchar = bstartinst->type;
|
||||||
list[0][0].inst = list[1][0].inst = nil;
|
list[0][0].inst = list[1][0].inst = nil;
|
||||||
sel.r[0].q0= -1;
|
sel.r[0].q0 = -1;
|
||||||
/* Execute machine once for each character, including terminal NUL */
|
/* Execute machine once for each character, including terminal NUL */
|
||||||
for(;;--p){
|
for (;; --p) {
|
||||||
doloop:
|
doloop:
|
||||||
if(p <= 0){
|
if (p <= 0) {
|
||||||
switch(wrapped++){
|
switch (wrapped++) {
|
||||||
case 0: /* let loop run one more click */
|
case 0: /* let loop run one more click */
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
case 1: /* expired; wrap to end */
|
case 1: /* expired; wrap to end */
|
||||||
if(sel.r[0].q0>=0)
|
if (sel.r[0].q0 >= 0)
|
||||||
goto Return;
|
goto Return;
|
||||||
list[0][0].inst = list[1][0].inst = nil;
|
list[0][0].inst = list[1][0].inst = nil;
|
||||||
p = t->file->b.nc;
|
p = t->file->b.nc;
|
||||||
|
@ -736,25 +687,25 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
|
||||||
goto Return;
|
goto Return;
|
||||||
}
|
}
|
||||||
c = 0;
|
c = 0;
|
||||||
}else{
|
} else {
|
||||||
if(((wrapped && p<=startp) || sel.r[0].q0>0) && nnl==0)
|
if (((wrapped && p <= startp) || sel.r[0].q0 > 0) && nnl == 0)
|
||||||
break;
|
break;
|
||||||
c = textreadc(t, p-1);
|
c = textreadc(t, p - 1);
|
||||||
}
|
}
|
||||||
/* fast check for first char */
|
/* fast check for first char */
|
||||||
if(startchar && nnl==0 && c!=startchar)
|
if (startchar && nnl == 0 && c != startchar)
|
||||||
continue;
|
continue;
|
||||||
tl = list[flag];
|
tl = list[flag];
|
||||||
nl = list[flag^=1];
|
nl = list[flag ^= 1];
|
||||||
nl->inst = nil;
|
nl->inst = nil;
|
||||||
ntl = nnl;
|
ntl = nnl;
|
||||||
nnl = 0;
|
nnl = 0;
|
||||||
if(sel.r[0].q0<0 && (!wrapped || p>startp)){
|
if (sel.r[0].q0 < 0 && (!wrapped || p > startp)) {
|
||||||
/* Add first instruction to this list */
|
/* Add first instruction to this list */
|
||||||
/* the minus is so the optimizations in addinst work */
|
/* the minus is so the optimizations in addinst work */
|
||||||
sempty.r[0].q0 = -p;
|
sempty.r[0].q0 = -p;
|
||||||
if(addinst(tl, bstartinst, &sempty))
|
if (addinst(tl, bstartinst, &sempty))
|
||||||
if(++ntl >= NLIST){
|
if (++ntl >= NLIST) {
|
||||||
Overflow:
|
Overflow:
|
||||||
warning(nil, "regexp list overflow\n");
|
warning(nil, "regexp list overflow\n");
|
||||||
sel.r[0].q0 = -1;
|
sel.r[0].q0 = -1;
|
||||||
|
@ -762,54 +713,54 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Execute machine until this list is empty */
|
/* Execute machine until this list is empty */
|
||||||
for(tlp = tl; inst = tlp->inst; tlp++){ /* assignment = */
|
for (tlp = tl; inst = tlp->inst; tlp++) { /* assignment = */
|
||||||
Switchstmt:
|
Switchstmt:
|
||||||
switch(inst->type){
|
switch (inst->type) {
|
||||||
default: /* regular character */
|
default: /* regular character */
|
||||||
if(inst->type == c){
|
if (inst->type == c) {
|
||||||
Addinst:
|
Addinst:
|
||||||
if(addinst(nl, inst->u1.next, &tlp->se))
|
if (addinst(nl, inst->u1.next, &tlp->se))
|
||||||
if(++nnl >= NLIST)
|
if (++nnl >= NLIST)
|
||||||
goto Overflow;
|
goto Overflow;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LBRA:
|
case LBRA:
|
||||||
if(inst->u.subid>=0)
|
if (inst->u.subid >= 0)
|
||||||
tlp->se.r[inst->u.subid].q0 = p;
|
tlp->se.r[inst->u.subid].q0 = p;
|
||||||
inst = inst->u1.next;
|
inst = inst->u1.next;
|
||||||
goto Switchstmt;
|
goto Switchstmt;
|
||||||
case RBRA:
|
case RBRA:
|
||||||
if(inst->u.subid >= 0)
|
if (inst->u.subid >= 0)
|
||||||
tlp->se.r[inst->u.subid].q1 = p;
|
tlp->se.r[inst->u.subid].q1 = p;
|
||||||
inst = inst->u1.next;
|
inst = inst->u1.next;
|
||||||
goto Switchstmt;
|
goto Switchstmt;
|
||||||
case ANY:
|
case ANY:
|
||||||
if(c != '\n')
|
if (c != '\n')
|
||||||
goto Addinst;
|
goto Addinst;
|
||||||
break;
|
break;
|
||||||
case BOL:
|
case BOL:
|
||||||
if(c=='\n' || p==0){
|
if (c == '\n' || p == 0) {
|
||||||
Step:
|
Step:
|
||||||
inst = inst->u1.next;
|
inst = inst->u1.next;
|
||||||
goto Switchstmt;
|
goto Switchstmt;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EOL:
|
case EOL:
|
||||||
if(p<t->file->b.nc && textreadc(t, p)=='\n')
|
if (p < t->file->b.nc && textreadc(t, p) == '\n')
|
||||||
goto Step;
|
goto Step;
|
||||||
break;
|
break;
|
||||||
case CCLASS:
|
case CCLASS:
|
||||||
if(c>0 && classmatch(inst->u.class, c, 0))
|
if (c > 0 && classmatch(inst->u.class, c, 0))
|
||||||
goto Addinst;
|
goto Addinst;
|
||||||
break;
|
break;
|
||||||
case NCCLASS:
|
case NCCLASS:
|
||||||
if(c>0 && classmatch(inst->u.class, c, 1))
|
if (c > 0 && classmatch(inst->u.class, c, 1))
|
||||||
goto Addinst;
|
goto Addinst;
|
||||||
break;
|
break;
|
||||||
case OR:
|
case OR:
|
||||||
/* evaluate right choice later */
|
/* evaluate right choice later */
|
||||||
if(addinst(tl, inst->u.right, &tlp->se))
|
if (addinst(tl, inst->u.right, &tlp->se))
|
||||||
if(++ntl >= NLIST)
|
if (++ntl >= NLIST)
|
||||||
goto Overflow;
|
goto Overflow;
|
||||||
/* efficiency: advance and re-evaluate */
|
/* efficiency: advance and re-evaluate */
|
||||||
inst = inst->u1.left;
|
inst = inst->u1.left;
|
||||||
|
@ -822,18 +773,18 @@ rxbexecute(Text *t, uint startp, Rangeset *rp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Return:
|
Return:
|
||||||
*rp = sel;
|
*rp = sel;
|
||||||
return sel.r[0].q0 >= 0;
|
return sel.r[0].q0 >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void bnewmatch(Rangeset* sp) {
|
||||||
bnewmatch(Rangeset *sp)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(sel.r[0].q0<0 || sp->r[0].q0>sel.r[0].q1 || (sp->r[0].q0==sel.r[0].q1 && sp->r[0].q1<sel.r[0].q0))
|
if (
|
||||||
for(i = 0; i<NRange; i++){ /* note the reversal; q0<=q1 */
|
sel.r[0].q0 < 0 || sp->r[0].q0 > sel.r[0].q1 ||
|
||||||
|
(sp->r[0].q0 == sel.r[0].q1 && sp->r[0].q1 < sel.r[0].q0))
|
||||||
|
for (i = 0; i < NRange; i++) { /* note the reversal; q0<=q1 */
|
||||||
sel.r[i].q0 = sp->r[i].q1;
|
sel.r[i].q0 = sp->r[i].q1;
|
||||||
sel.r[i].q1 = sp->r[i].q0;
|
sel.r[i].q1 = sp->r[i].q0;
|
||||||
}
|
}
|
||||||
|
|
114
scrl.c
114
scrl.c
|
@ -12,77 +12,73 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
static Image *scrtmp;
|
static Image* scrtmp;
|
||||||
|
|
||||||
static
|
static Rectangle scrpos(Rectangle r, uint p0, uint p1, uint tot) {
|
||||||
Rectangle
|
|
||||||
scrpos(Rectangle r, uint p0, uint p1, uint tot)
|
|
||||||
{
|
|
||||||
Rectangle q;
|
Rectangle q;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
q = r;
|
q = r;
|
||||||
h = q.max.y-q.min.y;
|
h = q.max.y - q.min.y;
|
||||||
if(tot == 0)
|
if (tot == 0)
|
||||||
return q;
|
return q;
|
||||||
if(tot > 1024*1024){
|
if (tot > 1024 * 1024) {
|
||||||
tot>>=10;
|
tot >>= 10;
|
||||||
p0>>=10;
|
p0 >>= 10;
|
||||||
p1>>=10;
|
p1 >>= 10;
|
||||||
}
|
}
|
||||||
if(p0 > 0)
|
if (p0 > 0)
|
||||||
q.min.y += h*p0/tot;
|
q.min.y += h * p0 / tot;
|
||||||
if(p1 < tot)
|
if (p1 < tot)
|
||||||
q.max.y -= h*(tot-p1)/tot;
|
q.max.y -= h * (tot - p1) / tot;
|
||||||
if(q.max.y < q.min.y+2){
|
if (q.max.y < q.min.y + 2) {
|
||||||
if(q.min.y+2 <= r.max.y)
|
if (q.min.y + 2 <= r.max.y)
|
||||||
q.max.y = q.min.y+2;
|
q.max.y = q.min.y + 2;
|
||||||
else
|
else
|
||||||
q.min.y = q.max.y-2;
|
q.min.y = q.max.y - 2;
|
||||||
}
|
}
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void scrlresize(void) {
|
||||||
scrlresize(void)
|
|
||||||
{
|
|
||||||
freeimage(scrtmp);
|
freeimage(scrtmp);
|
||||||
scrtmp = allocimage(display, Rect(0, 0, 32, screen->r.max.y), screen->chan, 0, DNofill);
|
scrtmp = allocimage(
|
||||||
if(scrtmp == nil)
|
display,
|
||||||
|
Rect(0, 0, 32, screen->r.max.y),
|
||||||
|
screen->chan,
|
||||||
|
0,
|
||||||
|
DNofill);
|
||||||
|
if (scrtmp == nil)
|
||||||
error("scroll alloc");
|
error("scroll alloc");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void textscrdraw(Text* t) {
|
||||||
textscrdraw(Text *t)
|
|
||||||
{
|
|
||||||
Rectangle r, r1, r2;
|
Rectangle r, r1, r2;
|
||||||
Image *b;
|
Image* b;
|
||||||
|
|
||||||
if(t->w==nil || t!=&t->w->body)
|
if (t->w == nil || t != &t->w->body)
|
||||||
return;
|
return;
|
||||||
if(scrtmp == nil)
|
if (scrtmp == nil)
|
||||||
scrlresize();
|
scrlresize();
|
||||||
r = t->scrollr;
|
r = t->scrollr;
|
||||||
b = scrtmp;
|
b = scrtmp;
|
||||||
r1 = r;
|
r1 = r;
|
||||||
r1.min.x = 0;
|
r1.min.x = 0;
|
||||||
r1.max.x = Dx(r);
|
r1.max.x = Dx(r);
|
||||||
r2 = scrpos(r1, t->org, t->org+t->fr.nchars, t->file->b.nc);
|
r2 = scrpos(r1, t->org, t->org + t->fr.nchars, t->file->b.nc);
|
||||||
if(!eqrect(r2, t->lastsr)){
|
if (!eqrect(r2, t->lastsr)) {
|
||||||
t->lastsr = r2;
|
t->lastsr = r2;
|
||||||
draw(b, r1, t->fr.cols[BORD], nil, ZP);
|
draw(b, r1, t->fr.cols[BORD], nil, ZP);
|
||||||
draw(b, r2, t->fr.cols[BACK], nil, ZP);
|
draw(b, r2, t->fr.cols[BACK], nil, ZP);
|
||||||
r2.min.x = r2.max.x-1;
|
r2.min.x = r2.max.x - 1;
|
||||||
draw(b, r2, t->fr.cols[BORD], nil, ZP);
|
draw(b, r2, t->fr.cols[BORD], nil, ZP);
|
||||||
draw(t->fr.b, r, b, nil, Pt(0, r1.min.y));
|
draw(t->fr.b, r, b, nil, Pt(0, r1.min.y));
|
||||||
/*flushimage(display, 1); // BUG? */
|
/*flushimage(display, 1); // BUG? */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void scrsleep(uint dt) {
|
||||||
scrsleep(uint dt)
|
Timer* timer;
|
||||||
{
|
|
||||||
Timer *timer;
|
|
||||||
static Alt alts[3];
|
static Alt alts[3];
|
||||||
|
|
||||||
timer = timerstart(dt);
|
timer = timerstart(dt);
|
||||||
|
@ -93,8 +89,8 @@ scrsleep(uint dt)
|
||||||
alts[1].v = &mousectl->m;
|
alts[1].v = &mousectl->m;
|
||||||
alts[1].op = CHANRCV;
|
alts[1].op = CHANRCV;
|
||||||
alts[2].op = CHANEND;
|
alts[2].op = CHANEND;
|
||||||
for(;;)
|
for (;;)
|
||||||
switch(alt(alts)){
|
switch (alt(alts)) {
|
||||||
case 0:
|
case 0:
|
||||||
timerstop(timer);
|
timerstop(timer);
|
||||||
return;
|
return;
|
||||||
|
@ -104,56 +100,54 @@ scrsleep(uint dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void textscroll(Text* t, int but) {
|
||||||
textscroll(Text *t, int but)
|
|
||||||
{
|
|
||||||
uint p0, oldp0;
|
uint p0, oldp0;
|
||||||
Rectangle s;
|
Rectangle s;
|
||||||
int x, y, my, h, first;
|
int x, y, my, h, first;
|
||||||
|
|
||||||
s = insetrect(t->scrollr, 1);
|
s = insetrect(t->scrollr, 1);
|
||||||
h = s.max.y-s.min.y;
|
h = s.max.y - s.min.y;
|
||||||
x = (s.min.x+s.max.x)/2;
|
x = (s.min.x + s.max.x) / 2;
|
||||||
oldp0 = ~0;
|
oldp0 = ~0;
|
||||||
first = TRUE;
|
first = TRUE;
|
||||||
do{
|
do {
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
my = mouse->xy.y;
|
my = mouse->xy.y;
|
||||||
if(my < s.min.y)
|
if (my < s.min.y)
|
||||||
my = s.min.y;
|
my = s.min.y;
|
||||||
if(my >= s.max.y)
|
if (my >= s.max.y)
|
||||||
my = s.max.y;
|
my = s.max.y;
|
||||||
if(!eqpt(mouse->xy, Pt(x, my))){
|
if (!eqpt(mouse->xy, Pt(x, my))) {
|
||||||
moveto(mousectl, Pt(x, my));
|
moveto(mousectl, Pt(x, my));
|
||||||
readmouse(mousectl); /* absorb event generated by moveto() */
|
readmouse(mousectl); /* absorb event generated by moveto() */
|
||||||
}
|
}
|
||||||
if(but == 2){
|
if (but == 2) {
|
||||||
y = my;
|
y = my;
|
||||||
p0 = (vlong)t->file->b.nc*(y-s.min.y)/h;
|
p0 = (vlong)t->file->b.nc * (y - s.min.y) / h;
|
||||||
if(p0 >= t->q1)
|
if (p0 >= t->q1)
|
||||||
p0 = textbacknl(t, p0, 2);
|
p0 = textbacknl(t, p0, 2);
|
||||||
if(oldp0 != p0)
|
if (oldp0 != p0)
|
||||||
textsetorigin(t, p0, FALSE);
|
textsetorigin(t, p0, FALSE);
|
||||||
oldp0 = p0;
|
oldp0 = p0;
|
||||||
readmouse(mousectl);
|
readmouse(mousectl);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(but == 1)
|
if (but == 1)
|
||||||
p0 = textbacknl(t, t->org, (my-s.min.y)/t->fr.font->height);
|
p0 = textbacknl(t, t->org, (my - s.min.y) / t->fr.font->height);
|
||||||
else
|
else
|
||||||
p0 = t->org+frcharofpt(&t->fr, Pt(s.max.x, my));
|
p0 = t->org + frcharofpt(&t->fr, Pt(s.max.x, my));
|
||||||
if(oldp0 != p0)
|
if (oldp0 != p0)
|
||||||
textsetorigin(t, p0, TRUE);
|
textsetorigin(t, p0, TRUE);
|
||||||
oldp0 = p0;
|
oldp0 = p0;
|
||||||
/* debounce */
|
/* debounce */
|
||||||
if(first){
|
if (first) {
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
sleep(200);
|
sleep(200);
|
||||||
nbrecv(mousectl->c, &mousectl->m);
|
nbrecv(mousectl->c, &mousectl->m);
|
||||||
first = FALSE;
|
first = FALSE;
|
||||||
}
|
}
|
||||||
scrsleep(80);
|
scrsleep(80);
|
||||||
}while(mouse->buttons & (1<<(but-1)));
|
} while (mouse->buttons & (1 << (but - 1)));
|
||||||
while(mouse->buttons)
|
while (mouse->buttons)
|
||||||
readmouse(mousectl);
|
readmouse(mousectl);
|
||||||
}
|
}
|
||||||
|
|
69
time.c
69
time.c
|
@ -13,32 +13,18 @@
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
static Channel* ctimer; /* chan(Timer*)[100] */
|
static Channel* ctimer; /* chan(Timer*)[100] */
|
||||||
static Timer *timer;
|
static Timer* timer;
|
||||||
|
|
||||||
static
|
static uint msec(void) { return nsec() / 1000000; }
|
||||||
uint
|
|
||||||
msec(void)
|
|
||||||
{
|
|
||||||
return nsec()/1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void timerstop(Timer* t) {
|
||||||
timerstop(Timer *t)
|
|
||||||
{
|
|
||||||
t->next = timer;
|
t->next = timer;
|
||||||
timer = t;
|
timer = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void timercancel(Timer* t) { t->cancel = TRUE; }
|
||||||
timercancel(Timer *t)
|
|
||||||
{
|
|
||||||
t->cancel = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static void timerproc(void* v) {
|
||||||
void
|
|
||||||
timerproc(void *v)
|
|
||||||
{
|
|
||||||
int i, nt, na, dt, del;
|
int i, nt, na, dt, del;
|
||||||
Timer **t, *x;
|
Timer **t, *x;
|
||||||
uint old, new;
|
uint old, new;
|
||||||
|
@ -50,68 +36,65 @@ timerproc(void *v)
|
||||||
na = 0;
|
na = 0;
|
||||||
nt = 0;
|
nt = 0;
|
||||||
old = msec();
|
old = msec();
|
||||||
for(;;){
|
for (;;) {
|
||||||
sleep(10); /* longer sleeps here delay recv on ctimer, but 10ms should not be noticeable */
|
sleep(10); /* longer sleeps here delay recv on ctimer, but 10ms should not
|
||||||
|
be noticeable */
|
||||||
new = msec();
|
new = msec();
|
||||||
dt = new-old;
|
dt = new - old;
|
||||||
old = new;
|
old = new;
|
||||||
if(dt < 0) /* timer wrapped; go around, losing a tick */
|
if (dt < 0) /* timer wrapped; go around, losing a tick */
|
||||||
continue;
|
continue;
|
||||||
for(i=0; i<nt; i++){
|
for (i = 0; i < nt; i++) {
|
||||||
x = t[i];
|
x = t[i];
|
||||||
x->dt -= dt;
|
x->dt -= dt;
|
||||||
del = FALSE;
|
del = FALSE;
|
||||||
if(x->cancel){
|
if (x->cancel) {
|
||||||
timerstop(x);
|
timerstop(x);
|
||||||
del = TRUE;
|
del = TRUE;
|
||||||
}else if(x->dt <= 0){
|
} else if (x->dt <= 0) {
|
||||||
/*
|
/*
|
||||||
* avoid possible deadlock if client is
|
* avoid possible deadlock if client is
|
||||||
* now sending on ctimer
|
* now sending on ctimer
|
||||||
*/
|
*/
|
||||||
if(nbsendul(x->c, 0) > 0)
|
if (nbsendul(x->c, 0) > 0)
|
||||||
del = TRUE;
|
del = TRUE;
|
||||||
}
|
}
|
||||||
if(del){
|
if (del) {
|
||||||
memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]);
|
memmove(&t[i], &t[i + 1], (nt - i - 1) * sizeof t[0]);
|
||||||
--nt;
|
--nt;
|
||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(nt == 0){
|
if (nt == 0) {
|
||||||
x = recvp(ctimer);
|
x = recvp(ctimer);
|
||||||
gotit:
|
gotit:
|
||||||
if(nt == na){
|
if (nt == na) {
|
||||||
na += 10;
|
na += 10;
|
||||||
t = realloc(t, na*sizeof(Timer*));
|
t = realloc(t, na * sizeof(Timer*));
|
||||||
if(t == nil)
|
if (t == nil)
|
||||||
error("timer realloc failed");
|
error("timer realloc failed");
|
||||||
}
|
}
|
||||||
t[nt++] = x;
|
t[nt++] = x;
|
||||||
old = msec();
|
old = msec();
|
||||||
}
|
}
|
||||||
if(nbrecv(ctimer, &x) > 0)
|
if (nbrecv(ctimer, &x) > 0)
|
||||||
goto gotit;
|
goto gotit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void timerinit(void) {
|
||||||
timerinit(void)
|
|
||||||
{
|
|
||||||
ctimer = chancreate(sizeof(Timer*), 100);
|
ctimer = chancreate(sizeof(Timer*), 100);
|
||||||
chansetname(ctimer, "ctimer");
|
chansetname(ctimer, "ctimer");
|
||||||
proccreate(timerproc, nil, STACK);
|
proccreate(timerproc, nil, STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer*
|
Timer* timerstart(int dt) {
|
||||||
timerstart(int dt)
|
Timer* t;
|
||||||
{
|
|
||||||
Timer *t;
|
|
||||||
|
|
||||||
t = timer;
|
t = timer;
|
||||||
if(t)
|
if (t)
|
||||||
timer = timer->next;
|
timer = timer->next;
|
||||||
else{
|
else {
|
||||||
t = emalloc(sizeof(Timer));
|
t = emalloc(sizeof(Timer));
|
||||||
t->c = chancreate(sizeof(int), 0);
|
t->c = chancreate(sizeof(int), 0);
|
||||||
chansetname(t->c, "tc%p", t->c);
|
chansetname(t->c, "tc%p", t->c);
|
||||||
|
|
305
util.c
305
util.c
|
@ -13,11 +13,9 @@
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
static Point prevmouse;
|
static Point prevmouse;
|
||||||
static Window *mousew;
|
static Window* mousew;
|
||||||
|
|
||||||
Range
|
Range range(int q0, int q1) {
|
||||||
range(int q0, int q1)
|
|
||||||
{
|
|
||||||
Range r;
|
Range r;
|
||||||
|
|
||||||
r.q0 = q0;
|
r.q0 = q0;
|
||||||
|
@ -25,9 +23,7 @@ range(int q0, int q1)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runestr
|
Runestr runestr(Rune* r, uint n) {
|
||||||
runestr(Rune *r, uint n)
|
|
||||||
{
|
|
||||||
Runestr rs;
|
Runestr rs;
|
||||||
|
|
||||||
rs.r = r;
|
rs.r = r;
|
||||||
|
@ -35,11 +31,9 @@ runestr(Rune *r, uint n)
|
||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void cvttorunes(char* p, int n, Rune* r, int* nb, int* nr, int* nulls) {
|
||||||
cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
|
uchar* q;
|
||||||
{
|
Rune* s;
|
||||||
uchar *q;
|
|
||||||
Rune *s;
|
|
||||||
int j, w;
|
int j, w;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -51,80 +45,74 @@ cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
|
||||||
*/
|
*/
|
||||||
q = (uchar*)p;
|
q = (uchar*)p;
|
||||||
s = r;
|
s = r;
|
||||||
for(j=0; j<n; j+=w){
|
for (j = 0; j < n; j += w) {
|
||||||
if(*q < Runeself){
|
if (*q < Runeself) {
|
||||||
w = 1;
|
w = 1;
|
||||||
*s = *q++;
|
*s = *q++;
|
||||||
}else{
|
} else {
|
||||||
w = chartorune(s, (char*)q);
|
w = chartorune(s, (char*)q);
|
||||||
q += w;
|
q += w;
|
||||||
}
|
}
|
||||||
if(*s)
|
if (*s)
|
||||||
s++;
|
s++;
|
||||||
else if(nulls)
|
else if (nulls)
|
||||||
*nulls = TRUE;
|
*nulls = TRUE;
|
||||||
}
|
}
|
||||||
*nb = (char*)q-p;
|
*nb = (char*)q - p;
|
||||||
*nr = s-r;
|
*nr = s - r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void error(char* s) {
|
||||||
error(char *s)
|
|
||||||
{
|
|
||||||
fprint(2, "acme: %s: %r\n", s);
|
fprint(2, "acme: %s: %r\n", s);
|
||||||
threadexitsall(nil);
|
threadexitsall(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
Window*
|
Window* errorwin1(Rune* dir, int ndir, Rune** incl, int nincl) {
|
||||||
errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
|
Window* w;
|
||||||
{
|
Rune* r;
|
||||||
Window *w;
|
|
||||||
Rune *r;
|
|
||||||
int i, n;
|
int i, n;
|
||||||
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
|
static Rune Lpluserrors[] = {'+', 'E', 'r', 'r', 'o', 'r', 's', 0};
|
||||||
|
|
||||||
r = runemalloc(ndir+8);
|
r = runemalloc(ndir + 8);
|
||||||
if((n = ndir) != 0){
|
if ((n = ndir) != 0) {
|
||||||
runemove(r, dir, ndir);
|
runemove(r, dir, ndir);
|
||||||
r[n++] = L'/';
|
r[n++] = L'/';
|
||||||
}
|
}
|
||||||
runemove(r+n, Lpluserrors, 7);
|
runemove(r + n, Lpluserrors, 7);
|
||||||
n += 7;
|
n += 7;
|
||||||
w = lookfile(r, n);
|
w = lookfile(r, n);
|
||||||
if(w == nil){
|
if (w == nil) {
|
||||||
if(row.ncol == 0)
|
if (row.ncol == 0)
|
||||||
if(rowadd(&row, nil, -1) == nil)
|
if (rowadd(&row, nil, -1) == nil)
|
||||||
error("can't create column to make error window");
|
error("can't create column to make error window");
|
||||||
w = coladd(row.col[row.ncol-1], nil, nil, -1);
|
w = coladd(row.col[row.ncol - 1], nil, nil, -1);
|
||||||
w->filemenu = FALSE;
|
w->filemenu = FALSE;
|
||||||
winsetname(w, r, n);
|
winsetname(w, r, n);
|
||||||
xfidlog(w, "new");
|
xfidlog(w, "new");
|
||||||
}
|
}
|
||||||
free(r);
|
free(r);
|
||||||
for(i=nincl; --i>=0; ){
|
for (i = nincl; --i >= 0;) {
|
||||||
n = runestrlen(incl[i]);
|
n = runestrlen(incl[i]);
|
||||||
r = runemalloc(n);
|
r = runemalloc(n);
|
||||||
runemove(r, incl[i], n);
|
runemove(r, incl[i], n);
|
||||||
winaddincl(w, r, n);
|
winaddincl(w, r, n);
|
||||||
}
|
}
|
||||||
for(i=0; i<NINDENT; i++)
|
for (i = 0; i < NINDENT; i++)
|
||||||
w->indent[i] = globalindent[i];
|
w->indent[i] = globalindent[i];
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make new window, if necessary; return with it locked */
|
/* make new window, if necessary; return with it locked */
|
||||||
Window*
|
Window* errorwin(Mntdir* md, int owner) {
|
||||||
errorwin(Mntdir *md, int owner)
|
Window* w;
|
||||||
{
|
|
||||||
Window *w;
|
|
||||||
|
|
||||||
for(;;){
|
for (;;) {
|
||||||
if(md == nil)
|
if (md == nil)
|
||||||
w = errorwin1(nil, 0, nil, 0);
|
w = errorwin1(nil, 0, nil, 0);
|
||||||
else
|
else
|
||||||
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
|
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
|
||||||
winlock(w, owner);
|
winlock(w, owner);
|
||||||
if(w->col != nil)
|
if (w->col != nil)
|
||||||
break;
|
break;
|
||||||
/* window was deleted too fast */
|
/* window was deleted too fast */
|
||||||
winunlock(w);
|
winunlock(w);
|
||||||
|
@ -137,37 +125,35 @@ errorwin(Mntdir *md, int owner)
|
||||||
* It will be unlocked and returned window
|
* It will be unlocked and returned window
|
||||||
* will be locked in its place.
|
* will be locked in its place.
|
||||||
*/
|
*/
|
||||||
Window*
|
Window* errorwinforwin(Window* w) {
|
||||||
errorwinforwin(Window *w)
|
|
||||||
{
|
|
||||||
int i, n, nincl, owner;
|
int i, n, nincl, owner;
|
||||||
Rune **incl;
|
Rune** incl;
|
||||||
Runestr dir;
|
Runestr dir;
|
||||||
Text *t;
|
Text* t;
|
||||||
|
|
||||||
t = &w->body;
|
t = &w->body;
|
||||||
dir = dirname(t, nil, 0);
|
dir = dirname(t, nil, 0);
|
||||||
if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */
|
if (dir.nr == 1 && dir.r[0] == '.') { /* sigh */
|
||||||
free(dir.r);
|
free(dir.r);
|
||||||
dir.r = nil;
|
dir.r = nil;
|
||||||
dir.nr = 0;
|
dir.nr = 0;
|
||||||
}
|
}
|
||||||
incl = nil;
|
incl = nil;
|
||||||
nincl = w->nincl;
|
nincl = w->nincl;
|
||||||
if(nincl > 0){
|
if (nincl > 0) {
|
||||||
incl = emalloc(nincl*sizeof(Rune*));
|
incl = emalloc(nincl * sizeof(Rune*));
|
||||||
for(i=0; i<nincl; i++){
|
for (i = 0; i < nincl; i++) {
|
||||||
n = runestrlen(w->incl[i]);
|
n = runestrlen(w->incl[i]);
|
||||||
incl[i] = runemalloc(n+1);
|
incl[i] = runemalloc(n + 1);
|
||||||
runemove(incl[i], w->incl[i], n);
|
runemove(incl[i], w->incl[i], n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
owner = w->owner;
|
owner = w->owner;
|
||||||
winunlock(w);
|
winunlock(w);
|
||||||
for(;;){
|
for (;;) {
|
||||||
w = errorwin1(dir.r, dir.nr, incl, nincl);
|
w = errorwin1(dir.r, dir.nr, incl, nincl);
|
||||||
winlock(w, owner);
|
winlock(w, owner);
|
||||||
if(w->col != nil)
|
if (w->col != nil)
|
||||||
break;
|
break;
|
||||||
/* window deleted too fast */
|
/* window deleted too fast */
|
||||||
winunlock(w);
|
winunlock(w);
|
||||||
|
@ -177,22 +163,19 @@ errorwinforwin(Window *w)
|
||||||
|
|
||||||
typedef struct Warning Warning;
|
typedef struct Warning Warning;
|
||||||
|
|
||||||
struct Warning{
|
struct Warning {
|
||||||
Mntdir *md;
|
Mntdir* md;
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Warning *next;
|
Warning* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Warning *warnings;
|
static Warning* warnings;
|
||||||
|
|
||||||
static
|
static void addwarningtext(Mntdir* md, Rune* r, int nr) {
|
||||||
void
|
Warning* warn;
|
||||||
addwarningtext(Mntdir *md, Rune *r, int nr)
|
|
||||||
{
|
|
||||||
Warning *warn;
|
|
||||||
|
|
||||||
for(warn = warnings; warn; warn=warn->next){
|
for (warn = warnings; warn; warn = warn->next) {
|
||||||
if(warn->md == md){
|
if (warn->md == md) {
|
||||||
bufinsert(&warn->buf, warn->buf.nc, r, nr);
|
bufinsert(&warn->buf, warn->buf.nc, r, nr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -200,7 +183,7 @@ addwarningtext(Mntdir *md, Rune *r, int nr)
|
||||||
warn = emalloc(sizeof(Warning));
|
warn = emalloc(sizeof(Warning));
|
||||||
warn->next = warnings;
|
warn->next = warnings;
|
||||||
warn->md = md;
|
warn->md = md;
|
||||||
if(md)
|
if (md)
|
||||||
fsysincid(md);
|
fsysincid(md);
|
||||||
warnings = warn;
|
warnings = warn;
|
||||||
bufinsert(&warn->buf, 0, r, nr);
|
bufinsert(&warn->buf, 0, r, nr);
|
||||||
|
@ -208,20 +191,18 @@ addwarningtext(Mntdir *md, Rune *r, int nr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called while row is locked */
|
/* called while row is locked */
|
||||||
void
|
void flushwarnings(void) {
|
||||||
flushwarnings(void)
|
|
||||||
{
|
|
||||||
Warning *warn, *next;
|
Warning *warn, *next;
|
||||||
Window *w;
|
Window* w;
|
||||||
Text *t;
|
Text* t;
|
||||||
int owner, nr, q0, n;
|
int owner, nr, q0, n;
|
||||||
Rune *r;
|
Rune* r;
|
||||||
|
|
||||||
for(warn=warnings; warn; warn=next) {
|
for (warn = warnings; warn; warn = next) {
|
||||||
w = errorwin(warn->md, 'E');
|
w = errorwin(warn->md, 'E');
|
||||||
t = &w->body;
|
t = &w->body;
|
||||||
owner = w->owner;
|
owner = w->owner;
|
||||||
if(owner == 0)
|
if (owner == 0)
|
||||||
w->owner = 'E';
|
w->owner = 'E';
|
||||||
wincommit(w, t);
|
wincommit(w, t);
|
||||||
/*
|
/*
|
||||||
|
@ -234,9 +215,9 @@ flushwarnings(void)
|
||||||
*/
|
*/
|
||||||
r = fbufalloc();
|
r = fbufalloc();
|
||||||
q0 = t->file->b.nc;
|
q0 = t->file->b.nc;
|
||||||
for(n = 0; n < warn->buf.nc; n += nr){
|
for (n = 0; n < warn->buf.nc; n += nr) {
|
||||||
nr = warn->buf.nc - n;
|
nr = warn->buf.nc - n;
|
||||||
if(nr > RBUFSIZE)
|
if (nr > RBUFSIZE)
|
||||||
nr = RBUFSIZE;
|
nr = RBUFSIZE;
|
||||||
bufread(&warn->buf, n, r, nr);
|
bufread(&warn->buf, n, r, nr);
|
||||||
textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
|
textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
|
||||||
|
@ -250,117 +231,95 @@ flushwarnings(void)
|
||||||
winunlock(w);
|
winunlock(w);
|
||||||
bufclose(&warn->buf);
|
bufclose(&warn->buf);
|
||||||
next = warn->next;
|
next = warn->next;
|
||||||
if(warn->md)
|
if (warn->md)
|
||||||
fsysdelid(warn->md);
|
fsysdelid(warn->md);
|
||||||
free(warn);
|
free(warn);
|
||||||
}
|
}
|
||||||
warnings = nil;
|
warnings = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void warning(Mntdir* md, char* s, ...) {
|
||||||
warning(Mntdir *md, char *s, ...)
|
Rune* r;
|
||||||
{
|
|
||||||
Rune *r;
|
|
||||||
va_list arg;
|
va_list arg;
|
||||||
|
|
||||||
va_start(arg, s);
|
va_start(arg, s);
|
||||||
r = runevsmprint(s, arg);
|
r = runevsmprint(s, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
if(r == nil)
|
if (r == nil)
|
||||||
error("runevsmprint failed");
|
error("runevsmprint failed");
|
||||||
addwarningtext(md, r, runestrlen(r));
|
addwarningtext(md, r, runestrlen(r));
|
||||||
free(r);
|
free(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int runeeq(Rune* s1, uint n1, Rune* s2, uint n2) {
|
||||||
runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
|
if (n1 != n2)
|
||||||
{
|
|
||||||
if(n1 != n2)
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
|
return memcmp(s1, s2, n1 * sizeof(Rune)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint min(uint a, uint b) {
|
||||||
min(uint a, uint b)
|
if (a < b)
|
||||||
{
|
|
||||||
if(a < b)
|
|
||||||
return a;
|
return a;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint max(uint a, uint b) {
|
||||||
max(uint a, uint b)
|
if (a > b)
|
||||||
{
|
|
||||||
if(a > b)
|
|
||||||
return a;
|
return a;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* runetobyte(Rune* r, int n) {
|
||||||
runetobyte(Rune *r, int n)
|
char* s;
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
if(r == nil)
|
if (r == nil)
|
||||||
return nil;
|
return nil;
|
||||||
s = emalloc(n*UTFmax+1);
|
s = emalloc(n * UTFmax + 1);
|
||||||
setmalloctag(s, getcallerpc(&r));
|
setmalloctag(s, getcallerpc(&r));
|
||||||
snprint(s, n*UTFmax+1, "%.*S", n, r);
|
snprint(s, n * UTFmax + 1, "%.*S", n, r);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rune*
|
Rune* bytetorune(char* s, int* ip) {
|
||||||
bytetorune(char *s, int *ip)
|
Rune* r;
|
||||||
{
|
|
||||||
Rune *r;
|
|
||||||
int nb, nr;
|
int nb, nr;
|
||||||
|
|
||||||
nb = strlen(s);
|
nb = strlen(s);
|
||||||
r = runemalloc(nb+1);
|
r = runemalloc(nb + 1);
|
||||||
cvttorunes(s, nb, r, &nb, &nr, nil);
|
cvttorunes(s, nb, r, &nb, &nr, nil);
|
||||||
r[nr] = '\0';
|
r[nr] = '\0';
|
||||||
*ip = nr;
|
*ip = nr;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int isalnum(Rune c) {
|
||||||
isalnum(Rune c)
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Hard to get absolutely right. Use what we know about ASCII
|
* Hard to get absolutely right. Use what we know about ASCII
|
||||||
* and assume anything above the Latin control characters is
|
* and assume anything above the Latin control characters is
|
||||||
* potentially an alphanumeric.
|
* potentially an alphanumeric.
|
||||||
*/
|
*/
|
||||||
if(c <= ' ')
|
if (c <= ' ')
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if(0x7F<=c && c<=0xA0)
|
if (0x7F <= c && c <= 0xA0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
|
if (utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int rgetc(void* v, uint n) { return ((Rune*)v)[n]; }
|
||||||
rgetc(void *v, uint n)
|
|
||||||
{
|
|
||||||
return ((Rune*)v)[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int tgetc(void* a, uint n) {
|
||||||
tgetc(void *a, uint n)
|
Text* t;
|
||||||
{
|
|
||||||
Text *t;
|
|
||||||
|
|
||||||
t = a;
|
t = a;
|
||||||
if(n >= t->file->b.nc)
|
if (n >= t->file->b.nc)
|
||||||
return 0;
|
return 0;
|
||||||
return textreadc(t, n);
|
return textreadc(t, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rune*
|
Rune* skipbl(Rune* r, int n, int* np) {
|
||||||
skipbl(Rune *r, int n, int *np)
|
while (n > 0 && (*r == ' ' || *r == '\t' || *r == '\n')) {
|
||||||
{
|
|
||||||
while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){
|
|
||||||
--n;
|
--n;
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
|
@ -368,10 +327,8 @@ skipbl(Rune *r, int n, int *np)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rune*
|
Rune* findbl(Rune* r, int n, int* np) {
|
||||||
findbl(Rune *r, int n, int *np)
|
while (n > 0 && *r != ' ' && *r != '\t' && *r != '\n') {
|
||||||
{
|
|
||||||
while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
|
|
||||||
--n;
|
--n;
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
|
@ -379,20 +336,16 @@ findbl(Rune *r, int n, int *np)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void savemouse(Window* w) {
|
||||||
savemouse(Window *w)
|
|
||||||
{
|
|
||||||
prevmouse = mouse->xy;
|
prevmouse = mouse->xy;
|
||||||
mousew = w;
|
mousew = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int restoremouse(Window* w) {
|
||||||
restoremouse(Window *w)
|
|
||||||
{
|
|
||||||
int did;
|
int did;
|
||||||
|
|
||||||
did = 0;
|
did = 0;
|
||||||
if(mousew!=nil && mousew==w) {
|
if (mousew != nil && mousew == w) {
|
||||||
moveto(mousectl, prevmouse);
|
moveto(mousectl, prevmouse);
|
||||||
did = 1;
|
did = 1;
|
||||||
}
|
}
|
||||||
|
@ -400,42 +353,32 @@ restoremouse(Window *w)
|
||||||
return did;
|
return did;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void clearmouse() { mousew = nil; }
|
||||||
clearmouse()
|
|
||||||
{
|
|
||||||
mousew = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
char* estrdup(char* s) {
|
||||||
estrdup(char *s)
|
char* t;
|
||||||
{
|
|
||||||
char *t;
|
|
||||||
|
|
||||||
t = strdup(s);
|
t = strdup(s);
|
||||||
if(t == nil)
|
if (t == nil)
|
||||||
error("strdup failed");
|
error("strdup failed");
|
||||||
setmalloctag(t, getcallerpc(&s));
|
setmalloctag(t, getcallerpc(&s));
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void* emalloc(uint n) {
|
||||||
emalloc(uint n)
|
void* p;
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
p = malloc(n);
|
p = malloc(n);
|
||||||
if(p == nil)
|
if (p == nil)
|
||||||
error("malloc failed");
|
error("malloc failed");
|
||||||
setmalloctag(p, getcallerpc(&n));
|
setmalloctag(p, getcallerpc(&n));
|
||||||
memset(p, 0, n);
|
memset(p, 0, n);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void* erealloc(void* p, uint n) {
|
||||||
erealloc(void *p, uint n)
|
|
||||||
{
|
|
||||||
p = realloc(p, n);
|
p = realloc(p, n);
|
||||||
if(p == nil)
|
if (p == nil)
|
||||||
error("realloc failed");
|
error("realloc failed");
|
||||||
setmalloctag(p, getcallerpc(&n));
|
setmalloctag(p, getcallerpc(&n));
|
||||||
return p;
|
return p;
|
||||||
|
@ -444,53 +387,53 @@ erealloc(void *p, uint n)
|
||||||
/*
|
/*
|
||||||
* Heuristic city.
|
* Heuristic city.
|
||||||
*/
|
*/
|
||||||
Window*
|
Window* makenewwindow(Text* t) {
|
||||||
makenewwindow(Text *t)
|
Column* c;
|
||||||
{
|
|
||||||
Column *c;
|
|
||||||
Window *w, *bigw, *emptyw;
|
Window *w, *bigw, *emptyw;
|
||||||
Text *emptyb;
|
Text* emptyb;
|
||||||
int i, y, el;
|
int i, y, el;
|
||||||
|
|
||||||
if(activecol)
|
if (activecol)
|
||||||
c = activecol;
|
c = activecol;
|
||||||
else if(seltext && seltext->col)
|
else if (seltext && seltext->col)
|
||||||
c = seltext->col;
|
c = seltext->col;
|
||||||
else if(t && t->col)
|
else if (t && t->col)
|
||||||
c = t->col;
|
c = t->col;
|
||||||
else{
|
else {
|
||||||
if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
|
if (row.ncol == 0 && rowadd(&row, nil, -1) == nil)
|
||||||
error("can't make column");
|
error("can't make column");
|
||||||
c = row.col[row.ncol-1];
|
c = row.col[row.ncol - 1];
|
||||||
}
|
}
|
||||||
activecol = c;
|
activecol = c;
|
||||||
if(t==nil || t->w==nil || c->nw==0)
|
if (t == nil || t->w == nil || c->nw == 0)
|
||||||
return coladd(c, nil, nil, -1);
|
return coladd(c, nil, nil, -1);
|
||||||
|
|
||||||
/* find biggest window and biggest blank spot */
|
/* find biggest window and biggest blank spot */
|
||||||
emptyw = c->w[0];
|
emptyw = c->w[0];
|
||||||
bigw = emptyw;
|
bigw = emptyw;
|
||||||
for(i=1; i<c->nw; i++){
|
for (i = 1; i < c->nw; i++) {
|
||||||
w = c->w[i];
|
w = c->w[i];
|
||||||
/* use >= to choose one near bottom of screen */
|
/* use >= to choose one near bottom of screen */
|
||||||
if(w->body.fr.maxlines >= bigw->body.fr.maxlines)
|
if (w->body.fr.maxlines >= bigw->body.fr.maxlines)
|
||||||
bigw = w;
|
bigw = w;
|
||||||
if(w->body.fr.maxlines-w->body.fr.nlines >= emptyw->body.fr.maxlines-emptyw->body.fr.nlines)
|
if (
|
||||||
|
w->body.fr.maxlines - w->body.fr.nlines >=
|
||||||
|
emptyw->body.fr.maxlines - emptyw->body.fr.nlines)
|
||||||
emptyw = w;
|
emptyw = w;
|
||||||
}
|
}
|
||||||
emptyb = &emptyw->body;
|
emptyb = &emptyw->body;
|
||||||
el = emptyb->fr.maxlines-emptyb->fr.nlines;
|
el = emptyb->fr.maxlines - emptyb->fr.nlines;
|
||||||
/* if empty space is big, use it */
|
/* if empty space is big, use it */
|
||||||
if(el>15 || (el>3 && el>(bigw->body.fr.maxlines-1)/2))
|
if (el > 15 || (el > 3 && el > (bigw->body.fr.maxlines - 1) / 2))
|
||||||
y = emptyb->fr.r.min.y+emptyb->fr.nlines*font->height;
|
y = emptyb->fr.r.min.y + emptyb->fr.nlines * font->height;
|
||||||
else{
|
else {
|
||||||
/* if this window is in column and isn't much smaller, split it */
|
/* if this window is in column and isn't much smaller, split it */
|
||||||
if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3)
|
if (t->col == c && Dy(t->w->r) > 2 * Dy(bigw->r) / 3)
|
||||||
bigw = t->w;
|
bigw = t->w;
|
||||||
y = (bigw->r.min.y + bigw->r.max.y)/2;
|
y = (bigw->r.min.y + bigw->r.max.y) / 2;
|
||||||
}
|
}
|
||||||
w = coladd(c, nil, nil, y);
|
w = coladd(c, nil, nil, y);
|
||||||
if(w->body.fr.maxlines < 2)
|
if (w->body.fr.maxlines < 2)
|
||||||
colgrow(w->col, w, 1);
|
colgrow(w->col, w, 1);
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
501
wind.c
501
wind.c
|
@ -14,13 +14,11 @@
|
||||||
|
|
||||||
int winid;
|
int winid;
|
||||||
|
|
||||||
void
|
void wininit(Window* w, Window* clone, Rectangle r) {
|
||||||
wininit(Window *w, Window *clone, Rectangle r)
|
|
||||||
{
|
|
||||||
Rectangle r1, br;
|
Rectangle r1, br;
|
||||||
File *f;
|
File* f;
|
||||||
Reffont *rf;
|
Reffont* rf;
|
||||||
Rune *rp;
|
Rune* rp;
|
||||||
int nc, i;
|
int nc, i;
|
||||||
|
|
||||||
w->tag.w = w;
|
w->tag.w = w;
|
||||||
|
@ -29,7 +27,7 @@ wininit(Window *w, Window *clone, Rectangle r)
|
||||||
w->body.w = w;
|
w->body.w = w;
|
||||||
w->id = ++winid;
|
w->id = ++winid;
|
||||||
incref(&w->ref);
|
incref(&w->ref);
|
||||||
if(globalincref)
|
if (globalincref)
|
||||||
incref(&w->ref);
|
incref(&w->ref);
|
||||||
w->ctlfid = ~0;
|
w->ctlfid = ~0;
|
||||||
w->utflastqid = -1;
|
w->utflastqid = -1;
|
||||||
|
@ -37,14 +35,14 @@ wininit(Window *w, Window *clone, Rectangle r)
|
||||||
|
|
||||||
w->tagtop = r;
|
w->tagtop = r;
|
||||||
w->tagtop.max.y = r.min.y + font->height;
|
w->tagtop.max.y = r.min.y + font->height;
|
||||||
r1.max.y = r1.min.y + w->taglines*font->height;
|
r1.max.y = r1.min.y + w->taglines * font->height;
|
||||||
|
|
||||||
incref(&reffont.ref);
|
incref(&reffont.ref);
|
||||||
f = fileaddtext(nil, &w->tag);
|
f = fileaddtext(nil, &w->tag);
|
||||||
textinit(&w->tag, f, r1, &reffont, tagcols);
|
textinit(&w->tag, f, r1, &reffont, tagcols);
|
||||||
w->tag.what = Tag;
|
w->tag.what = Tag;
|
||||||
/* tag is a copy of the contents, not a tracked image */
|
/* tag is a copy of the contents, not a tracked image */
|
||||||
if(clone){
|
if (clone) {
|
||||||
textdelete(&w->tag, 0, w->tag.file->b.nc, TRUE);
|
textdelete(&w->tag, 0, w->tag.file->b.nc, TRUE);
|
||||||
nc = clone->tag.file->b.nc;
|
nc = clone->tag.file->b.nc;
|
||||||
rp = runemalloc(nc);
|
rp = runemalloc(nc);
|
||||||
|
@ -55,22 +53,22 @@ wininit(Window *w, Window *clone, Rectangle r)
|
||||||
textsetselect(&w->tag, nc, nc);
|
textsetselect(&w->tag, nc, nc);
|
||||||
}
|
}
|
||||||
r1 = r;
|
r1 = r;
|
||||||
r1.min.y += w->taglines*font->height + 1;
|
r1.min.y += w->taglines * font->height + 1;
|
||||||
if(r1.max.y < r1.min.y)
|
if (r1.max.y < r1.min.y)
|
||||||
r1.max.y = r1.min.y;
|
r1.max.y = r1.min.y;
|
||||||
f = nil;
|
f = nil;
|
||||||
if(clone){
|
if (clone) {
|
||||||
f = clone->body.file;
|
f = clone->body.file;
|
||||||
w->body.org = clone->body.org;
|
w->body.org = clone->body.org;
|
||||||
w->isscratch = clone->isscratch;
|
w->isscratch = clone->isscratch;
|
||||||
rf = rfget(FALSE, FALSE, FALSE, clone->body.reffont->f->name);
|
rf = rfget(FALSE, FALSE, FALSE, clone->body.reffont->f->name);
|
||||||
}else
|
} else
|
||||||
rf = rfget(FALSE, FALSE, FALSE, nil);
|
rf = rfget(FALSE, FALSE, FALSE, nil);
|
||||||
f = fileaddtext(f, &w->body);
|
f = fileaddtext(f, &w->body);
|
||||||
w->body.what = Body;
|
w->body.what = Body;
|
||||||
textinit(&w->body, f, r1, rf, textcols);
|
textinit(&w->body, f, r1, rf, textcols);
|
||||||
r1.min.y -= 1;
|
r1.min.y -= 1;
|
||||||
r1.max.y = r1.min.y+1;
|
r1.max.y = r1.min.y + 1;
|
||||||
draw(screen, r1, tagcols[BORD], nil, ZP);
|
draw(screen, r1, tagcols[BORD], nil, ZP);
|
||||||
textscrdraw(&w->body);
|
textscrdraw(&w->body);
|
||||||
w->r = r;
|
w->r = r;
|
||||||
|
@ -80,11 +78,11 @@ wininit(Window *w, Window *clone, Rectangle r)
|
||||||
draw(screen, br, button, nil, button->r.min);
|
draw(screen, br, button, nil, button->r.min);
|
||||||
w->filemenu = TRUE;
|
w->filemenu = TRUE;
|
||||||
w->maxlines = w->body.fr.maxlines;
|
w->maxlines = w->body.fr.maxlines;
|
||||||
for(i=0; i<NINDENT; i++)
|
for (i = 0; i < NINDENT; i++)
|
||||||
w->indent[i] = globalindent[i];
|
w->indent[i] = globalindent[i];
|
||||||
if(clone){
|
if (clone) {
|
||||||
w->dirty = clone->dirty;
|
w->dirty = clone->dirty;
|
||||||
for(i=0; i<NINDENT; i++)
|
for (i = 0; i < NINDENT; i++)
|
||||||
w->indent[i] = clone->indent[i];
|
w->indent[i] = clone->indent[i];
|
||||||
textsetselect(&w->body, clone->body.q0, clone->body.q1);
|
textsetselect(&w->body, clone->body.q0, clone->body.q1);
|
||||||
winsettag(w);
|
winsettag(w);
|
||||||
|
@ -94,14 +92,12 @@ wininit(Window *w, Window *clone, Rectangle r)
|
||||||
/*
|
/*
|
||||||
* Draw the appropriate button.
|
* Draw the appropriate button.
|
||||||
*/
|
*/
|
||||||
void
|
void windrawbutton(Window* w) {
|
||||||
windrawbutton(Window *w)
|
Image* b;
|
||||||
{
|
|
||||||
Image *b;
|
|
||||||
Rectangle br;
|
Rectangle br;
|
||||||
|
|
||||||
b = button;
|
b = button;
|
||||||
if(!w->isdir && !w->isscratch && (w->body.file->mod || w->body.ncache))
|
if (!w->isdir && !w->isscratch && (w->body.file->mod || w->body.ncache))
|
||||||
b = modbutton;
|
b = modbutton;
|
||||||
br.min = w->tag.scrollr.min;
|
br.min = w->tag.scrollr.min;
|
||||||
br.max.x = br.min.x + Dx(b->r);
|
br.max.x = br.min.x + Dx(b->r);
|
||||||
|
@ -109,46 +105,42 @@ windrawbutton(Window *w)
|
||||||
draw(screen, br, b, nil, b->r.min);
|
draw(screen, br, b, nil, b->r.min);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int delrunepos(Window* w) {
|
||||||
delrunepos(Window *w)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
Rune rune;
|
Rune rune;
|
||||||
|
|
||||||
for(n=0; n<w->tag.file->b.nc; n++) {
|
for (n = 0; n < w->tag.file->b.nc; n++) {
|
||||||
bufread(&w->tag.file->b, n, &rune, 1);
|
bufread(&w->tag.file->b, n, &rune, 1);
|
||||||
if(rune == ' ')
|
if (rune == ' ')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n += 2;
|
n += 2;
|
||||||
if(n >= w->tag.file->b.nc)
|
if (n >= w->tag.file->b.nc)
|
||||||
return -1;
|
return -1;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void movetodel(Window* w) {
|
||||||
movetodel(Window *w)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
n = delrunepos(w);
|
n = delrunepos(w);
|
||||||
if(n < 0)
|
if (n < 0)
|
||||||
return;
|
return;
|
||||||
moveto(mousectl, addpt(frptofchar(&w->tag.fr, n), Pt(4, w->tag.fr.font->height-4)));
|
moveto(
|
||||||
|
mousectl,
|
||||||
|
addpt(frptofchar(&w->tag.fr, n), Pt(4, w->tag.fr.font->height - 4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute number of tag lines required
|
* Compute number of tag lines required
|
||||||
* to display entire tag text.
|
* to display entire tag text.
|
||||||
*/
|
*/
|
||||||
int
|
int wintaglines(Window* w, Rectangle r) {
|
||||||
wintaglines(Window *w, Rectangle r)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
Rune rune;
|
Rune rune;
|
||||||
Point p;
|
Point p;
|
||||||
|
|
||||||
if(!w->tagexpand && !w->showdel)
|
if (!w->tagexpand && !w->showdel)
|
||||||
return 1;
|
return 1;
|
||||||
w->showdel = FALSE;
|
w->showdel = FALSE;
|
||||||
w->tag.fr.noredraw = 1;
|
w->tag.fr.noredraw = 1;
|
||||||
|
@ -156,34 +148,32 @@ wintaglines(Window *w, Rectangle r)
|
||||||
w->tag.fr.noredraw = 0;
|
w->tag.fr.noredraw = 0;
|
||||||
w->tagsafe = FALSE;
|
w->tagsafe = FALSE;
|
||||||
|
|
||||||
if(!w->tagexpand) {
|
if (!w->tagexpand) {
|
||||||
/* use just as many lines as needed to show the Del */
|
/* use just as many lines as needed to show the Del */
|
||||||
n = delrunepos(w);
|
n = delrunepos(w);
|
||||||
if(n < 0)
|
if (n < 0)
|
||||||
return 1;
|
return 1;
|
||||||
p = subpt(frptofchar(&w->tag.fr, n), w->tag.fr.r.min);
|
p = subpt(frptofchar(&w->tag.fr, n), w->tag.fr.r.min);
|
||||||
return 1 + p.y / w->tag.fr.font->height;
|
return 1 + p.y / w->tag.fr.font->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* can't use more than we have */
|
/* can't use more than we have */
|
||||||
if(w->tag.fr.nlines >= w->tag.fr.maxlines)
|
if (w->tag.fr.nlines >= w->tag.fr.maxlines)
|
||||||
return w->tag.fr.maxlines;
|
return w->tag.fr.maxlines;
|
||||||
|
|
||||||
/* if tag ends with \n, include empty line at end for typing */
|
/* if tag ends with \n, include empty line at end for typing */
|
||||||
n = w->tag.fr.nlines;
|
n = w->tag.fr.nlines;
|
||||||
if(w->tag.file->b.nc > 0){
|
if (w->tag.file->b.nc > 0) {
|
||||||
bufread(&w->tag.file->b, w->tag.file->b.nc-1, &rune, 1);
|
bufread(&w->tag.file->b, w->tag.file->b.nc - 1, &rune, 1);
|
||||||
if(rune == '\n')
|
if (rune == '\n')
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
if(n == 0)
|
if (n == 0)
|
||||||
n = 1;
|
n = 1;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int winresize(Window* w, Rectangle r, int safe, int keepextra) {
|
||||||
winresize(Window *w, Rectangle r, int safe, int keepextra)
|
|
||||||
{
|
|
||||||
int oy, y, mouseintag, mouseinbody;
|
int oy, y, mouseintag, mouseinbody;
|
||||||
Point p;
|
Point p;
|
||||||
Rectangle r1;
|
Rectangle r1;
|
||||||
|
@ -193,36 +183,36 @@ winresize(Window *w, Rectangle r, int safe, int keepextra)
|
||||||
|
|
||||||
/* tagtop is first line of tag */
|
/* tagtop is first line of tag */
|
||||||
w->tagtop = r;
|
w->tagtop = r;
|
||||||
w->tagtop.max.y = r.min.y+font->height;
|
w->tagtop.max.y = r.min.y + font->height;
|
||||||
|
|
||||||
r1 = r;
|
r1 = r;
|
||||||
r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height);
|
r1.max.y = min(r.max.y, r1.min.y + w->taglines * font->height);
|
||||||
|
|
||||||
/* If needed, recompute number of lines in tag. */
|
/* If needed, recompute number of lines in tag. */
|
||||||
if(!safe || !w->tagsafe || !eqrect(w->tag.all, r1)){
|
if (!safe || !w->tagsafe || !eqrect(w->tag.all, r1)) {
|
||||||
w->taglines = wintaglines(w, r);
|
w->taglines = wintaglines(w, r);
|
||||||
r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height);
|
r1.max.y = min(r.max.y, r1.min.y + w->taglines * font->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If needed, resize & redraw tag. */
|
/* If needed, resize & redraw tag. */
|
||||||
y = r1.max.y;
|
y = r1.max.y;
|
||||||
if(!safe || !w->tagsafe || !eqrect(w->tag.all, r1)){
|
if (!safe || !w->tagsafe || !eqrect(w->tag.all, r1)) {
|
||||||
textresize(&w->tag, r1, TRUE);
|
textresize(&w->tag, r1, TRUE);
|
||||||
y = w->tag.fr.r.max.y;
|
y = w->tag.fr.r.max.y;
|
||||||
windrawbutton(w);
|
windrawbutton(w);
|
||||||
w->tagsafe = TRUE;
|
w->tagsafe = TRUE;
|
||||||
|
|
||||||
/* If mouse is in tag, pull up as tag closes. */
|
/* If mouse is in tag, pull up as tag closes. */
|
||||||
if(mouseintag && !ptinrect(mouse->xy, w->tag.all)){
|
if (mouseintag && !ptinrect(mouse->xy, w->tag.all)) {
|
||||||
p = mouse->xy;
|
p = mouse->xy;
|
||||||
p.y = w->tag.all.max.y-3;
|
p.y = w->tag.all.max.y - 3;
|
||||||
moveto(mousectl, p);
|
moveto(mousectl, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If mouse is in body, push down as tag expands. */
|
/* If mouse is in body, push down as tag expands. */
|
||||||
if(mouseinbody && ptinrect(mouse->xy, w->tag.all)){
|
if (mouseinbody && ptinrect(mouse->xy, w->tag.all)) {
|
||||||
p = mouse->xy;
|
p = mouse->xy;
|
||||||
p.y = w->tag.all.max.y+3;
|
p.y = w->tag.all.max.y + 3;
|
||||||
moveto(mousectl, p);
|
moveto(mousectl, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,16 +220,16 @@ winresize(Window *w, Rectangle r, int safe, int keepextra)
|
||||||
/* If needed, resize & redraw body. */
|
/* If needed, resize & redraw body. */
|
||||||
r1 = r;
|
r1 = r;
|
||||||
r1.min.y = y;
|
r1.min.y = y;
|
||||||
if(!safe || !eqrect(w->body.all, r1)){
|
if (!safe || !eqrect(w->body.all, r1)) {
|
||||||
oy = y;
|
oy = y;
|
||||||
if(y+1+w->body.fr.font->height <= r.max.y){ /* room for one line */
|
if (y + 1 + w->body.fr.font->height <= r.max.y) { /* room for one line */
|
||||||
r1.min.y = y;
|
r1.min.y = y;
|
||||||
r1.max.y = y+1;
|
r1.max.y = y + 1;
|
||||||
draw(screen, r1, tagcols[BORD], nil, ZP);
|
draw(screen, r1, tagcols[BORD], nil, ZP);
|
||||||
y++;
|
y++;
|
||||||
r1.min.y = min(y, r.max.y);
|
r1.min.y = min(y, r.max.y);
|
||||||
r1.max.y = r.max.y;
|
r1.max.y = r.max.y;
|
||||||
}else{
|
} else {
|
||||||
r1.min.y = y;
|
r1.min.y = y;
|
||||||
r1.max.y = y;
|
r1.max.y = y;
|
||||||
}
|
}
|
||||||
|
@ -253,30 +243,24 @@ winresize(Window *w, Rectangle r, int safe, int keepextra)
|
||||||
return w->r.max.y;
|
return w->r.max.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winlock1(Window* w, int owner) {
|
||||||
winlock1(Window *w, int owner)
|
|
||||||
{
|
|
||||||
incref(&w->ref);
|
incref(&w->ref);
|
||||||
qlock(&w->lk);
|
qlock(&w->lk);
|
||||||
w->owner = owner;
|
w->owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winlock(Window* w, int owner) {
|
||||||
winlock(Window *w, int owner)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
File *f;
|
File* f;
|
||||||
|
|
||||||
f = w->body.file;
|
f = w->body.file;
|
||||||
for(i=0; i<f->ntext; i++)
|
for (i = 0; i < f->ntext; i++)
|
||||||
winlock1(f->text[i]->w, owner);
|
winlock1(f->text[i]->w, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winunlock(Window* w) {
|
||||||
winunlock(Window *w)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
File *f;
|
File* f;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* subtle: loop runs backwards to avoid tripping over
|
* subtle: loop runs backwards to avoid tripping over
|
||||||
|
@ -284,7 +268,7 @@ winunlock(Window *w)
|
||||||
* on the last iteration of the loop.
|
* on the last iteration of the loop.
|
||||||
*/
|
*/
|
||||||
f = w->body.file;
|
f = w->body.file;
|
||||||
for(i=f->ntext-1; i>=0; i--){
|
for (i = f->ntext - 1; i >= 0; i--) {
|
||||||
w = f->text[i]->w;
|
w = f->text[i]->w;
|
||||||
w->owner = 0;
|
w->owner = 0;
|
||||||
qunlock(&w->lk);
|
qunlock(&w->lk);
|
||||||
|
@ -292,21 +276,18 @@ winunlock(Window *w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winmousebut(Window* w) {
|
||||||
winmousebut(Window *w)
|
moveto(
|
||||||
{
|
mousectl,
|
||||||
moveto(mousectl, addpt(w->tag.scrollr.min,
|
addpt(w->tag.scrollr.min, divpt(Pt(Dx(w->tag.scrollr), font->height), 2)));
|
||||||
divpt(Pt(Dx(w->tag.scrollr), font->height), 2)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void windirfree(Window* w) {
|
||||||
windirfree(Window *w)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
Dirlist *dl;
|
Dirlist* dl;
|
||||||
|
|
||||||
if(w->isdir){
|
if (w->isdir) {
|
||||||
for(i=0; i<w->ndl; i++){
|
for (i = 0; i < w->ndl; i++) {
|
||||||
dl = w->dlp[i];
|
dl = w->dlp[i];
|
||||||
free(dl->r);
|
free(dl->r);
|
||||||
free(dl);
|
free(dl);
|
||||||
|
@ -317,19 +298,17 @@ windirfree(Window *w)
|
||||||
w->ndl = 0;
|
w->ndl = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winclose(Window* w) {
|
||||||
winclose(Window *w)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(decref(&w->ref) == 0){
|
if (decref(&w->ref) == 0) {
|
||||||
xfidlog(w, "del");
|
xfidlog(w, "del");
|
||||||
windirfree(w);
|
windirfree(w);
|
||||||
textclose(&w->tag);
|
textclose(&w->tag);
|
||||||
textclose(&w->body);
|
textclose(&w->body);
|
||||||
if(activewin == w)
|
if (activewin == w)
|
||||||
activewin = nil;
|
activewin = nil;
|
||||||
for(i=0; i<w->nincl; i++)
|
for (i = 0; i < w->nincl; i++)
|
||||||
free(w->incl[i]);
|
free(w->incl[i]);
|
||||||
free(w->incl);
|
free(w->incl);
|
||||||
free(w->events);
|
free(w->events);
|
||||||
|
@ -337,13 +316,11 @@ winclose(Window *w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void windelete(Window* w) {
|
||||||
windelete(Window *w)
|
Xfid* x;
|
||||||
{
|
|
||||||
Xfid *x;
|
|
||||||
|
|
||||||
x = w->eventx;
|
x = w->eventx;
|
||||||
if(x){
|
if (x) {
|
||||||
w->nevents = 0;
|
w->nevents = 0;
|
||||||
free(w->events);
|
free(w->events);
|
||||||
w->events = nil;
|
w->events = nil;
|
||||||
|
@ -352,164 +329,183 @@ windelete(Window *w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winundo(Window* w, int isundo) {
|
||||||
winundo(Window *w, int isundo)
|
Text* body;
|
||||||
{
|
|
||||||
Text *body;
|
|
||||||
int i;
|
int i;
|
||||||
File *f;
|
File* f;
|
||||||
Window *v;
|
Window* v;
|
||||||
|
|
||||||
w->utflastqid = -1;
|
w->utflastqid = -1;
|
||||||
body = &w->body;
|
body = &w->body;
|
||||||
fileundo(body->file, isundo, &body->q0, &body->q1);
|
fileundo(body->file, isundo, &body->q0, &body->q1);
|
||||||
textshow(body, body->q0, body->q1, 1);
|
textshow(body, body->q0, body->q1, 1);
|
||||||
f = body->file;
|
f = body->file;
|
||||||
for(i=0; i<f->ntext; i++){
|
for (i = 0; i < f->ntext; i++) {
|
||||||
v = f->text[i]->w;
|
v = f->text[i]->w;
|
||||||
v->dirty = (f->seq != v->putseq);
|
v->dirty = (f->seq != v->putseq);
|
||||||
if(v != w){
|
if (v != w) {
|
||||||
v->body.q0 = v->body.fr.p0+v->body.org;
|
v->body.q0 = v->body.fr.p0 + v->body.org;
|
||||||
v->body.q1 = v->body.fr.p1+v->body.org;
|
v->body.q1 = v->body.fr.p1 + v->body.org;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
winsettag(w);
|
winsettag(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winsetname(Window* w, Rune* name, int n) {
|
||||||
winsetname(Window *w, Rune *name, int n)
|
Text* t;
|
||||||
{
|
Window* v;
|
||||||
Text *t;
|
|
||||||
Window *v;
|
|
||||||
int i;
|
int i;
|
||||||
static Rune Lslashguide[] = { '/', 'g', 'u', 'i', 'd', 'e', 0 };
|
static Rune Lslashguide[] = {'/', 'g', 'u', 'i', 'd', 'e', 0};
|
||||||
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
|
static Rune Lpluserrors[] = {'+', 'E', 'r', 'r', 'o', 'r', 's', 0};
|
||||||
|
|
||||||
t = &w->body;
|
t = &w->body;
|
||||||
if(runeeq(t->file->name, t->file->nname, name, n) == TRUE)
|
if (runeeq(t->file->name, t->file->nname, name, n) == TRUE)
|
||||||
return;
|
return;
|
||||||
w->isscratch = FALSE;
|
w->isscratch = FALSE;
|
||||||
if(n>=6 && runeeq(Lslashguide, 6, name+(n-6), 6))
|
if (n >= 6 && runeeq(Lslashguide, 6, name + (n - 6), 6))
|
||||||
w->isscratch = TRUE;
|
w->isscratch = TRUE;
|
||||||
else if(n>=7 && runeeq(Lpluserrors, 7, name+(n-7), 7))
|
else if (n >= 7 && runeeq(Lpluserrors, 7, name + (n - 7), 7))
|
||||||
w->isscratch = TRUE;
|
w->isscratch = TRUE;
|
||||||
filesetname(t->file, name, n);
|
filesetname(t->file, name, n);
|
||||||
for(i=0; i<t->file->ntext; i++){
|
for (i = 0; i < t->file->ntext; i++) {
|
||||||
v = t->file->text[i]->w;
|
v = t->file->text[i]->w;
|
||||||
winsettag(v);
|
winsettag(v);
|
||||||
v->isscratch = w->isscratch;
|
v->isscratch = w->isscratch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void wintype(Window* w, Text* t, Rune r) {
|
||||||
wintype(Window *w, Text *t, Rune r)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
texttype(t, r);
|
texttype(t, r);
|
||||||
if(t->what == Body)
|
if (t->what == Body)
|
||||||
for(i=0; i<t->file->ntext; i++)
|
for (i = 0; i < t->file->ntext; i++)
|
||||||
textscrdraw(t->file->text[i]);
|
textscrdraw(t->file->text[i]);
|
||||||
winsettag(w);
|
winsettag(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void wincleartag(Window* w) {
|
||||||
wincleartag(Window *w)
|
|
||||||
{
|
|
||||||
int i, n;
|
int i, n;
|
||||||
Rune *r;
|
Rune* r;
|
||||||
|
|
||||||
/* w must be committed */
|
/* w must be committed */
|
||||||
n = w->tag.file->b.nc;
|
n = w->tag.file->b.nc;
|
||||||
r = runemalloc(n);
|
r = parsetag(w, &i);
|
||||||
bufread(&w->tag.file->b, 0, r, n);
|
for (; i < n; i++)
|
||||||
for(i=0; i<n; i++)
|
if (r[i] == '|')
|
||||||
if(r[i]==' ' || r[i]=='\t')
|
|
||||||
break;
|
break;
|
||||||
for(; i<n; i++)
|
if (i == n)
|
||||||
if(r[i] == '|')
|
|
||||||
break;
|
|
||||||
if(i == n)
|
|
||||||
return;
|
return;
|
||||||
i++;
|
i++;
|
||||||
textdelete(&w->tag, i, n, TRUE);
|
textdelete(&w->tag, i, n, TRUE);
|
||||||
free(r);
|
free(r);
|
||||||
w->tag.file->mod = FALSE;
|
w->tag.file->mod = FALSE;
|
||||||
if(w->tag.q0 > i)
|
if (w->tag.q0 > i)
|
||||||
w->tag.q0 = i;
|
w->tag.q0 = i;
|
||||||
if(w->tag.q1 > i)
|
if (w->tag.q1 > i)
|
||||||
w->tag.q1 = i;
|
w->tag.q1 = i;
|
||||||
textsetselect(&w->tag, w->tag.q0, w->tag.q1);
|
textsetselect(&w->tag, w->tag.q0, w->tag.q1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
Rune* parsetag(Window* w, int* len) {
|
||||||
winsettag1(Window *w)
|
static Rune Ldelsnarf[] =
|
||||||
{
|
{' ', 'D', 'e', 'l', ' ', 'S', 'n', 'a', 'r', 'f', 0};
|
||||||
int i, j, k, n, bar, dirty, resize;
|
static Rune Lspacepipe[] = {' ', '|', 0};
|
||||||
Rune *new, *old, *r;
|
static Rune Ltabpipe[] = {' ', '|', 0};
|
||||||
uint q0, q1;
|
int i;
|
||||||
static Rune Ldelsnarf[] = { ' ', 'D', 'e', 'l', ' ',
|
Rune *r, *p, *pipe;
|
||||||
'S', 'n', 'a', 'r', 'f', 0 };
|
|
||||||
static Rune Lundo[] = { ' ', 'U', 'n', 'd', 'o', 0 };
|
|
||||||
static Rune Lredo[] = { ' ', 'R', 'e', 'd', 'o', 0 };
|
|
||||||
static Rune Lget[] = { ' ', 'G', 'e', 't', 0 };
|
|
||||||
static Rune Lput[] = { ' ', 'P', 'u', 't', 0 };
|
|
||||||
static Rune Llook[] = { ' ', 'L', 'o', 'o', 'k', ' ', 0 };
|
|
||||||
static Rune Lpipe[] = { ' ', '|', 0 };
|
|
||||||
|
|
||||||
/* there are races that get us here with stuff in the tag cache, so we take extra care to sync it */
|
r = runemalloc(w->tag.file->b.nc + 1);
|
||||||
if(w->tag.ncache!=0 || w->tag.file->mod)
|
bufread(&w->tag.file->b, 0, r, w->tag.file->b.nc);
|
||||||
wincommit(w, &w->tag); /* check file name; also guarantees we can modify tag contents */
|
r[w->tag.file->b.nc] = '\0';
|
||||||
old = runemalloc(w->tag.file->b.nc+1);
|
|
||||||
bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc);
|
for (i = 0; i < w->tag.file->b.nc; i++)
|
||||||
old[w->tag.file->b.nc] = '\0';
|
if (r[i] == ' ' || r[i] == '\t')
|
||||||
for(i=0; i<w->tag.file->b.nc; i++)
|
|
||||||
if(old[i]==' ' || old[i]=='\t')
|
|
||||||
break;
|
break;
|
||||||
if(runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE){
|
|
||||||
|
/*
|
||||||
|
* " |" or "\t|" ends left half of tag
|
||||||
|
* If we find " Del Snarf" in the left half of the tag
|
||||||
|
* (before the pipe), that ends the file name.
|
||||||
|
*/
|
||||||
|
pipe = runestrstr(r, Lspacepipe);
|
||||||
|
if ((p = runestrstr(r, Ltabpipe)) != nil && (pipe == nil || p < pipe))
|
||||||
|
pipe = p;
|
||||||
|
if ((p = runestrstr(r, Ldelsnarf)) != nil && (pipe == nil || p < pipe))
|
||||||
|
i = p - r;
|
||||||
|
else {
|
||||||
|
for (i = 0; i < w->tag.file->b.nc; i++)
|
||||||
|
if (r[i] == ' ' || r[i] == '\t')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*len = i;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void winsettag1(Window* w) {
|
||||||
|
int i, j, k, n, bar, dirty, resize;
|
||||||
|
Rune* new, *old, *r;
|
||||||
|
uint q0, q1;
|
||||||
|
static Rune Ldelsnarf[] =
|
||||||
|
{' ', 'D', 'e', 'l', ' ', 'S', 'n', 'a', 'r', 'f', 0};
|
||||||
|
static Rune Lundo[] = {' ', 'U', 'n', 'd', 'o', 0};
|
||||||
|
static Rune Lredo[] = {' ', 'R', 'e', 'd', 'o', 0};
|
||||||
|
static Rune Lget[] = {' ', 'G', 'e', 't', 0};
|
||||||
|
static Rune Lput[] = {' ', 'P', 'u', 't', 0};
|
||||||
|
static Rune Llook[] = {' ', 'L', 'o', 'o', 'k', ' ', 0};
|
||||||
|
static Rune Lpipe[] = {' ', '|', 0};
|
||||||
|
|
||||||
|
/* there are races that get us here with stuff in the tag cache, so we take
|
||||||
|
* extra care to sync it */
|
||||||
|
if (w->tag.ncache != 0 || w->tag.file->mod)
|
||||||
|
wincommit(w, &w->tag); /* check file name; also guarantees we can modify tag
|
||||||
|
contents */
|
||||||
|
old = parsetag(w, &i);
|
||||||
|
if (runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE) {
|
||||||
textdelete(&w->tag, 0, i, TRUE);
|
textdelete(&w->tag, 0, i, TRUE);
|
||||||
textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE);
|
textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE);
|
||||||
free(old);
|
free(old);
|
||||||
old = runemalloc(w->tag.file->b.nc+1);
|
old = runemalloc(w->tag.file->b.nc + 1);
|
||||||
bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc);
|
bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc);
|
||||||
old[w->tag.file->b.nc] = '\0';
|
old[w->tag.file->b.nc] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compute the text for the whole tag, replacing current only if it differs */
|
/* compute the text for the whole tag, replacing current only if it differs */
|
||||||
new = runemalloc(w->body.file->nname+100);
|
new = runemalloc(w->body.file->nname + 100);
|
||||||
i = 0;
|
i = 0;
|
||||||
runemove(new+i, w->body.file->name, w->body.file->nname);
|
runemove(new + i, w->body.file->name, w->body.file->nname);
|
||||||
i += w->body.file->nname;
|
i += w->body.file->nname;
|
||||||
runemove(new+i, Ldelsnarf, 10);
|
runemove(new + i, Ldelsnarf, 10);
|
||||||
i += 10;
|
i += 10;
|
||||||
if(w->filemenu){
|
if (w->filemenu) {
|
||||||
if(w->body.needundo || w->body.file->delta.nc>0 || w->body.ncache){
|
if (w->body.needundo || w->body.file->delta.nc > 0 || w->body.ncache) {
|
||||||
runemove(new+i, Lundo, 5);
|
runemove(new + i, Lundo, 5);
|
||||||
i += 5;
|
i += 5;
|
||||||
}
|
}
|
||||||
if(w->body.file->epsilon.nc > 0){
|
if (w->body.file->epsilon.nc > 0) {
|
||||||
runemove(new+i, Lredo, 5);
|
runemove(new + i, Lredo, 5);
|
||||||
i += 5;
|
i += 5;
|
||||||
}
|
}
|
||||||
dirty = w->body.file->nname && (w->body.ncache || w->body.file->seq!=w->putseq);
|
dirty =
|
||||||
if(!w->isdir && dirty){
|
w->body.file->nname && (w->body.ncache || w->body.file->seq != w->putseq);
|
||||||
runemove(new+i, Lput, 4);
|
if (!w->isdir && dirty) {
|
||||||
|
runemove(new + i, Lput, 4);
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(w->isdir){
|
if (w->isdir) {
|
||||||
runemove(new+i, Lget, 4);
|
runemove(new + i, Lget, 4);
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
runemove(new+i, Lpipe, 2);
|
runemove(new + i, Lpipe, 2);
|
||||||
i += 2;
|
i += 2;
|
||||||
r = runestrchr(old, '|');
|
r = runestrchr(old, '|');
|
||||||
if(r)
|
if (r)
|
||||||
k = r-old+1;
|
k = r - old + 1;
|
||||||
else{
|
else {
|
||||||
k = w->tag.file->b.nc;
|
k = w->tag.file->b.nc;
|
||||||
if(w->body.file->seq == 0){
|
if (w->body.file->seq == 0) {
|
||||||
runemove(new+i, Llook, 6);
|
runemove(new + i, Llook, 6);
|
||||||
i += 6;
|
i += 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -517,80 +513,72 @@ winsettag1(Window *w)
|
||||||
|
|
||||||
/* replace tag if the new one is different */
|
/* replace tag if the new one is different */
|
||||||
resize = 0;
|
resize = 0;
|
||||||
if(runeeq(new, i, old, k) == FALSE){
|
if (runeeq(new, i, old, k) == FALSE) {
|
||||||
resize = 1;
|
resize = 1;
|
||||||
n = k;
|
n = k;
|
||||||
if(n > i)
|
if (n > i)
|
||||||
n = i;
|
n = i;
|
||||||
for(j=0; j<n; j++)
|
for (j = 0; j < n; j++)
|
||||||
if(old[j] != new[j])
|
if (old[j] != new[j])
|
||||||
break;
|
break;
|
||||||
q0 = w->tag.q0;
|
q0 = w->tag.q0;
|
||||||
q1 = w->tag.q1;
|
q1 = w->tag.q1;
|
||||||
textdelete(&w->tag, j, k, TRUE);
|
textdelete(&w->tag, j, k, TRUE);
|
||||||
textinsert(&w->tag, j, new+j, i-j, TRUE);
|
textinsert(&w->tag, j, new + j, i - j, TRUE);
|
||||||
/* try to preserve user selection */
|
/* try to preserve user selection */
|
||||||
r = runestrchr(old, '|');
|
r = runestrchr(old, '|');
|
||||||
if(r){
|
if (r) {
|
||||||
bar = r-old;
|
bar = r - old;
|
||||||
if(q0 > bar){
|
if (q0 > bar) {
|
||||||
bar = (runestrchr(new, '|')-new)-bar;
|
bar = (runestrchr(new, '|') - new) - bar;
|
||||||
w->tag.q0 = q0+bar;
|
w->tag.q0 = q0 + bar;
|
||||||
w->tag.q1 = q1+bar;
|
w->tag.q1 = q1 + bar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(old);
|
free(old);
|
||||||
free(new);
|
free(new);
|
||||||
w->tag.file->mod = FALSE;
|
w->tag.file->mod = FALSE;
|
||||||
n = w->tag.file->b.nc+w->tag.ncache;
|
n = w->tag.file->b.nc + w->tag.ncache;
|
||||||
if(w->tag.q0 > n)
|
if (w->tag.q0 > n)
|
||||||
w->tag.q0 = n;
|
w->tag.q0 = n;
|
||||||
if(w->tag.q1 > n)
|
if (w->tag.q1 > n)
|
||||||
w->tag.q1 = n;
|
w->tag.q1 = n;
|
||||||
textsetselect(&w->tag, w->tag.q0, w->tag.q1);
|
textsetselect(&w->tag, w->tag.q0, w->tag.q1);
|
||||||
windrawbutton(w);
|
windrawbutton(w);
|
||||||
if(resize){
|
if (resize) {
|
||||||
w->tagsafe = 0;
|
w->tagsafe = 0;
|
||||||
winresize(w, w->r, TRUE, TRUE);
|
winresize(w, w->r, TRUE, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winsettag(Window* w) {
|
||||||
winsettag(Window *w)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
File *f;
|
File* f;
|
||||||
Window *v;
|
Window* v;
|
||||||
|
|
||||||
f = w->body.file;
|
f = w->body.file;
|
||||||
for(i=0; i<f->ntext; i++){
|
for (i = 0; i < f->ntext; i++) {
|
||||||
v = f->text[i]->w;
|
v = f->text[i]->w;
|
||||||
if(v->col->safe || v->body.fr.maxlines>0)
|
if (v->col->safe || v->body.fr.maxlines > 0)
|
||||||
winsettag1(v);
|
winsettag1(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void wincommit(Window* w, Text* t) {
|
||||||
wincommit(Window *w, Text *t)
|
Rune* r;
|
||||||
{
|
|
||||||
Rune *r;
|
|
||||||
int i;
|
int i;
|
||||||
File *f;
|
File* f;
|
||||||
|
|
||||||
textcommit(t, TRUE);
|
textcommit(t, TRUE);
|
||||||
f = t->file;
|
f = t->file;
|
||||||
if(f->ntext > 1)
|
if (f->ntext > 1)
|
||||||
for(i=0; i<f->ntext; i++)
|
for (i = 0; i < f->ntext; i++)
|
||||||
textcommit(f->text[i], FALSE); /* no-op for t */
|
textcommit(f->text[i], FALSE); /* no-op for t */
|
||||||
if(t->what == Body)
|
if (t->what == Body)
|
||||||
return;
|
return;
|
||||||
r = runemalloc(w->tag.file->b.nc);
|
r = parsetag(w, &i);
|
||||||
bufread(&w->tag.file->b, 0, r, w->tag.file->b.nc);
|
if (runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE) {
|
||||||
for(i=0; i<w->tag.file->b.nc; i++)
|
|
||||||
if(r[i]==' ' || r[i]=='\t')
|
|
||||||
break;
|
|
||||||
if(runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE){
|
|
||||||
seq++;
|
seq++;
|
||||||
filemark(w->body.file);
|
filemark(w->body.file);
|
||||||
w->body.file->mod = TRUE;
|
w->body.file->mod = TRUE;
|
||||||
|
@ -601,17 +589,15 @@ wincommit(Window *w, Text *t)
|
||||||
free(r);
|
free(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winaddincl(Window* w, Rune* r, int n) {
|
||||||
winaddincl(Window *w, Rune *r, int n)
|
char* a;
|
||||||
{
|
Dir* d;
|
||||||
char *a;
|
|
||||||
Dir *d;
|
|
||||||
Runestr rs;
|
Runestr rs;
|
||||||
|
|
||||||
a = runetobyte(r, n);
|
a = runetobyte(r, n);
|
||||||
d = dirstat(a);
|
d = dirstat(a);
|
||||||
if(d == nil){
|
if (d == nil) {
|
||||||
if(a[0] == '/')
|
if (a[0] == '/')
|
||||||
goto Rescue;
|
goto Rescue;
|
||||||
rs = dirname(&w->body, r, n);
|
rs = dirname(&w->body, r, n);
|
||||||
r = rs.r;
|
r = rs.r;
|
||||||
|
@ -619,13 +605,13 @@ winaddincl(Window *w, Rune *r, int n)
|
||||||
free(a);
|
free(a);
|
||||||
a = runetobyte(r, n);
|
a = runetobyte(r, n);
|
||||||
d = dirstat(a);
|
d = dirstat(a);
|
||||||
if(d == nil)
|
if (d == nil)
|
||||||
goto Rescue;
|
goto Rescue;
|
||||||
r = runerealloc(r, n+1);
|
r = runerealloc(r, n + 1);
|
||||||
r[n] = 0;
|
r[n] = 0;
|
||||||
}
|
}
|
||||||
free(a);
|
free(a);
|
||||||
if((d->qid.type&QTDIR) == 0){
|
if ((d->qid.type & QTDIR) == 0) {
|
||||||
free(d);
|
free(d);
|
||||||
warning(nil, "%s: not a directory\n", a);
|
warning(nil, "%s: not a directory\n", a);
|
||||||
free(r);
|
free(r);
|
||||||
|
@ -633,9 +619,9 @@ winaddincl(Window *w, Rune *r, int n)
|
||||||
}
|
}
|
||||||
free(d);
|
free(d);
|
||||||
w->nincl++;
|
w->nincl++;
|
||||||
w->incl = realloc(w->incl, w->nincl*sizeof(Rune*));
|
w->incl = realloc(w->incl, w->nincl * sizeof(Rune*));
|
||||||
memmove(w->incl+1, w->incl, (w->nincl-1)*sizeof(Rune*));
|
memmove(w->incl + 1, w->incl, (w->nincl - 1) * sizeof(Rune*));
|
||||||
w->incl[0] = runemalloc(n+1);
|
w->incl[0] = runemalloc(n + 1);
|
||||||
runemove(w->incl[0], r, n);
|
runemove(w->incl[0], r, n);
|
||||||
free(r);
|
free(r);
|
||||||
return;
|
return;
|
||||||
|
@ -647,18 +633,17 @@ Rescue:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int winclean(Window* w, int conservative) {
|
||||||
winclean(Window *w, int conservative)
|
if (w->isscratch || w->isdir) /* don't whine if it's a guide file, error
|
||||||
{
|
window, etc. */
|
||||||
if(w->isscratch || w->isdir) /* don't whine if it's a guide file, error window, etc. */
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
if(!conservative && w->nopen[QWevent]>0)
|
if (!conservative && w->nopen[QWevent] > 0)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
if(w->dirty){
|
if (w->dirty) {
|
||||||
if(w->body.file->nname)
|
if (w->body.file->nname)
|
||||||
warning(nil, "%.*S modified\n", w->body.file->nname, w->body.file->name);
|
warning(nil, "%.*S modified\n", w->body.file->nname, w->body.file->name);
|
||||||
else{
|
else {
|
||||||
if(w->body.file->b.nc < 100) /* don't whine if it's too small */
|
if (w->body.file->b.nc < 100) /* don't whine if it's too small */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
warning(nil, "unnamed file modified\n");
|
warning(nil, "unnamed file modified\n");
|
||||||
}
|
}
|
||||||
|
@ -668,42 +653,48 @@ winclean(Window *w, int conservative)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char* winctlprint(Window* w, char* buf, int fonts) {
|
||||||
winctlprint(Window *w, char *buf, int fonts)
|
sprint(
|
||||||
{
|
buf,
|
||||||
sprint(buf, "%11d %11d %11d %11d %11d ", w->id, w->tag.file->b.nc,
|
"%11d %11d %11d %11d %11d ",
|
||||||
w->body.file->b.nc, w->isdir, w->dirty);
|
w->id,
|
||||||
if(fonts)
|
w->tag.file->b.nc,
|
||||||
return smprint("%s%11d %q %11d ", buf, Dx(w->body.fr.r),
|
w->body.file->b.nc,
|
||||||
w->body.reffont->f->name, w->body.fr.maxtab);
|
w->isdir,
|
||||||
|
w->dirty);
|
||||||
|
if (fonts)
|
||||||
|
return smprint(
|
||||||
|
"%s%11d %q %11d ",
|
||||||
|
buf,
|
||||||
|
Dx(w->body.fr.r),
|
||||||
|
w->body.reffont->f->name,
|
||||||
|
w->body.fr.maxtab);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void winevent(Window* w, char* fmt, ...) {
|
||||||
winevent(Window *w, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
char *b;
|
char* b;
|
||||||
Xfid *x;
|
Xfid* x;
|
||||||
va_list arg;
|
va_list arg;
|
||||||
|
|
||||||
if(w->nopen[QWevent] == 0)
|
if (w->nopen[QWevent] == 0)
|
||||||
return;
|
return;
|
||||||
if(w->owner == 0)
|
if (w->owner == 0)
|
||||||
error("no window owner");
|
error("no window owner");
|
||||||
va_start(arg, fmt);
|
va_start(arg, fmt);
|
||||||
b = vsmprint(fmt, arg);
|
b = vsmprint(fmt, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
if(b == nil)
|
if (b == nil)
|
||||||
error("vsmprint failed");
|
error("vsmprint failed");
|
||||||
n = strlen(b);
|
n = strlen(b);
|
||||||
w->events = erealloc(w->events, w->nevents+1+n);
|
w->events = erealloc(w->events, w->nevents + 1 + n);
|
||||||
w->events[w->nevents++] = w->owner;
|
w->events[w->nevents++] = w->owner;
|
||||||
memmove(w->events+w->nevents, b, n);
|
memmove(w->events + w->nevents, b, n);
|
||||||
free(b);
|
free(b);
|
||||||
w->nevents += n;
|
w->nevents += n;
|
||||||
x = w->eventx;
|
x = w->eventx;
|
||||||
if(x){
|
if (x) {
|
||||||
w->eventx = nil;
|
w->eventx = nil;
|
||||||
sendp(x->c, nil);
|
sendp(x->c, nil);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue