]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/sam/cmd.c
realemu: implement IDIV, mark 0xE0000 writeable, fix DIV overfow trap
[plan9front.git] / sys / src / cmd / sam / cmd.c
1 #include "sam.h"
2 #include "parse.h"
3
4 static char     linex[]="\n";
5 static char     wordx[]=" \t\n";
6 Cmdtab cmdtab[]={
7 /*      cmdc    text    regexp  addr    defcmd  defaddr count   token    fn     */
8         '\n',   0,      0,      0,      0,      aDot,   0,      0,      nl_cmd,
9         'a',    1,      0,      0,      0,      aDot,   0,      0,      a_cmd,
10         'b',    0,      0,      0,      0,      aNo,    0,      linex,  b_cmd,
11         'B',    0,      0,      0,      0,      aNo,    0,      linex,  b_cmd,
12         'c',    1,      0,      0,      0,      aDot,   0,      0,      c_cmd,
13         'd',    0,      0,      0,      0,      aDot,   0,      0,      d_cmd,
14         'D',    0,      0,      0,      0,      aNo,    0,      linex,  D_cmd,
15         'e',    0,      0,      0,      0,      aNo,    0,      wordx,  e_cmd,
16         'f',    0,      0,      0,      0,      aNo,    0,      wordx,  f_cmd,
17         'g',    0,      1,      0,      'p',    aDot,   0,      0,      g_cmd,
18         'i',    1,      0,      0,      0,      aDot,   0,      0,      i_cmd,
19         'k',    0,      0,      0,      0,      aDot,   0,      0,      k_cmd,
20         'm',    0,      0,      1,      0,      aDot,   0,      0,      m_cmd,
21         'n',    0,      0,      0,      0,      aNo,    0,      0,      n_cmd,
22         'p',    0,      0,      0,      0,      aDot,   0,      0,      p_cmd,
23         'q',    0,      0,      0,      0,      aNo,    0,      0,      q_cmd,
24         'r',    0,      0,      0,      0,      aDot,   0,      wordx,  e_cmd,
25         's',    0,      1,      0,      0,      aDot,   1,      0,      s_cmd,
26         't',    0,      0,      1,      0,      aDot,   0,      0,      m_cmd,
27         'u',    0,      0,      0,      0,      aNo,    2,      0,      u_cmd,
28         'v',    0,      1,      0,      'p',    aDot,   0,      0,      g_cmd,
29         'w',    0,      0,      0,      0,      aAll,   0,      wordx,  w_cmd,
30         'x',    0,      1,      0,      'p',    aDot,   0,      0,      x_cmd,
31         'y',    0,      1,      0,      'p',    aDot,   0,      0,      x_cmd,
32         'X',    0,      1,      0,      'f',    aNo,    0,      0,      X_cmd,
33         'Y',    0,      1,      0,      'f',    aNo,    0,      0,      X_cmd,
34         '!',    0,      0,      0,      0,      aNo,    0,      linex,  plan9_cmd,
35         '>',    0,      0,      0,      0,      aDot,   0,      linex,  plan9_cmd,
36         '<',    0,      0,      0,      0,      aDot,   0,      linex,  plan9_cmd,
37         '|',    0,      0,      0,      0,      aDot,   0,      linex,  plan9_cmd,
38         '=',    0,      0,      0,      0,      aDot,   0,      linex,  eq_cmd,
39         'c'|0x100,0,    0,      0,      0,      aNo,    0,      wordx,  cd_cmd,
40         0,      0,      0,      0,      0,      0,      0,      0,
41 };
42 Cmd     *parsecmd(int);
43 Addr    *compoundaddr(void);
44 Addr    *simpleaddr(void);
45 void    freecmd(void);
46 void    okdelim(int);
47
48 Rune    line[BLOCKSIZE];
49 Rune    termline[BLOCKSIZE];
50 Rune    *linep = line;
51 Rune    *terminp = termline;
52 Rune    *termoutp = termline;
53
54 List    cmdlist = { 'p' };
55 List    addrlist = { 'p' };
56 List    relist = { 'p' };
57 List    stringlist = { 'p' };
58
59 int     eof;
60
61 void
62 resetcmd(void)
63 {
64         linep = line;
65         *linep = 0;
66         terminp = termoutp = termline;
67         freecmd();
68 }
69
70 int
71 inputc(void)
72 {
73         int n, nbuf;
74         char buf[UTFmax];
75         Rune r;
76
77     Again:
78         nbuf = 0;
79         if(downloaded){
80                 while(termoutp == terminp){
81                         cmdupdate();
82                         if(patset)
83                                 tellpat();
84                         while(termlocked > 0){
85                                 outT0(Hunlock);
86                                 termlocked--;
87                         }
88                         if(rcv() == 0)
89                                 return -1;
90                 }
91                 r = *termoutp++;
92                 if(termoutp == terminp)
93                         terminp = termoutp = termline;
94         }else{
95                 do{
96                         n = read(0, buf+nbuf, 1);
97                         if(n <= 0)
98                                 return -1;
99                         nbuf += n;
100                 }while(!fullrune(buf, nbuf));
101                 chartorune(&r, buf);
102         }
103         if(r == 0){
104                 warn(Wnulls);
105                 goto Again;
106         }
107         return r;
108 }
109
110 int
111 inputline(void)
112 {
113         int i, c, start;
114
115         /*
116          * Could set linep = line and i = 0 here and just
117          * error(Etoolong) below, but this way we keep
118          * old input buffer history around for a while.
119          * This is useful only for debugging.
120          */
121         i = linep - line;
122         do{
123                 if((c = inputc())<=0)
124                         return -1;
125                 if(i == nelem(line)-1){
126                         if(linep == line)
127                                 error(Etoolong);
128                         start = linep - line;
129                         runemove(line, linep, i-start);
130                         i -= start;
131                         linep = line;
132                 }
133         }while((line[i++]=c) != '\n');
134         line[i] = 0;
135         return 1;
136 }
137
138 int
139 getch(void)
140 {
141         if(eof)
142                 return -1;
143         if(*linep==0 && inputline()<0){
144                 eof = TRUE;
145                 return -1;
146         }
147         return *linep++;
148 }
149
150 int
151 nextc(void)
152 {
153         if(*linep == 0)
154                 return -1;
155         return *linep;
156 }
157
158 void
159 ungetch(void)
160 {
161         if(--linep < line)
162                 panic("ungetch");
163 }
164
165 Posn
166 getnum(int signok)
167 {
168         Posn n=0;
169         int c, sign;
170
171         sign = 1;
172         if(signok>1 && nextc()=='-'){
173                 sign = -1;
174                 getch();
175         }
176         if((c=nextc())<'0' || '9'<c)    /* no number defaults to 1 */
177                 return sign;
178         while('0'<=(c=getch()) && c<='9')
179                 n = n*10 + (c-'0');
180         ungetch();
181         return sign*n;
182 }
183
184 int
185 skipbl(void)
186 {
187         int c;
188         do
189                 c = getch();
190         while(c==' ' || c=='\t');
191         if(c >= 0)
192                 ungetch();
193         return c;
194 }
195
196 void
197 termcommand(void)
198 {
199         Posn p;
200
201         for(p=cmdpt; p<cmd->nc; p++){
202                 if(terminp >= termline+nelem(termline)){
203                         cmdpt = cmd->nc;
204                         error(Etoolong);
205                 }
206                 *terminp++ = filereadc(cmd, p);
207         }
208         cmdpt = cmd->nc;
209 }
210
211 void
212 cmdloop(void)
213 {
214         Cmd *cmdp;
215         File *ocurfile;
216         int loaded;
217
218         for(;;){
219                 if(!downloaded && curfile && curfile->unread)
220                         load(curfile);
221                 if((cmdp = parsecmd(0))==0){
222                         if(downloaded){
223                                 rescue();
224                                 exits("eof");
225                         }
226                         break;
227                 }
228                 ocurfile = curfile;
229                 loaded = curfile && !curfile->unread;
230                 if(cmdexec(curfile, cmdp) == 0)
231                         break;
232                 freecmd();
233                 cmdupdate();
234                 update();
235                 if(downloaded && curfile &&
236                     (ocurfile!=curfile || (!loaded && !curfile->unread)))
237                         outTs(Hcurrent, curfile->tag);
238                         /* don't allow type ahead on files that aren't bound */
239                 if(downloaded && curfile && curfile->rasp == 0)
240                         terminp = termoutp;
241         }
242 }
243
244 Cmd *
245 newcmd(void){
246         Cmd *p;
247
248         p = emalloc(sizeof(Cmd));
249         inslist(&cmdlist, cmdlist.nused, p);
250         return p;
251 }
252
253 Addr*
254 newaddr(void)
255 {
256         Addr *p;
257
258         p = emalloc(sizeof(Addr));
259         inslist(&addrlist, addrlist.nused, p);
260         return p;
261 }
262
263 String*
264 newre(void)
265 {
266         String *p;
267
268         p = emalloc(sizeof(String));
269         inslist(&relist, relist.nused, p);
270         Strinit(p);
271         return p;
272 }
273
274 String*
275 newstring(void)
276 {
277         String *p;
278
279         p = emalloc(sizeof(String));
280         inslist(&stringlist, stringlist.nused, p);
281         Strinit(p);
282         return p;
283 }
284
285 void
286 freecmd(void)
287 {
288         int i;
289
290         while(cmdlist.nused > 0)
291                 free(cmdlist.voidpptr[--cmdlist.nused]);
292         while(addrlist.nused > 0)
293                 free(addrlist.voidpptr[--addrlist.nused]);
294         while(relist.nused > 0){
295                 i = --relist.nused;
296                 Strclose(relist.stringpptr[i]);
297                 free(relist.stringpptr[i]);
298         }
299         while(stringlist.nused>0){
300                 i = --stringlist.nused;
301                 Strclose(stringlist.stringpptr[i]);
302                 free(stringlist.stringpptr[i]);
303         }
304 }
305
306 int
307 lookup(int c)
308 {
309         int i;
310
311         for(i=0; cmdtab[i].cmdc; i++)
312                 if(cmdtab[i].cmdc == c)
313                         return i;
314         return -1;
315 }
316
317 void
318 okdelim(int c)
319 {
320         if(c=='\\' || ('a'<=c && c<='z')
321         || ('A'<=c && c<='Z') || ('0'<=c && c<='9'))
322                 error_c(Edelim, c);
323 }
324
325 void
326 atnl(void)
327 {
328         skipbl();
329         if(getch() != '\n')
330                 error(Enewline);
331 }
332
333 void
334 getrhs(String *s, int delim, int cmd)
335 {
336         int c;
337
338         while((c = getch())>0 && c!=delim && c!='\n'){
339                 if(c == '\\'){
340                         if((c=getch()) <= 0)
341                                 error(Ebadrhs);
342                         if(c == '\n'){
343                                 ungetch();
344                                 c='\\';
345                         }else if(c == 'n')
346                                 c='\n';
347                         else if(c!=delim && (cmd=='s' || c!='\\'))      /* s does its own */
348                                 Straddc(s, '\\');
349                 }
350                 Straddc(s, c);
351         }
352         ungetch();      /* let client read whether delimeter, '\n' or whatever */
353 }
354
355 String *
356 collecttoken(char *end)
357 {
358         String *s = newstring();
359         int c;
360
361         while((c=nextc())==' ' || c=='\t')
362                 Straddc(s, getch()); /* blanks significant for getname() */
363         while((c=getch())>0 && utfrune(end, c)==0)
364                 Straddc(s, c);
365         Straddc(s, 0);
366         if(c != '\n')
367                 atnl();
368         return s;
369 }
370
371 String *
372 collecttext(void)
373 {
374         String *s = newstring();
375         int begline, i, c, delim;
376
377         if(skipbl()=='\n'){
378                 getch();
379                 i = 0;
380                 do{
381                         begline = i;
382                         while((c = getch())>0 && c!='\n')
383                                 i++, Straddc(s, c);
384                         i++, Straddc(s, '\n');
385                         if(c < 0)
386                                 goto Return;
387                 }while(s->s[begline]!='.' || s->s[begline+1]!='\n');
388                 Strdelete(s, s->n-2, s->n);
389         }else{
390                 okdelim(delim = getch());
391                 getrhs(s, delim, 'a');
392                 if(nextc()==delim)
393                         getch();
394                 atnl();
395         }
396     Return:
397         Straddc(s, 0);          /* JUST FOR CMDPRINT() */
398         return s;
399 }
400
401 Cmd *
402 parsecmd(int nest)
403 {
404         int i, c;
405         Cmdtab *ct;
406         Cmd *cp, *ncp;
407         Cmd cmd;
408
409         cmd.next = cmd.ccmd = 0;
410         cmd.re = 0;
411         cmd.flag = cmd.num = 0;
412         cmd.addr = compoundaddr();
413         if(skipbl() == -1)
414                 return 0;
415         if((c=getch())==-1)
416                 return 0;
417         cmd.cmdc = c;
418         if(cmd.cmdc=='c' && nextc()=='d'){      /* sleazy two-character case */
419                 getch();                /* the 'd' */
420                 cmd.cmdc='c'|0x100;
421         }
422         i = lookup(cmd.cmdc);
423         if(i >= 0){
424                 if(cmd.cmdc == '\n')
425                         goto Return;    /* let nl_cmd work it all out */
426                 ct = &cmdtab[i];
427                 if(ct->defaddr==aNo && cmd.addr)
428                         error(Enoaddr);
429                 if(ct->count)
430                         cmd.num = getnum(ct->count);
431                 if(ct->regexp){
432                         /* x without pattern -> .*\n, indicated by cmd.re==0 */
433                         /* X without pattern is all files */
434                         if((ct->cmdc!='x' && ct->cmdc!='X') ||
435                            ((c = nextc())!=' ' && c!='\t' && c!='\n')){
436                                 skipbl();
437                                 if((c = getch())=='\n' || c<0)
438                                         error(Enopattern);
439                                 okdelim(c);
440                                 cmd.re = getregexp(c);
441                                 if(ct->cmdc == 's'){
442                                         cmd.ctext = newstring();
443                                         getrhs(cmd.ctext, c, 's');
444                                         if(nextc() == c){
445                                                 getch();
446                                                 if(nextc() == 'g')
447                                                         cmd.flag = getch();
448                                         }
449                         
450                                 }
451                         }
452                 }
453                 if(ct->addr && (cmd.caddr=simpleaddr())==0)
454                         error(Eaddress);
455                 if(ct->defcmd){
456                         if(skipbl() == '\n'){
457                                 getch();
458                                 cmd.ccmd = newcmd();
459                                 cmd.ccmd->cmdc = ct->defcmd;
460                         }else if((cmd.ccmd = parsecmd(nest))==0)
461                                 panic("defcmd");
462                 }else if(ct->text)
463                         cmd.ctext = collecttext();
464                 else if(ct->token)
465                         cmd.ctext = collecttoken(ct->token);
466                 else
467                         atnl();
468         }else
469                 switch(cmd.cmdc){
470                 case '{':
471                         cp = 0;
472                         do{
473                                 if(skipbl()=='\n')
474                                         getch();
475                                 ncp = parsecmd(nest+1);
476                                 if(cp)
477                                         cp->next = ncp;
478                                 else
479                                         cmd.ccmd = ncp;
480                         }while(cp = ncp);
481                         break;
482                 case '}':
483                         atnl();
484                         if(nest==0)
485                                 error(Enolbrace);
486                         return 0;
487                 default:
488                         error_c(Eunk, cmd.cmdc);
489                 }
490     Return:
491         cp = newcmd();
492         *cp = cmd;
493         return cp;
494 }
495
496 String*                         /* BUGGERED */
497 getregexp(int delim)
498 {
499         String *r = newre();
500         int c;
501
502         for(Strzero(&genstr); ; Straddc(&genstr, c))
503                 if((c = getch())=='\\'){
504                         if(nextc()==delim)
505                                 c = getch();
506                         else if(nextc()=='\\'){
507                                 Straddc(&genstr, c);
508                                 c = getch();
509                         }
510                 }else if(c==delim || c=='\n')
511                         break;
512         if(c!=delim && c)
513                 ungetch();
514         if(genstr.n > 0){
515                 patset = TRUE;
516                 Strduplstr(&lastpat, &genstr);
517                 Straddc(&lastpat, '\0');
518         }
519         if(lastpat.n <= 1)
520                 error(Epattern);
521         Strduplstr(r, &lastpat);
522         return r;
523 }
524
525 Addr *
526 simpleaddr(void)
527 {
528         Addr addr;
529         Addr *ap, *nap;
530
531         addr.next = 0;
532         addr.left = 0;
533         switch(skipbl()){
534         case '#':
535                 addr.type = getch();
536                 addr.num = getnum(1);
537                 break;
538         case '0': case '1': case '2': case '3': case '4':
539         case '5': case '6': case '7': case '8': case '9': 
540                 addr.num = getnum(1);
541                 addr.type='l';
542                 break;
543         case '/': case '?': case '"':
544                 addr.are = getregexp(addr.type = getch());
545                 break;
546         case '.':
547         case '$':
548         case '+':
549         case '-':
550         case '\'':
551                 addr.type = getch();
552                 break;
553         default:
554                 return 0;
555         }
556         if(addr.next = simpleaddr())
557                 switch(addr.next->type){
558                 case '.':
559                 case '$':
560                 case '\'':
561                         if(addr.type!='"')
562                 case '"':
563                                 error(Eaddress);
564                         break;
565                 case 'l':
566                 case '#':
567                         if(addr.type=='"')
568                                 break;
569                         /* fall through */
570                 case '/':
571                 case '?':
572                         if(addr.type!='+' && addr.type!='-'){
573                                 /* insert the missing '+' */
574                                 nap = newaddr();
575                                 nap->type='+';
576                                 nap->next = addr.next;
577                                 addr.next = nap;
578                         }
579                         break;
580                 case '+':
581                 case '-':
582                         break;
583                 default:
584                         panic("simpleaddr");
585                 }
586         ap = newaddr();
587         *ap = addr;
588         return ap;
589 }
590
591 Addr *
592 compoundaddr(void)
593 {
594         Addr addr;
595         Addr *ap, *next;
596
597         addr.left = simpleaddr();
598         if((addr.type = skipbl())!=',' && addr.type!=';')
599                 return addr.left;
600         getch();
601         next = addr.next = compoundaddr();
602         if(next && (next->type==',' || next->type==';') && next->left==0)
603                 error(Eaddress);
604         ap = newaddr();
605         *ap = addr;
606         return ap;
607 }