]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rc/code.c
disk/format: implement long name support
[plan9front.git] / sys / src / cmd / rc / code.c
1 #include "rc.h"
2 #include "io.h"
3 #include "exec.h"
4 #include "fns.h"
5 #include "getflags.h"
6 #define c0      t->child[0]
7 #define c1      t->child[1]
8 #define c2      t->child[2]
9 int codep, ncode;
10 #define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
11 #define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
12 #define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
13 void stuffdot(int);
14 char *fnstr(tree*);
15 void outcode(tree*, int);
16 void codeswitch(tree*, int);
17 int iscase(tree*);
18 code *codecopy(code*);
19 void codefree(code*);
20
21 int
22 morecode(void)
23 {
24         ncode+=100;
25         codebuf = (code *)erealloc((char *)codebuf, ncode*sizeof codebuf[0]);
26         return 0;
27 }
28
29 void
30 stuffdot(int a)
31 {
32         if(a<0 || codep<=a)
33                 panic("Bad address %d in stuffdot", a);
34         codebuf[a].i = codep;
35 }
36
37 int
38 compile(tree *t)
39 {
40         ncode = 100;
41         codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
42         codep = 0;
43         emiti(0);                       /* reference count */
44         outcode(t, flag['e']?1:0);
45         if(nerror){
46                 free(codebuf);
47                 return 0;
48         }
49         readhere();
50         emitf(Xreturn);
51         emitf(0);
52         return 1;
53 }
54
55 void
56 cleanhere(char *f)
57 {
58         emitf(Xdelhere);
59         emits(estrdup(f));
60 }
61
62 char*
63 fnstr(tree *t)
64 {
65         io *f = openstr();
66         void *v;
67         extern char nl;
68         char svnl = nl;
69
70         nl = ';';
71         pfmt(f, "%t", t);
72         nl = svnl;
73         v = f->strp;
74         f->strp = 0;
75         closeio(f);
76         return v;
77 }
78
79 void
80 outcode(tree *t, int eflag)
81 {
82         int p, q;
83         tree *tt;
84         if(t==0)
85                 return;
86         if(t->type!=NOT && t->type!=';')
87                 runq->iflast = 0;
88         switch(t->type){
89         default:
90                 pfmt(err, "bad type %d in outcode\n", t->type);
91                 break;
92         case '$':
93                 emitf(Xmark);
94                 outcode(c0, eflag);
95                 emitf(Xdol);
96                 break;
97         case '"':
98                 emitf(Xmark);
99                 emitf(Xmark);
100                 outcode(c0, eflag);
101                 emitf(Xdol);
102                 emitf(Xqw);
103                 break;
104         case SUB:
105                 emitf(Xmark);
106                 outcode(c0, eflag);
107                 emitf(Xmark);
108                 outcode(c1, eflag);
109                 emitf(Xsub);
110                 break;
111         case '&':
112                 emitf(Xasync);
113                 p = emiti(0);
114                 outcode(c0, eflag);
115                 emitf(Xexit);
116                 stuffdot(p);
117                 break;
118         case ';':
119                 outcode(c0, eflag);
120                 outcode(c1, eflag);
121                 break;
122         case '^':
123                 emitf(Xmark);
124                 outcode(c1, eflag);
125                 emitf(Xmark);
126                 outcode(c0, eflag);
127                 emitf(Xconc);
128                 break;
129         case '`':
130                 emitf(Xmark);
131                 if(c0){
132                         outcode(c0, 0);
133                         emitf(Xglob);
134                 } else {
135                         emitf(Xmark);
136                         emitf(Xword);
137                         emits(estrdup("ifs"));
138                         emitf(Xdol);
139                 }
140                 emitf(Xbackq);
141                 p = emiti(0);
142                 outcode(c1, 0);
143                 emitf(Xexit);
144                 stuffdot(p);
145                 break;
146         case ANDAND:
147                 outcode(c0, 0);
148                 emitf(Xtrue);
149                 p = emiti(0);
150                 outcode(c1, eflag);
151                 stuffdot(p);
152                 break;
153         case ARGLIST:
154                 outcode(c1, eflag);
155                 outcode(c0, eflag);
156                 break;
157         case BANG:
158                 outcode(c0, eflag);
159                 emitf(Xbang);
160                 break;
161         case PCMD:
162         case BRACE:
163                 outcode(c0, eflag);
164                 break;
165         case COUNT:
166                 emitf(Xmark);
167                 outcode(c0, eflag);
168                 emitf(Xcount);
169                 break;
170         case FN:
171                 emitf(Xmark);
172                 outcode(c0, eflag);
173                 if(c1){
174                         emitf(Xfn);
175                         p = emiti(0);
176                         emits(fnstr(c1));
177                         outcode(c1, eflag);
178                         emitf(Xunlocal);        /* get rid of $* */
179                         emitf(Xreturn);
180                         stuffdot(p);
181                 }
182                 else
183                         emitf(Xdelfn);
184                 break;
185         case IF:
186                 outcode(c0, 0);
187                 emitf(Xif);
188                 p = emiti(0);
189                 outcode(c1, eflag);
190                 emitf(Xwastrue);
191                 stuffdot(p);
192                 break;
193         case NOT:
194                 if(!runq->iflast)
195                         yyerror("`if not' does not follow `if(...)'");
196                 emitf(Xifnot);
197                 p = emiti(0);
198                 outcode(c0, eflag);
199                 stuffdot(p);
200                 break;
201         case OROR:
202                 outcode(c0, 0);
203                 emitf(Xfalse);
204                 p = emiti(0);
205                 outcode(c1, eflag);
206                 stuffdot(p);
207                 break;
208         case PAREN:
209                 outcode(c0, eflag);
210                 break;
211         case SIMPLE:
212                 emitf(Xmark);
213                 outcode(c0, eflag);
214                 emitf(Xsimple);
215                 if(eflag)
216                         emitf(Xeflag);
217                 break;
218         case SUBSHELL:
219                 emitf(Xsubshell);
220                 p = emiti(0);
221                 outcode(c0, eflag);
222                 emitf(Xexit);
223                 stuffdot(p);
224                 if(eflag)
225                         emitf(Xeflag);
226                 break;
227         case SWITCH:
228                 codeswitch(t, eflag);
229                 break;
230         case TWIDDLE:
231                 emitf(Xmark);
232                 outcode(c1, eflag);
233                 emitf(Xmark);
234                 outcode(c0, eflag);
235                 emitf(Xmatch);
236                 if(eflag)
237                         emitf(Xeflag);
238                 break;
239         case WHILE:
240                 q = codep;
241                 outcode(c0, 0);
242                 if(q==codep)
243                         emitf(Xsettrue);        /* empty condition == while(true) */
244                 emitf(Xtrue);
245                 p = emiti(0);
246                 outcode(c1, eflag);
247                 emitf(Xjump);
248                 emiti(q);
249                 stuffdot(p);
250                 break;
251         case WORDS:
252                 outcode(c1, eflag);
253                 outcode(c0, eflag);
254                 break;
255         case FOR:
256                 emitf(Xmark);
257                 if(c1){
258                         outcode(c1, eflag);
259                         emitf(Xglob);
260                 }
261                 else{
262                         emitf(Xmark);
263                         emitf(Xword);
264                         emits(estrdup("*"));
265                         emitf(Xdol);
266                 }
267                 emitf(Xmark);           /* dummy value for Xlocal */
268                 emitf(Xmark);
269                 outcode(c0, eflag);
270                 emitf(Xlocal);
271                 p = emitf(Xfor);
272                 q = emiti(0);
273                 outcode(c2, eflag);
274                 emitf(Xjump);
275                 emiti(p);
276                 stuffdot(q);
277                 emitf(Xunlocal);
278                 break;
279         case WORD:
280                 if(t->quoted){
281                         emitf(Xword);
282                         emits(estrdup(t->str));
283                 } else {
284                         if((q = Globsize(t->str)) > 0){
285                                 emitf(Xglobs);
286                                 emits(estrdup(t->str));
287                                 emiti(q);
288                         } else {
289                                 emitf(Xword);
290                                 emits(deglob(estrdup(t->str)));
291                         }
292                 }
293                 break;
294         case DUP:
295                 if(t->rtype==DUPFD){
296                         emitf(Xdup);
297                         emiti(t->fd0);
298                         emiti(t->fd1);
299                 }
300                 else{
301                         emitf(Xclose);
302                         emiti(t->fd0);
303                 }
304                 outcode(c1, eflag);
305                 emitf(Xpopredir);
306                 break;
307         case PIPEFD:
308                 emitf(Xpipefd);
309                 emiti(t->rtype);
310                 p = emiti(0);
311                 outcode(c0, eflag);
312                 emitf(Xexit);
313                 stuffdot(p);
314                 break;
315         case REDIR:
316                 emitf(Xmark);
317                 outcode(c0, eflag);
318                 emitf(Xglob);
319                 switch(t->rtype){
320                 case APPEND:
321                         emitf(Xappend);
322                         break;
323                 case WRITE:
324                         emitf(Xwrite);
325                         break;
326                 case READ:
327                 case HERE:
328                         emitf(Xread);
329                         break;
330                 case RDWR:
331                         emitf(Xrdwr);
332                         break;
333                 }
334                 emiti(t->fd0);
335                 outcode(c1, eflag);
336                 emitf(Xpopredir);
337                 break;
338         case '=':
339                 tt = t;
340                 for(;t && t->type=='=';t = c2);
341                 if(t){                                  /* var=value cmd */
342                         for(t = tt;t->type=='=';t = c2){
343                                 emitf(Xmark);
344                                 outcode(c1, eflag);
345                                 emitf(Xmark);
346                                 outcode(c0, eflag);
347                                 emitf(Xlocal);          /* push var for cmd */
348                         }
349                         outcode(t, eflag);              /* gen. code for cmd */
350                         for(t = tt; t->type == '='; t = c2)
351                                 emitf(Xunlocal);        /* pop var */
352                 }
353                 else{                                   /* var=value */
354                         for(t = tt;t;t = c2){
355                                 emitf(Xmark);
356                                 outcode(c1, eflag);
357                                 emitf(Xmark);
358                                 outcode(c0, eflag);
359                                 emitf(Xassign); /* set var permanently */
360                         }
361                 }
362                 t = tt; /* so tests below will work */
363                 break;
364         case PIPE:
365                 emitf(Xpipe);
366                 emiti(t->fd0);
367                 emiti(t->fd1);
368                 p = emiti(0);
369                 q = emiti(0);
370                 outcode(c0, eflag);
371                 emitf(Xexit);
372                 stuffdot(p);
373                 outcode(c1, eflag);
374                 emitf(Xreturn);
375                 stuffdot(q);
376                 emitf(Xpipewait);
377                 break;
378         }
379         if(t->type!=NOT && t->type!=';')
380                 runq->iflast = t->type==IF;
381         else if(c0) runq->iflast = c0->type==IF;
382 }
383 /*
384  * switch code looks like this:
385  *      Xmark
386  *      (get switch value)
387  *      Xjump   1f
388  * out: Xjump   leave
389  * 1:   Xmark
390  *      (get case values)
391  *      Xcase   1f
392  *      (commands)
393  *      Xjump   out
394  * 1:   Xmark
395  *      (get case values)
396  *      Xcase   1f
397  *      (commands)
398  *      Xjump   out
399  * 1:
400  * leave:
401  *      Xpopm
402  */
403
404 void
405 codeswitch(tree *t, int eflag)
406 {
407         int leave;              /* patch jump address to leave switch */
408         int out;                /* jump here to leave switch */
409         int nextcase;   /* patch jump address to next case */
410         tree *tt;
411         if(c1->child[0]==nil
412         || c1->child[0]->type!=';'
413         || !iscase(c1->child[0]->child[0])){
414                 yyerror("case missing in switch");
415                 return;
416         }
417         emitf(Xmark);
418         outcode(c0, eflag);
419         emitf(Xjump);
420         nextcase = emiti(0);
421         out = emitf(Xjump);
422         leave = emiti(0);
423         stuffdot(nextcase);
424         t = c1->child[0];
425         while(t->type==';'){
426                 tt = c1;
427                 emitf(Xmark);
428                 for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
429                 emitf(Xcase);
430                 nextcase = emiti(0);
431                 t = tt;
432                 for(;;){
433                         if(t->type==';'){
434                                 if(iscase(c0)) break;
435                                 outcode(c0, eflag);
436                                 t = c1;
437                         }
438                         else{
439                                 if(!iscase(t)) outcode(t, eflag);
440                                 break;
441                         }
442                 }
443                 emitf(Xjump);
444                 emiti(out);
445                 stuffdot(nextcase);
446         }
447         stuffdot(leave);
448         emitf(Xpopm);
449 }
450
451 int
452 iscase(tree *t)
453 {
454         if(t->type!=SIMPLE)
455                 return 0;
456         do t = c0; while(t->type==ARGLIST);
457         return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
458 }
459
460 code*
461 codecopy(code *cp)
462 {
463         cp[0].i++;
464         return cp;
465 }
466
467 void
468 codefree(code *cp)
469 {
470         code *p;
471         if(--cp[0].i!=0)
472                 return;
473         for(p = cp+1;p->f;p++){
474                 if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
475                 || p->f==Xrdwr
476                 || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
477                 || p->f==Xfor || p->f==Xjump
478                 || p->f==Xsubshell || p->f==Xtrue) p++;
479                 else if(p->f==Xdup || p->f==Xpipefd) p+=2;
480                 else if(p->f==Xpipe) p+=4;
481                 else if(p->f==Xglobs) free(p[1].s), p+=2;
482                 else if(p->f==Xword || p->f==Xdelhere) free((++p)->s);
483                 else if(p->f==Xfn){
484                         free(p[2].s);
485                         p+=2;
486                 }
487         }
488         free(cp);
489 }