simple.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       simple.c (9019B)
       ---
            1 /*
            2  * Maybe `simple' is a misnomer.
            3  */
            4 #include "rc.h"
            5 #include "getflags.h"
            6 #include "exec.h"
            7 #include "io.h"
            8 #include "fns.h"
            9 /*
           10  * Search through the following code to see if we're just going to exit.
           11  */
           12 int
           13 exitnext(void){
           14         union code *c=&runq->code[runq->pc];
           15         while(c->f==Xpopredir) c++;
           16         return c->f==Xexit;
           17 }
           18 
           19 void
           20 Xsimple(void)
           21 {
           22         word *a;
           23         thread *p = runq;
           24         var *v;
           25         struct builtin *bp;
           26         int pid;
           27         globlist();
           28         a = runq->argv->words;
           29         if(a==0){
           30                 Xerror1("empty argument list");
           31                 return;
           32         }
           33         if(flag['x'])
           34                 pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
           35         v = gvlook(a->word);
           36         if(v->fn)
           37                 execfunc(v);
           38         else{
           39                 if(strcmp(a->word, "builtin")==0){
           40                         if(count(a)==1){
           41                                 pfmt(err, "builtin: empty argument list\n");
           42                                 setstatus("empty arg list");
           43                                 poplist();
           44                                 return;
           45                         }
           46                         a = a->next;
           47                         popword();
           48                 }
           49                 for(bp = Builtin;bp->name;bp++)
           50                         if(strcmp(a->word, bp->name)==0){
           51                                 (*bp->fnc)();
           52                                 return;
           53                         }
           54                 if(exitnext()){
           55                         /* fork and wait is redundant */
           56                         pushword("exec");
           57                         execexec();
           58                         Xexit();
           59                 }
           60                 else{
           61                         flush(err);
           62                         Updenv();        /* necessary so changes don't go out again */
           63                         if((pid = execforkexec()) < 0){
           64                                 Xerror("try again");
           65                                 return;
           66                         }
           67 
           68                         /* interrupts don't get us out */
           69                         poplist();
           70                         while(Waitfor(pid, 1) < 0)
           71                                 ;
           72                 }
           73         }
           74 }
           75 struct word nullpath = { "", 0};
           76 
           77 void
           78 doredir(redir *rp)
           79 {
           80         if(rp){
           81                 doredir(rp->next);
           82                 switch(rp->type){
           83                 case ROPEN:
           84                         if(rp->from!=rp->to){
           85                                 Dup(rp->from, rp->to);
           86                                 close(rp->from);
           87                         }
           88                         break;
           89                 case RDUP:
           90                         Dup(rp->from, rp->to);
           91                         break;
           92                 case RCLOSE:
           93                         close(rp->from);
           94                         break;
           95                 }
           96         }
           97 }
           98 
           99 word*
          100 searchpath(char *w)
          101 {
          102         word *path;
          103         if(strncmp(w, "/", 1)==0
          104 /*        || strncmp(w, "#", 1)==0 */
          105         || strncmp(w, "./", 2)==0
          106         || strncmp(w, "../", 3)==0
          107         || (path = vlook("path")->val)==0)
          108                 path=&nullpath;
          109         return path;
          110 }
          111 
          112 void
          113 execexec(void)
          114 {
          115         popword();        /* "exec" */
          116         if(runq->argv->words==0){
          117                 Xerror1("empty argument list");
          118                 return;
          119         }
          120         doredir(runq->redir);
          121         Execute(runq->argv->words, searchpath(runq->argv->words->word));
          122         poplist();
          123 }
          124 
          125 void
          126 execfunc(var *func)
          127 {
          128         word *starval;
          129         popword();
          130         starval = runq->argv->words;
          131         runq->argv->words = 0;
          132         poplist();
          133         start(func->fn, func->pc, runq->local);
          134         runq->local = newvar(strdup("*"), runq->local);
          135         runq->local->val = starval;
          136         runq->local->changed = 1;
          137 }
          138 
          139 int
          140 dochdir(char *word)
          141 {
          142         /* report to /dev/wdir if it exists and we're interactive */
          143         static int wdirfd = -2;
          144         if(chdir(word)<0) return -1;
          145         if(flag['i']!=0){
          146                 if(wdirfd==-2)        /* try only once */
          147                         wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
          148                 if(wdirfd>=0)
          149                         write(wdirfd, word, strlen(word));
          150         }
          151         return 1;
          152 }
          153 
          154 void
          155 execcd(void)
          156 {
          157         word *a = runq->argv->words;
          158         word *cdpath;
          159         char dir[512];
          160         setstatus("can't cd");
          161         cdpath = vlook("cdpath")->val;
          162         switch(count(a)){
          163         default:
          164                 pfmt(err, "Usage: cd [directory]\n");
          165                 break;
          166         case 2:
          167                 if(a->next->word[0]=='/' || cdpath==0)
          168                         cdpath=&nullpath;
          169                 for(;cdpath;cdpath = cdpath->next){
          170                         strcpy(dir, cdpath->word);
          171                         if(dir[0])
          172                                 strcat(dir, "/");
          173                         strcat(dir, a->next->word);
          174                         if(dochdir(dir)>=0){
          175                                 if(strlen(cdpath->word)
          176                                 && strcmp(cdpath->word, ".")!=0)
          177                                         pfmt(err, "%s\n", dir);
          178                                 setstatus("");
          179                                 break;
          180                         }
          181                 }
          182                 if(cdpath==0)
          183                         pfmt(err, "Can't cd %s: %r\n", a->next->word);
          184                 break;
          185         case 1:
          186                 a = vlook("home")->val;
          187                 if(count(a)>=1){
          188                         if(dochdir(a->word)>=0)
          189                                 setstatus("");
          190                         else
          191                                 pfmt(err, "Can't cd %s: %r\n", a->word);
          192                 }
          193                 else
          194                         pfmt(err, "Can't cd -- $home empty\n");
          195                 break;
          196         }
          197         poplist();
          198 }
          199 
          200 void
          201 execexit(void)
          202 {
          203         switch(count(runq->argv->words)){
          204         default:
          205                 pfmt(err, "Usage: exit [status]\nExiting anyway\n");
          206         case 2:
          207                 setstatus(runq->argv->words->next->word);
          208         case 1:        Xexit();
          209         }
          210 }
          211 
          212 void
          213 execshift(void)
          214 {
          215         int n;
          216         word *a;
          217         var *star;
          218         switch(count(runq->argv->words)){
          219         default:
          220                 pfmt(err, "Usage: shift [n]\n");
          221                 setstatus("shift usage");
          222                 poplist();
          223                 return;
          224         case 2:
          225                 n = atoi(runq->argv->words->next->word);
          226                 break;
          227         case 1:
          228                 n = 1;
          229                 break;
          230         }
          231         star = vlook("*");
          232         for(;n && star->val;--n){
          233                 a = star->val->next;
          234                 efree(star->val->word);
          235                 efree((char *)star->val);
          236                 star->val = a;
          237                 star->changed = 1;
          238         }
          239         setstatus("");
          240         poplist();
          241 }
          242 
          243 int
          244 octal(char *s)
          245 {
          246         int n = 0;
          247         while(*s==' ' || *s=='\t' || *s=='\n') s++;
          248         while('0'<=*s && *s<='7') n = n*8+*s++-'0';
          249         return n;
          250 }
          251 
          252 int
          253 mapfd(int fd)
          254 {
          255         redir *rp;
          256         for(rp = runq->redir;rp;rp = rp->next){
          257                 switch(rp->type){
          258                 case RCLOSE:
          259                         if(rp->from==fd)
          260                                 fd=-1;
          261                         break;
          262                 case RDUP:
          263                 case ROPEN:
          264                         if(rp->to==fd)
          265                                 fd = rp->from;
          266                         break;
          267                 }
          268         }
          269         return fd;
          270 }
          271 union code rdcmds[4];
          272 
          273 void
          274 execcmds(io *f)
          275 {
          276         static int first = 1;
          277         if(first){
          278                 rdcmds[0].i = 1;
          279                 rdcmds[1].f = Xrdcmds;
          280                 rdcmds[2].f = Xreturn;
          281                 first = 0;
          282         }
          283         start(rdcmds, 1, runq->local);
          284         runq->cmdfd = f;
          285         runq->iflast = 0;
          286 }
          287 
          288 void
          289 execeval(void)
          290 {
          291         char *cmdline, *s, *t;
          292         int len = 0;
          293         word *ap;
          294         if(count(runq->argv->words)<=1){
          295                 Xerror1("Usage: eval cmd ...");
          296                 return;
          297         }
          298         eflagok = 1;
          299         for(ap = runq->argv->words->next;ap;ap = ap->next)
          300                 len+=1+strlen(ap->word);
          301         cmdline = emalloc(len);
          302         s = cmdline;
          303         for(ap = runq->argv->words->next;ap;ap = ap->next){
          304                 for(t = ap->word;*t;) *s++=*t++;
          305                 *s++=' ';
          306         }
          307         s[-1]='\n';
          308         poplist();
          309         execcmds(opencore(cmdline, len));
          310         efree(cmdline);
          311 }
          312 union code dotcmds[14];
          313 
          314 void
          315 execdot(void)
          316 {
          317         int iflag = 0;
          318         int fd;
          319         list *av;
          320         thread *p = runq;
          321         char *zero;
          322         static int first = 1;
          323         char file[512];
          324         word *path;
          325         if(first){
          326                 dotcmds[0].i = 1;
          327                 dotcmds[1].f = Xmark;
          328                 dotcmds[2].f = Xword;
          329                 dotcmds[3].s="0";
          330                 dotcmds[4].f = Xlocal;
          331                 dotcmds[5].f = Xmark;
          332                 dotcmds[6].f = Xword;
          333                 dotcmds[7].s="*";
          334                 dotcmds[8].f = Xlocal;
          335                 dotcmds[9].f = Xrdcmds;
          336                 dotcmds[10].f = Xunlocal;
          337                 dotcmds[11].f = Xunlocal;
          338                 dotcmds[12].f = Xreturn;
          339                 first = 0;
          340         }
          341         else
          342                 eflagok = 1;
          343         popword();
          344         if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
          345                 iflag = 1;
          346                 popword();
          347         }
          348         /* get input file */
          349         if(p->argv->words==0){
          350                 Xerror1("Usage: . [-i] file [arg ...]");
          351                 return;
          352         }
          353         zero = strdup(p->argv->words->word);
          354         popword();
          355         fd=-1;
          356         for(path = searchpath(zero);path;path = path->next){
          357                 strcpy(file, path->word);
          358                 if(file[0])
          359                         strcat(file, "/");
          360                 strcat(file, zero);
          361                 if((fd = open(file, 0))>=0) break;
          362                 if(strcmp(file, "/dev/stdin")==0){        /* for sun & ucb */
          363                         fd = Dup1(0);
          364                         if(fd>=0)
          365                                 break;
          366                 }
          367         }
          368         if(fd<0){
          369                 pfmt(err, "%s: ", zero);
          370                 setstatus("can't open");
          371                 Xerror(".: can't open");
          372                 return;
          373         }
          374         /* set up for a new command loop */
          375         start(dotcmds, 1, (struct var *)0);
          376         pushredir(RCLOSE, fd, 0);
          377         runq->cmdfile = zero;
          378         runq->cmdfd = openfd(fd);
          379         runq->iflag = iflag;
          380         runq->iflast = 0;
          381         /* push $* value */
          382         pushlist();
          383         runq->argv->words = p->argv->words;
          384         /* free caller's copy of $* */
          385         av = p->argv;
          386         p->argv = av->next;
          387         efree((char *)av);
          388         /* push $0 value */
          389         pushlist();
          390         pushword(zero);
          391         ndot++;
          392 }
          393 
          394 void
          395 execflag(void)
          396 {
          397         char *letter, *val;
          398         switch(count(runq->argv->words)){
          399         case 2:
          400                 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
          401                 break;
          402         case 3:
          403                 letter = runq->argv->words->next->word;
          404                 val = runq->argv->words->next->next->word;
          405                 if(strlen(letter)==1){
          406                         if(strcmp(val, "+")==0){
          407                                 flag[(uchar)letter[0]] = flagset;
          408                                 break;
          409                         }
          410                         if(strcmp(val, "-")==0){
          411                                 flag[(uchar)letter[0]] = 0;
          412                                 break;
          413                         }
          414                 }
          415         default:
          416                 Xerror1("Usage: flag [letter] [+-]");
          417                 return;
          418         }
          419         poplist();
          420 }
          421 
          422 void
          423 execwhatis(void){        /* mildly wrong -- should fork before writing */
          424         word *a, *b, *path;
          425         var *v;
          426         struct builtin *bp;
          427         char file[512];
          428         struct io out[1];
          429         int found, sep;
          430         a = runq->argv->words->next;
          431         if(a==0){
          432                 Xerror1("Usage: whatis name ...");
          433                 return;
          434         }
          435         setstatus("");
          436         out->fd = mapfd(1);
          437         out->bufp = out->buf;
          438         out->ebuf = &out->buf[NBUF];
          439         out->strp = 0;
          440         for(;a;a = a->next){
          441                 v = vlook(a->word);
          442                 if(v->val){
          443                         pfmt(out, "%s=", a->word);
          444                         if(v->val->next==0)
          445                                 pfmt(out, "%q\n", v->val->word);
          446                         else{
          447                                 sep='(';
          448                                 for(b = v->val;b && b->word;b = b->next){
          449                                         pfmt(out, "%c%q", sep, b->word);
          450                                         sep=' ';
          451                                 }
          452                                 pfmt(out, ")\n");
          453                         }
          454                         found = 1;
          455                 }
          456                 else
          457                         found = 0;
          458                 v = gvlook(a->word);
          459                 if(v->fn)
          460                         pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
          461                 else{
          462                         for(bp = Builtin;bp->name;bp++)
          463                                 if(strcmp(a->word, bp->name)==0){
          464                                         pfmt(out, "builtin %s\n", a->word);
          465                                         break;
          466                                 }
          467                         if(!bp->name){
          468                                 for(path = searchpath(a->word);path;path = path->next){
          469                                         strcpy(file, path->word);
          470                                         if(file[0])
          471                                                 strcat(file, "/");
          472                                         strcat(file, a->word);
          473                                         if(Executable(file)){
          474                                                 pfmt(out, "%s\n", file);
          475                                                 break;
          476                                         }
          477                                 }
          478                                 if(!path && !found){
          479                                         pfmt(err, "%s: not found\n", a->word);
          480                                         setstatus("not found");
          481                                 }
          482                         }
          483                 }
          484         }
          485         poplist();
          486         flush(err);
          487 }
          488 
          489 void
          490 execwait(void)
          491 {
          492         switch(count(runq->argv->words)){
          493         default:
          494                 Xerror1("Usage: wait [pid]");
          495                 return;
          496         case 2:
          497                 Waitfor(atoi(runq->argv->words->next->word), 0);
          498                 break;
          499         case 1:
          500                 Waitfor(-1, 0);
          501                 break;
          502         }
          503         poplist();
          504 }