15 static char linex[]="\n";
16 static char wordx[]=" \t\n";
17 struct cmdtab cmdtab[]={
18 /* cmdc text regexp addr defcmd defaddr count token fn */
19 '\n', 0, 0, 0, 0, aDot, 0, 0, nl_cmd,
20 'a', 1, 0, 0, 0, aDot, 0, 0, a_cmd,
21 'b', 0, 0, 0, 0, aNo, 0, linex, b_cmd,
22 'c', 1, 0, 0, 0, aDot, 0, 0, c_cmd,
23 'd', 0, 0, 0, 0, aDot, 0, 0, d_cmd,
24 'e', 0, 0, 0, 0, aNo, 0, wordx, e_cmd,
25 'f', 0, 0, 0, 0, aNo, 0, wordx, f_cmd,
26 'g', 0, 1, 0, 'p', aDot, 0, 0, g_cmd,
27 'i', 1, 0, 0, 0, aDot, 0, 0, i_cmd,
28 'm', 0, 0, 1, 0, aDot, 0, 0, m_cmd,
29 'p', 0, 0, 0, 0, aDot, 0, 0, p_cmd,
30 'r', 0, 0, 0, 0, aDot, 0, wordx, e_cmd,
31 's', 0, 1, 0, 0, aDot, 1, 0, s_cmd,
32 't', 0, 0, 1, 0, aDot, 0, 0, m_cmd,
33 'u', 0, 0, 0, 0, aNo, 2, 0, u_cmd,
34 'v', 0, 1, 0, 'p', aDot, 0, 0, g_cmd,
35 'w', 0, 0, 0, 0, aAll, 0, wordx, w_cmd,
36 'x', 0, 1, 0, 'p', aDot, 0, 0, x_cmd,
37 'y', 0, 1, 0, 'p', aDot, 0, 0, x_cmd,
38 '=', 0, 0, 0, 0, aDot, 0, linex, eq_cmd,
39 'B', 0, 0, 0, 0, aNo, 0, linex, B_cmd,
40 'D', 0, 0, 0, 0, aNo, 0, linex, D_cmd,
41 'X', 0, 1, 0, 'f', aNo, 0, 0, X_cmd,
42 'Y', 0, 1, 0, 'f', aNo, 0, 0, X_cmd,
43 '<', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd,
44 '|', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd,
45 '>', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd,
46 /* deliberately unimplemented:
47 'k', 0, 0, 0, 0, aDot, 0, 0, k_cmd,
48 'n', 0, 0, 0, 0, aNo, 0, 0, n_cmd,
49 'q', 0, 0, 0, 0, aNo, 0, 0, q_cmd,
50 '!', 0, 0, 0, 0, aNo, 0, linex, plan9_cmd,
52 0, 0, 0, 0, 0, 0, 0, 0,
56 Addr *compoundaddr(void);
57 Addr *simpleaddr(void);
73 int editing = Inactive;
75 String* newstring(int);
82 threadsetname("editthread");
83 while((cmdp=parsecmd(0)) != 0){
84 // ocurfile = curfile;
85 // loaded = curfile && !curfile->unread;
86 if(cmdexec(curtext, cmdp) == 0)
94 allelogterm(Window *w, void*)
96 elogterm(w->body.file);
100 alleditinit(Window *w, void*)
102 textcommit(&w->tag, TRUE);
103 textcommit(&w->body, TRUE);
104 w->body.file->editclean = FALSE;
108 allupdate(Window *w, void*)
116 if(f->curtext != t) /* do curtext only */
118 if(f->elog.type == Null)
120 else if(f->elog.type != Empty){
124 for(i=0; i<f->ntext; i++)
125 f->text[i]->w->dirty = FALSE;
128 textsetselect(t, t->q0, t->q1);
134 editerror(char *fmt, ...)
140 s = vsmprint(fmt, arg);
143 allwindows(allelogterm, nil); /* truncate the edit logs */
149 editcmd(Text *ct, Rune *r, uint n)
156 warning(nil, "string too long\n");
160 allwindows(alleditinit, nil);
163 cmdstartp = runemalloc(n+2);
164 runemove(cmdstartp, r, n);
166 cmdstartp[n++] = '\n';
168 cmdendp = cmdstartp+n;
173 curtext = &ct->w->body;
176 editerrc = chancreate(sizeof(char*), 0);
177 lastpat = allocstring(0);
179 threadcreate(editthread, nil, STACK);
180 err = recvp(editerrc);
184 warning(nil, "Edit: %s\n", err);
188 /* update everyone whose edit log has data */
189 allwindows(allupdate, nil);
195 if(*cmdp == *cmdendp)
203 if(*cmdp == *cmdendp)
211 if(--cmdp < cmdstartp)
223 if(signok>1 && nextc()=='-'){
227 if((c=nextc())<'0' || '9'<c) /* no number defaults to 1 */
229 while('0'<=(c=getch()) && c<='9')
241 while(c==' ' || c=='\t');
248 * Check that list has room for one more element.
253 if(l->listptr==0 || l->nalloc==0){
255 l->listptr = emalloc(INCR*sizeof(void*));
257 }else if(l->nused == l->nalloc){
258 l->listptr = erealloc(l->listptr, (l->nalloc+INCR)*sizeof(void*));
259 memset(l->ptr+l->nalloc, 0, INCR*sizeof(void*));
265 * Remove the ith element from the list
268 dellist(List *l, int i)
270 memmove(&l->ptr[i], &l->ptr[i+1], (l->nused-(i+1))*sizeof(void*));
275 * Add a new element, whose position is i, to the list
278 inslist(List *l, int i, void *v)
281 memmove(&l->ptr[i+1], &l->ptr[i], (l->nused-i)*sizeof(void*));
298 s = emalloc(sizeof(String));
301 s->r = emalloc(s->nalloc*sizeof(Rune));
307 freestring(String *s)
317 p = emalloc(sizeof(Cmd));
318 inslist(&cmdlist, cmdlist.nused, p);
328 inslist(&stringlist, stringlist.nused, p);
337 p = emalloc(sizeof(Addr));
338 inslist(&addrlist, addrlist.nused, p);
347 while(cmdlist.nused > 0)
348 free(cmdlist.ucharptr[--cmdlist.nused]);
349 while(addrlist.nused > 0)
350 free(addrlist.ucharptr[--addrlist.nused]);
351 while(stringlist.nused>0){
352 i = --stringlist.nused;
353 freestring(stringlist.stringptr[i]);
360 if(c=='\\' || ('a'<=c && c<='z')
361 || ('A'<=c && c<='Z') || ('0'<=c && c<='9'))
362 editerror("bad delimiter %c\n", c);
373 editerror("newline expected (saw %C)", c);
377 Straddc(String *s, int c)
379 if(s->n+1 >= s->nalloc){
381 s->r = erealloc(s->r, s->nalloc*sizeof(Rune));
388 getrhs(String *s, int delim, int cmd)
392 while((c = getch())>0 && c!=delim && c!='\n'){
395 error("bad right hand side");
401 else if(c!=delim && (cmd=='s' || c!='\\')) /* s does its own */
406 ungetch(); /* let client read whether delimiter, '\n' or whatever */
410 collecttoken(char *end)
412 String *s = newstring(0);
415 while((c=nextc())==' ' || c=='\t')
416 Straddc(s, getch()); /* blanks significant for getname() */
417 while((c=getch())>0 && utfrune(end, c)==0)
428 int begline, i, c, delim;
431 if(cmdskipbl()=='\n'){
436 while((c = getch())>0 && c!='\n')
438 i++, Straddc(s, '\n');
441 }while(s->r[begline]!='.' || s->r[begline+1]!='\n');
445 okdelim(delim = getch());
446 getrhs(s, delim, 'a');
460 for(i=0; cmdtab[i].cmdc; i++)
461 if(cmdtab[i].cmdc == c)
474 cmd.next = cmd.cmd = 0;
476 cmd.flag = cmd.num = 0;
477 cmd.addr = compoundaddr();
478 if(cmdskipbl() == -1)
483 if(cmd.cmdc=='c' && nextc()=='d'){ /* sleazy two-character case */
484 getch(); /* the 'd' */
487 i = cmdlookup(cmd.cmdc);
490 goto Return; /* let nl_cmd work it all out */
492 if(ct->defaddr==aNo && cmd.addr)
493 editerror("command takes no address");
495 cmd.num = getnum(ct->count);
497 /* x without pattern -> .*\n, indicated by cmd.re==0 */
498 /* X without pattern is all files */
499 if((ct->cmdc!='x' && ct->cmdc!='X') ||
500 ((c = nextc())!=' ' && c!='\t' && c!='\n')){
502 if((c = getch())=='\n' || c<0)
503 editerror("no address");
505 cmd.re = getregexp(c);
507 cmd.text = newstring(0);
508 getrhs(cmd.text, c, 's');
518 if(ct->addr && (cmd.mtaddr=simpleaddr())==0)
519 editerror("bad address");
521 if(cmdskipbl() == '\n'){
524 cmd.cmd->cmdc = ct->defcmd;
525 }else if((cmd.cmd = parsecmd(nest))==0)
528 cmd.text = collecttext();
530 cmd.text = collecttoken(ct->token);
538 if(cmdskipbl()=='\n')
540 ncp = parsecmd(nest+1);
550 editerror("right brace with no left brace");
553 editerror("unknown command %c", cmd.cmdc);
567 buf = allocstring(0);
569 if((c = getch())=='\\'){
572 else if(nextc()=='\\'){
576 }else if(c==delim || c=='\n')
579 editerror("regular expression too long");
591 editerror("no regular expression defined");
592 r = newstring(lastpat->n);
593 runemove(r->r, lastpat->r, lastpat->n); /* newstring put \0 at end */
608 addr.num = getnum(1);
610 case '0': case '1': case '2': case '3': case '4':
611 case '5': case '6': case '7': case '8': case '9':
612 addr.num = getnum(1);
615 case '/': case '?': case '"':
616 addr.re = getregexp(addr.type = getch());
628 if(addr.next = simpleaddr())
629 switch(addr.next->type){
635 editerror("bad address syntax");
644 if(addr.type!='+' && addr.type!='-'){
645 /* insert the missing '+' */
648 nap->next = addr.next;
669 addr.left = simpleaddr();
670 if((addr.type = cmdskipbl())!=',' && addr.type!=';')
673 next = addr.next = compoundaddr();
674 if(next && (next->type==',' || next->type==';') && next->left==0)
675 editerror("bad address syntax");