123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679 |
- #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*)
- {
- Cmd *cmdp;
- 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*)
- {
- elogterm(w->body.file);
- }
- void
- alleditinit(Window *w, void*)
- {
- textcommit(&w->tag, TRUE);
- textcommit(&w->body, TRUE);
- w->body.file->editclean = FALSE;
- }
- void
- allupdate(Window *w, void*)
- {
- Text *t;
- int i;
- File *f;
- 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->listptr==0 || l->nalloc==0){
- l->nalloc = INCR;
- l->listptr = emalloc(INCR*sizeof(void*));
- l->nused = 0;
- }else if(l->nused == l->nalloc){
- l->listptr = erealloc(l->listptr, (l->nalloc+INCR)*sizeof(void*));
- memset(l->ptr+l->nalloc, 0, INCR*sizeof(void*));
- l->nalloc += INCR;
- }
- }
- /*
- * Remove the ith element from the list
- */
- void
- dellist(List *l, int i)
- {
- memmove(&l->ptr[i], &l->ptr[i+1], (l->nused-(i+1))*sizeof(void*));
- l->nused--;
- }
- /*
- * Add a new element, whose position is i, to the list
- */
- void
- inslist(List *l, int i, void *v)
- {
- growlist(l);
- memmove(&l->ptr[i+1], &l->ptr[i], (l->nused-i)*sizeof(void*));
- l->ptr[i] = v;
- l->nused++;
- }
- void
- listfree(List *l)
- {
- free(l->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, p);
- return p;
- }
- String*
- newstring(int n)
- {
- String *p;
- p = allocstring(n);
- inslist(&stringlist, stringlist.nused, p);
- return p;
- }
- Addr*
- newaddr(void)
- {
- Addr *p;
- p = emalloc(sizeof(Addr));
- inslist(&addrlist, addrlist.nused, p);
- return p;
- }
- void
- freecmd(void)
- {
- int i;
- while(cmdlist.nused > 0)
- free(cmdlist.ucharptr[--cmdlist.nused]);
- while(addrlist.nused > 0)
- free(addrlist.ucharptr[--addrlist.nused]);
- while(stringlist.nused>0){
- i = --stringlist.nused;
- freestring(stringlist.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';
- s->n -= 2;
- }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.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.text = newstring(0);
- getrhs(cmd.text, c, 's');
- if(nextc() == c){
- getch();
- if(nextc() == 'g')
- cmd.flag = getch();
- }
-
- }
- }
- }
- if(ct->addr && (cmd.mtaddr=simpleaddr())==0)
- editerror("bad address");
- if(ct->defcmd){
- if(cmdskipbl() == '\n'){
- getch();
- cmd.cmd = newcmd();
- cmd.cmd->cmdc = ct->defcmd;
- }else if((cmd.cmd = parsecmd(nest))==0)
- error("defcmd");
- }else if(ct->text)
- cmd.text = collecttext();
- else if(ct->token)
- cmd.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.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.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.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.left = simpleaddr();
- if((addr.type = cmdskipbl())!=',' && addr.type!=';')
- return addr.left;
- getch();
- next = addr.next = compoundaddr();
- if(next && (next->type==',' || next->type==';') && next->left==0)
- editerror("bad address syntax");
- ap = newaddr();
- *ap = addr;
- return ap;
- }
|