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 }