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