More files related to user-level file servers.
Also add acme!
This commit is contained in:
parent
32f69c36e0
commit
b3994ec5c7
35 changed files with 14133 additions and 0 deletions
682
src/cmd/acme/edit.c
Normal file
682
src/cmd/acme/edit.c
Normal file
|
|
@ -0,0 +1,682 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <thread.h>
|
||||
#include <cursor.h>
|
||||
#include <mouse.h>
|
||||
#include <keyboard.h>
|
||||
#include <frame.h>
|
||||
#include <fcall.h>
|
||||
#include <plumb.h>
|
||||
#include "dat.h"
|
||||
#include "edit.h"
|
||||
#include "fns.h"
|
||||
|
||||
static char linex[]="\n";
|
||||
static char wordx[]=" \t\n";
|
||||
struct cmdtab cmdtab[]={
|
||||
/* cmdc text regexp addr defcmd defaddr count token fn */
|
||||
'\n', 0, 0, 0, 0, aDot, 0, 0, nl_cmd,
|
||||
'a', 1, 0, 0, 0, aDot, 0, 0, a_cmd,
|
||||
'b', 0, 0, 0, 0, aNo, 0, linex, b_cmd,
|
||||
'c', 1, 0, 0, 0, aDot, 0, 0, c_cmd,
|
||||
'd', 0, 0, 0, 0, aDot, 0, 0, d_cmd,
|
||||
'e', 0, 0, 0, 0, aNo, 0, wordx, e_cmd,
|
||||
'f', 0, 0, 0, 0, aNo, 0, wordx, f_cmd,
|
||||
'g', 0, 1, 0, 'p', aDot, 0, 0, g_cmd,
|
||||
'i', 1, 0, 0, 0, aDot, 0, 0, i_cmd,
|
||||
'm', 0, 0, 1, 0, aDot, 0, 0, m_cmd,
|
||||
'p', 0, 0, 0, 0, aDot, 0, 0, p_cmd,
|
||||
'r', 0, 0, 0, 0, aDot, 0, wordx, e_cmd,
|
||||
's', 0, 1, 0, 0, aDot, 1, 0, s_cmd,
|
||||
't', 0, 0, 1, 0, aDot, 0, 0, m_cmd,
|
||||
'u', 0, 0, 0, 0, aNo, 2, 0, u_cmd,
|
||||
'v', 0, 1, 0, 'p', aDot, 0, 0, g_cmd,
|
||||
'w', 0, 0, 0, 0, aAll, 0, wordx, w_cmd,
|
||||
'x', 0, 1, 0, 'p', aDot, 0, 0, x_cmd,
|
||||
'y', 0, 1, 0, 'p', aDot, 0, 0, x_cmd,
|
||||
'=', 0, 0, 0, 0, aDot, 0, linex, eq_cmd,
|
||||
'B', 0, 0, 0, 0, aNo, 0, linex, B_cmd,
|
||||
'D', 0, 0, 0, 0, aNo, 0, linex, D_cmd,
|
||||
'X', 0, 1, 0, 'f', aNo, 0, 0, X_cmd,
|
||||
'Y', 0, 1, 0, 'f', aNo, 0, 0, X_cmd,
|
||||
'<', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd,
|
||||
'|', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd,
|
||||
'>', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd,
|
||||
/* deliberately unimplemented:
|
||||
'k', 0, 0, 0, 0, aDot, 0, 0, k_cmd,
|
||||
'n', 0, 0, 0, 0, aNo, 0, 0, n_cmd,
|
||||
'q', 0, 0, 0, 0, aNo, 0, 0, q_cmd,
|
||||
'!', 0, 0, 0, 0, aNo, 0, linex, plan9_cmd,
|
||||
*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
Cmd *parsecmd(int);
|
||||
Addr *compoundaddr(void);
|
||||
Addr *simpleaddr(void);
|
||||
void freecmd(void);
|
||||
void okdelim(int);
|
||||
|
||||
Rune *cmdstartp;
|
||||
Rune *cmdendp;
|
||||
Rune *cmdp;
|
||||
Channel *editerrc;
|
||||
|
||||
String *lastpat;
|
||||
int patset;
|
||||
|
||||
List cmdlist;
|
||||
List addrlist;
|
||||
List stringlist;
|
||||
Text *curtext;
|
||||
int editing = Inactive;
|
||||
|
||||
String* newstring(int);
|
||||
|
||||
void
|
||||
editthread(void *v)
|
||||
{
|
||||
Cmd *cmdp;
|
||||
|
||||
USED(v);
|
||||
threadsetname("editthread");
|
||||
while((cmdp=parsecmd(0)) != 0){
|
||||
// ocurfile = curfile;
|
||||
// loaded = curfile && !curfile->unread;
|
||||
if(cmdexec(curtext, cmdp) == 0)
|
||||
break;
|
||||
freecmd();
|
||||
}
|
||||
sendp(editerrc, nil);
|
||||
}
|
||||
|
||||
void
|
||||
allelogterm(Window *w, void *x)
|
||||
{
|
||||
USED(x);
|
||||
elogterm(w->body.file);
|
||||
}
|
||||
|
||||
void
|
||||
alleditinit(Window *w, void *x)
|
||||
{
|
||||
USED(x);
|
||||
textcommit(&w->tag, TRUE);
|
||||
textcommit(&w->body, TRUE);
|
||||
w->body.file->editclean = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
allupdate(Window *w, void *x)
|
||||
{
|
||||
Text *t;
|
||||
int i;
|
||||
File *f;
|
||||
|
||||
USED(x);
|
||||
t = &w->body;
|
||||
f = t->file;
|
||||
if(f->curtext != t) /* do curtext only */
|
||||
return;
|
||||
if(f->elog.type == Null)
|
||||
elogterm(f);
|
||||
else if(f->elog.type != Empty){
|
||||
elogapply(f);
|
||||
if(f->editclean){
|
||||
f->mod = FALSE;
|
||||
for(i=0; i<f->ntext; i++)
|
||||
f->text[i]->w->dirty = FALSE;
|
||||
}
|
||||
}
|
||||
textsetselect(t, t->q0, t->q1);
|
||||
textscrdraw(t);
|
||||
winsettag(w);
|
||||
}
|
||||
|
||||
void
|
||||
editerror(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char *s;
|
||||
|
||||
va_start(arg, fmt);
|
||||
s = vsmprint(fmt, arg);
|
||||
va_end(arg);
|
||||
freecmd();
|
||||
allwindows(allelogterm, nil); /* truncate the edit logs */
|
||||
sendp(editerrc, s);
|
||||
threadexits(nil);
|
||||
}
|
||||
|
||||
void
|
||||
editcmd(Text *ct, Rune *r, uint n)
|
||||
{
|
||||
char *err;
|
||||
|
||||
if(n == 0)
|
||||
return;
|
||||
if(2*n > RBUFSIZE){
|
||||
warning(nil, "string too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
allwindows(alleditinit, nil);
|
||||
if(cmdstartp)
|
||||
free(cmdstartp);
|
||||
cmdstartp = runemalloc(n+2);
|
||||
runemove(cmdstartp, r, n);
|
||||
if(r[n] != '\n')
|
||||
cmdstartp[n++] = '\n';
|
||||
cmdstartp[n] = '\0';
|
||||
cmdendp = cmdstartp+n;
|
||||
cmdp = cmdstartp;
|
||||
if(ct->w == nil)
|
||||
curtext = nil;
|
||||
else
|
||||
curtext = &ct->w->body;
|
||||
resetxec();
|
||||
if(editerrc == nil){
|
||||
editerrc = chancreate(sizeof(char*), 0);
|
||||
lastpat = allocstring(0);
|
||||
}
|
||||
threadcreate(editthread, nil, STACK);
|
||||
err = recvp(editerrc);
|
||||
editing = Inactive;
|
||||
if(err != nil){
|
||||
if(err[0] != '\0')
|
||||
warning(nil, "Edit: %s\n", err);
|
||||
free(err);
|
||||
}
|
||||
|
||||
/* update everyone whose edit log has data */
|
||||
allwindows(allupdate, nil);
|
||||
}
|
||||
|
||||
int
|
||||
getch(void)
|
||||
{
|
||||
if(*cmdp == *cmdendp)
|
||||
return -1;
|
||||
return *cmdp++;
|
||||
}
|
||||
|
||||
int
|
||||
nextc(void)
|
||||
{
|
||||
if(*cmdp == *cmdendp)
|
||||
return -1;
|
||||
return *cmdp;
|
||||
}
|
||||
|
||||
void
|
||||
ungetch(void)
|
||||
{
|
||||
if(--cmdp < cmdstartp)
|
||||
error("ungetch");
|
||||
}
|
||||
|
||||
long
|
||||
getnum(int signok)
|
||||
{
|
||||
long n;
|
||||
int c, sign;
|
||||
|
||||
n = 0;
|
||||
sign = 1;
|
||||
if(signok>1 && nextc()=='-'){
|
||||
sign = -1;
|
||||
getch();
|
||||
}
|
||||
if((c=nextc())<'0' || '9'<c) /* no number defaults to 1 */
|
||||
return sign;
|
||||
while('0'<=(c=getch()) && c<='9')
|
||||
n = n*10 + (c-'0');
|
||||
ungetch();
|
||||
return sign*n;
|
||||
}
|
||||
|
||||
int
|
||||
cmdskipbl(void)
|
||||
{
|
||||
int c;
|
||||
do
|
||||
c = getch();
|
||||
while(c==' ' || c=='\t');
|
||||
if(c >= 0)
|
||||
ungetch();
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that list has room for one more element.
|
||||
*/
|
||||
void
|
||||
growlist(List *l)
|
||||
{
|
||||
if(l->u.listptr==0 || l->nalloc==0){
|
||||
l->nalloc = INCR;
|
||||
l->u.listptr = emalloc(INCR*sizeof(long));
|
||||
l->nused = 0;
|
||||
}else if(l->nused == l->nalloc){
|
||||
l->u.listptr = erealloc(l->u.listptr, (l->nalloc+INCR)*sizeof(long));
|
||||
memset((void*)(l->u.longptr+l->nalloc), 0, INCR*sizeof(long));
|
||||
l->nalloc += INCR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the ith element from the list
|
||||
*/
|
||||
void
|
||||
dellist(List *l, int i)
|
||||
{
|
||||
memmove(&l->u.longptr[i], &l->u.longptr[i+1], (l->nused-(i+1))*sizeof(long));
|
||||
l->nused--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new element, whose position is i, to the list
|
||||
*/
|
||||
void
|
||||
inslist(List *l, int i, long val)
|
||||
{
|
||||
growlist(l);
|
||||
memmove(&l->u.longptr[i+1], &l->u.longptr[i], (l->nused-i)*sizeof(long));
|
||||
l->u.longptr[i] = val;
|
||||
l->nused++;
|
||||
}
|
||||
|
||||
void
|
||||
listfree(List *l)
|
||||
{
|
||||
free(l->u.listptr);
|
||||
free(l);
|
||||
}
|
||||
|
||||
String*
|
||||
allocstring(int n)
|
||||
{
|
||||
String *s;
|
||||
|
||||
s = emalloc(sizeof(String));
|
||||
s->n = n;
|
||||
s->nalloc = n+10;
|
||||
s->r = emalloc(s->nalloc*sizeof(Rune));
|
||||
s->r[n] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
freestring(String *s)
|
||||
{
|
||||
free(s->r);
|
||||
free(s);
|
||||
}
|
||||
|
||||
Cmd*
|
||||
newcmd(void){
|
||||
Cmd *p;
|
||||
|
||||
p = emalloc(sizeof(Cmd));
|
||||
inslist(&cmdlist, cmdlist.nused, (long)p);
|
||||
return p;
|
||||
}
|
||||
|
||||
String*
|
||||
newstring(int n)
|
||||
{
|
||||
String *p;
|
||||
|
||||
p = allocstring(n);
|
||||
inslist(&stringlist, stringlist.nused, (long)p);
|
||||
return p;
|
||||
}
|
||||
|
||||
Addr*
|
||||
newaddr(void)
|
||||
{
|
||||
Addr *p;
|
||||
|
||||
p = emalloc(sizeof(Addr));
|
||||
inslist(&addrlist, addrlist.nused, (long)p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
freecmd(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
while(cmdlist.nused > 0)
|
||||
free(cmdlist.u.ucharptr[--cmdlist.nused]);
|
||||
while(addrlist.nused > 0)
|
||||
free(addrlist.u.ucharptr[--addrlist.nused]);
|
||||
while(stringlist.nused>0){
|
||||
i = --stringlist.nused;
|
||||
freestring(stringlist.u.stringptr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
okdelim(int c)
|
||||
{
|
||||
if(c=='\\' || ('a'<=c && c<='z')
|
||||
|| ('A'<=c && c<='Z') || ('0'<=c && c<='9'))
|
||||
editerror("bad delimiter %c\n", c);
|
||||
}
|
||||
|
||||
void
|
||||
atnl(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
cmdskipbl();
|
||||
c = getch();
|
||||
if(c != '\n')
|
||||
editerror("newline expected (saw %C)", c);
|
||||
}
|
||||
|
||||
void
|
||||
Straddc(String *s, int c)
|
||||
{
|
||||
if(s->n+1 >= s->nalloc){
|
||||
s->nalloc += 10;
|
||||
s->r = erealloc(s->r, s->nalloc*sizeof(Rune));
|
||||
}
|
||||
s->r[s->n++] = c;
|
||||
s->r[s->n] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
getrhs(String *s, int delim, int cmd)
|
||||
{
|
||||
int c;
|
||||
|
||||
while((c = getch())>0 && c!=delim && c!='\n'){
|
||||
if(c == '\\'){
|
||||
if((c=getch()) <= 0)
|
||||
error("bad right hand side");
|
||||
if(c == '\n'){
|
||||
ungetch();
|
||||
c='\\';
|
||||
}else if(c == 'n')
|
||||
c='\n';
|
||||
else if(c!=delim && (cmd=='s' || c!='\\')) /* s does its own */
|
||||
Straddc(s, '\\');
|
||||
}
|
||||
Straddc(s, c);
|
||||
}
|
||||
ungetch(); /* let client read whether delimiter, '\n' or whatever */
|
||||
}
|
||||
|
||||
String *
|
||||
collecttoken(char *end)
|
||||
{
|
||||
String *s = newstring(0);
|
||||
int c;
|
||||
|
||||
while((c=nextc())==' ' || c=='\t')
|
||||
Straddc(s, getch()); /* blanks significant for getname() */
|
||||
while((c=getch())>0 && utfrune(end, c)==0)
|
||||
Straddc(s, c);
|
||||
if(c != '\n')
|
||||
atnl();
|
||||
return s;
|
||||
}
|
||||
|
||||
String *
|
||||
collecttext(void)
|
||||
{
|
||||
String *s;
|
||||
int begline, i, c, delim;
|
||||
|
||||
s = newstring(0);
|
||||
if(cmdskipbl()=='\n'){
|
||||
getch();
|
||||
i = 0;
|
||||
do{
|
||||
begline = i;
|
||||
while((c = getch())>0 && c!='\n')
|
||||
i++, Straddc(s, c);
|
||||
i++, Straddc(s, '\n');
|
||||
if(c < 0)
|
||||
goto Return;
|
||||
}while(s->r[begline]!='.' || s->r[begline+1]!='\n');
|
||||
s->r[s->n-2] = '\0';
|
||||
}else{
|
||||
okdelim(delim = getch());
|
||||
getrhs(s, delim, 'a');
|
||||
if(nextc()==delim)
|
||||
getch();
|
||||
atnl();
|
||||
}
|
||||
Return:
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
cmdlookup(int c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; cmdtab[i].cmdc; i++)
|
||||
if(cmdtab[i].cmdc == c)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Cmd*
|
||||
parsecmd(int nest)
|
||||
{
|
||||
int i, c;
|
||||
struct cmdtab *ct;
|
||||
Cmd *cp, *ncp;
|
||||
Cmd cmd;
|
||||
|
||||
cmd.next = cmd.u.cmd = 0;
|
||||
cmd.re = 0;
|
||||
cmd.flag = cmd.num = 0;
|
||||
cmd.addr = compoundaddr();
|
||||
if(cmdskipbl() == -1)
|
||||
return 0;
|
||||
if((c=getch())==-1)
|
||||
return 0;
|
||||
cmd.cmdc = c;
|
||||
if(cmd.cmdc=='c' && nextc()=='d'){ /* sleazy two-character case */
|
||||
getch(); /* the 'd' */
|
||||
cmd.cmdc='c'|0x100;
|
||||
}
|
||||
i = cmdlookup(cmd.cmdc);
|
||||
if(i >= 0){
|
||||
if(cmd.cmdc == '\n')
|
||||
goto Return; /* let nl_cmd work it all out */
|
||||
ct = &cmdtab[i];
|
||||
if(ct->defaddr==aNo && cmd.addr)
|
||||
editerror("command takes no address");
|
||||
if(ct->count)
|
||||
cmd.num = getnum(ct->count);
|
||||
if(ct->regexp){
|
||||
/* x without pattern -> .*\n, indicated by cmd.re==0 */
|
||||
/* X without pattern is all files */
|
||||
if((ct->cmdc!='x' && ct->cmdc!='X') ||
|
||||
((c = nextc())!=' ' && c!='\t' && c!='\n')){
|
||||
cmdskipbl();
|
||||
if((c = getch())=='\n' || c<0)
|
||||
editerror("no address");
|
||||
okdelim(c);
|
||||
cmd.re = getregexp(c);
|
||||
if(ct->cmdc == 's'){
|
||||
cmd.u.text = newstring(0);
|
||||
getrhs(cmd.u.text, c, 's');
|
||||
if(nextc() == c){
|
||||
getch();
|
||||
if(nextc() == 'g')
|
||||
cmd.flag = getch();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ct->addr && (cmd.u.mtaddr=simpleaddr())==0)
|
||||
editerror("bad address");
|
||||
if(ct->defcmd){
|
||||
if(cmdskipbl() == '\n'){
|
||||
getch();
|
||||
cmd.u.cmd = newcmd();
|
||||
cmd.u.cmd->cmdc = ct->defcmd;
|
||||
}else if((cmd.u.cmd = parsecmd(nest))==0)
|
||||
error("defcmd");
|
||||
}else if(ct->text)
|
||||
cmd.u.text = collecttext();
|
||||
else if(ct->token)
|
||||
cmd.u.text = collecttoken(ct->token);
|
||||
else
|
||||
atnl();
|
||||
}else
|
||||
switch(cmd.cmdc){
|
||||
case '{':
|
||||
cp = 0;
|
||||
do{
|
||||
if(cmdskipbl()=='\n')
|
||||
getch();
|
||||
ncp = parsecmd(nest+1);
|
||||
if(cp)
|
||||
cp->next = ncp;
|
||||
else
|
||||
cmd.u.cmd = ncp;
|
||||
}while(cp = ncp);
|
||||
break;
|
||||
case '}':
|
||||
atnl();
|
||||
if(nest==0)
|
||||
editerror("right brace with no left brace");
|
||||
return 0;
|
||||
default:
|
||||
editerror("unknown command %c", cmd.cmdc);
|
||||
}
|
||||
Return:
|
||||
cp = newcmd();
|
||||
*cp = cmd;
|
||||
return cp;
|
||||
}
|
||||
|
||||
String*
|
||||
getregexp(int delim)
|
||||
{
|
||||
String *buf, *r;
|
||||
int i, c;
|
||||
|
||||
buf = allocstring(0);
|
||||
for(i=0; ; i++){
|
||||
if((c = getch())=='\\'){
|
||||
if(nextc()==delim)
|
||||
c = getch();
|
||||
else if(nextc()=='\\'){
|
||||
Straddc(buf, c);
|
||||
c = getch();
|
||||
}
|
||||
}else if(c==delim || c=='\n')
|
||||
break;
|
||||
if(i >= RBUFSIZE)
|
||||
editerror("regular expression too long");
|
||||
Straddc(buf, c);
|
||||
}
|
||||
if(c!=delim && c)
|
||||
ungetch();
|
||||
if(buf->n > 0){
|
||||
patset = TRUE;
|
||||
freestring(lastpat);
|
||||
lastpat = buf;
|
||||
}else
|
||||
freestring(buf);
|
||||
if(lastpat->n == 0)
|
||||
editerror("no regular expression defined");
|
||||
r = newstring(lastpat->n);
|
||||
runemove(r->r, lastpat->r, lastpat->n); /* newstring put \0 at end */
|
||||
return r;
|
||||
}
|
||||
|
||||
Addr *
|
||||
simpleaddr(void)
|
||||
{
|
||||
Addr addr;
|
||||
Addr *ap, *nap;
|
||||
|
||||
addr.next = 0;
|
||||
addr.u.left = 0;
|
||||
switch(cmdskipbl()){
|
||||
case '#':
|
||||
addr.type = getch();
|
||||
addr.num = getnum(1);
|
||||
break;
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
addr.num = getnum(1);
|
||||
addr.type='l';
|
||||
break;
|
||||
case '/': case '?': case '"':
|
||||
addr.u.re = getregexp(addr.type = getch());
|
||||
break;
|
||||
case '.':
|
||||
case '$':
|
||||
case '+':
|
||||
case '-':
|
||||
case '\'':
|
||||
addr.type = getch();
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if(addr.next = simpleaddr())
|
||||
switch(addr.next->type){
|
||||
case '.':
|
||||
case '$':
|
||||
case '\'':
|
||||
if(addr.type!='"')
|
||||
case '"':
|
||||
editerror("bad address syntax");
|
||||
break;
|
||||
case 'l':
|
||||
case '#':
|
||||
if(addr.type=='"')
|
||||
break;
|
||||
/* fall through */
|
||||
case '/':
|
||||
case '?':
|
||||
if(addr.type!='+' && addr.type!='-'){
|
||||
/* insert the missing '+' */
|
||||
nap = newaddr();
|
||||
nap->type='+';
|
||||
nap->next = addr.next;
|
||||
addr.next = nap;
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
case '-':
|
||||
break;
|
||||
default:
|
||||
error("simpleaddr");
|
||||
}
|
||||
ap = newaddr();
|
||||
*ap = addr;
|
||||
return ap;
|
||||
}
|
||||
|
||||
Addr *
|
||||
compoundaddr(void)
|
||||
{
|
||||
Addr addr;
|
||||
Addr *ap, *next;
|
||||
|
||||
addr.u.left = simpleaddr();
|
||||
if((addr.type = cmdskipbl())!=',' && addr.type!=';')
|
||||
return addr.u.left;
|
||||
getch();
|
||||
next = addr.next = compoundaddr();
|
||||
if(next && (next->type==',' || next->type==';') && next->u.left==0)
|
||||
editerror("bad address syntax");
|
||||
ap = newaddr();
|
||||
*ap = addr;
|
||||
return ap;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue