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