main.c (30419B)
1 /* 23jun13abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 #include "pico.h" 6 #include "vers.h" 7 8 #ifdef __CYGWIN__ 9 #define O_ASYNC FASYNC 10 #endif 11 12 /* Globals */ 13 int Repl, Chr, Slot, Spkr, Mic, Hear, Tell, Children, ExtN; 14 char **AV, *AV0, *Home; 15 child *Child; 16 heap *Heaps; 17 cell *Avail; 18 stkEnv Env; 19 catchFrame *CatchPtr; 20 struct termios OrgTermio, *Termio; 21 int InFDs, OutFDs; 22 inFile *InFile, **InFiles; 23 outFile *OutFile, **OutFiles; 24 int (*getBin)(void); 25 void (*putBin)(int); 26 any TheKey, TheCls, Thrown; 27 any Alarm, Sigio, Line, Zero, One; 28 any Intern[IHASH], Transient[IHASH], Extern[EHASH]; 29 any ApplyArgs, ApplyBody, DbVal, DbTail; 30 any Nil, DB, Meth, Quote, T; 31 any Solo, PPid, Pid, At, At2, At3, This, Prompt, Dbg, Zap, Ext, Scl, Class; 32 any Run, Hup, Sig1, Sig2, Up, Err, Msg, Uni, Led, Tsm, Adr, Fork, Bye; 33 bool Break; 34 sig_atomic_t Signal[NSIG]; 35 36 static int TtyPid; 37 static word2 USec; 38 static struct timeval Tv; 39 static bool Tio, Jam; 40 static jmp_buf ErrRst; 41 static void finish(int) __attribute__ ((noreturn)); 42 static struct rlimit ULim = {RLIM_INFINITY, RLIM_INFINITY}; 43 44 45 /*** System ***/ 46 static void finish(int n) { 47 setCooked(); 48 exit(n); 49 } 50 51 void giveup(char *msg) { 52 fprintf(stderr, "%d %s\n", (int)getpid(), msg); 53 finish(1); 54 } 55 56 void bye(int n) { 57 static bool flg; 58 59 if (!flg) { 60 flg = YES; 61 unwind(NULL); 62 prog(val(Bye)); 63 } 64 flushAll(); 65 finish(n); 66 } 67 68 void execError(char *s) { 69 fprintf(stderr, "%s: Can't exec\n", s); 70 exit(127); 71 } 72 73 /* Install interrupting signal */ 74 static void iSignal(int n, void (*foo)(int)) { 75 struct sigaction act, old; 76 77 act.sa_handler = foo; 78 sigemptyset(&act.sa_mask); 79 act.sa_flags = 0; 80 sigaction(n, &act, &old); 81 } 82 83 /* Signal handler */ 84 void sighandler(any ex) { 85 int i; 86 bool flg; 87 88 if (!Env.protect) { 89 Env.protect = 1; 90 do { 91 if (Signal[SIGIO]) { 92 --Signal[0], --Signal[SIGIO]; 93 run(Sigio); 94 } 95 else if (Signal[SIGUSR1]) { 96 --Signal[0], --Signal[SIGUSR1]; 97 run(val(Sig1)); 98 } 99 else if (Signal[SIGUSR2]) { 100 --Signal[0], --Signal[SIGUSR2]; 101 run(val(Sig2)); 102 } 103 else if (Signal[SIGALRM]) { 104 --Signal[0], --Signal[SIGALRM]; 105 run(Alarm); 106 } 107 else if (Signal[SIGINT]) { 108 --Signal[0], --Signal[SIGINT]; 109 if (Repl < 2) 110 brkLoad(ex ?: Nil); 111 } 112 else if (Signal[SIGHUP]) { 113 --Signal[0], --Signal[SIGHUP]; 114 run(val(Hup)); 115 } 116 else if (Signal[SIGTERM]) { 117 for (flg = NO, i = 0; i < Children; ++i) 118 if (Child[i].pid && kill(Child[i].pid, SIGTERM) == 0) 119 flg = YES; 120 if (flg) 121 break; 122 Signal[0] = 0, bye(0); 123 } 124 } while (*Signal); 125 Env.protect = 0; 126 } 127 } 128 129 static void sig(int n) { 130 if (TtyPid) 131 kill(TtyPid, n); 132 else 133 ++Signal[n], ++Signal[0]; 134 } 135 136 static void sigTerm(int n) { 137 if (TtyPid) 138 kill(TtyPid, n); 139 else 140 ++Signal[SIGTERM], ++Signal[0]; 141 } 142 143 static void sigChld(int n __attribute__((unused))) { 144 int e, stat; 145 pid_t pid; 146 147 e = errno; 148 while ((pid = waitpid(0, &stat, WNOHANG)) > 0) 149 if (WIFSIGNALED(stat)) 150 fprintf(stderr, "%d SIG-%d\n", (int)pid, WTERMSIG(stat)); 151 errno = e; 152 } 153 154 static void tcSet(struct termios *p) { 155 if (Termio) 156 while (tcsetattr(STDIN_FILENO, TCSADRAIN, p) && errno == EINTR); 157 } 158 159 static void sigTermStop(int n __attribute__((unused))) { 160 sigset_t mask; 161 162 tcSet(&OrgTermio); 163 sigemptyset(&mask); 164 sigaddset(&mask, SIGTSTP); 165 sigprocmask(SIG_UNBLOCK, &mask, NULL); 166 signal(SIGTSTP, SIG_DFL), raise(SIGTSTP), signal(SIGTSTP, sigTermStop); 167 tcSet(Termio); 168 } 169 170 void setRaw(void) { 171 if (Tio && !Termio) { 172 *(Termio = malloc(sizeof(struct termios))) = OrgTermio; 173 Termio->c_iflag = 0; 174 Termio->c_lflag = ISIG; 175 Termio->c_cc[VMIN] = 1; 176 Termio->c_cc[VTIME] = 0; 177 tcSet(Termio); 178 if (signal(SIGTSTP,SIG_IGN) == SIG_DFL) 179 signal(SIGTSTP, sigTermStop); 180 } 181 } 182 183 void setCooked(void) { 184 tcSet(&OrgTermio); 185 free(Termio), Termio = NULL; 186 } 187 188 // (raw ['flg]) -> flg 189 any doRaw(any x) { 190 if (!isCell(x = cdr(x))) 191 return Termio? T : Nil; 192 if (isNil(EVAL(car(x)))) { 193 setCooked(); 194 return Nil; 195 } 196 setRaw(); 197 return T; 198 } 199 200 // (alarm 'cnt . prg) -> cnt 201 any doAlarm(any x) { 202 int n = alarm((int)evCnt(x,cdr(x))); 203 Alarm = cddr(x); 204 return boxCnt(n); 205 } 206 207 // (sigio 'cnt . prg) -> cnt 208 any doSigio(any ex) { 209 any x = EVAL(cadr(ex)); 210 int fd = (int)xCnt(ex,x); 211 212 Sigio = cddr(ex); 213 fcntl(fd, F_SETOWN, unBox(val(Pid))); 214 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK|O_ASYNC); 215 return x; 216 } 217 218 // (protect . prg) -> any 219 any doProtect(any x) { 220 ++Env.protect; 221 x = prog(cdr(x)); 222 --Env.protect; 223 return x; 224 } 225 226 /* Allocate memory */ 227 void *alloc(void *p, size_t siz) { 228 if (!(p = realloc(p,siz))) 229 giveup("No memory"); 230 return p; 231 } 232 233 /* Allocate cell heap */ 234 void heapAlloc(void) { 235 heap *h; 236 cell *p; 237 238 h = (heap*)alloc(NULL, sizeof(heap)); 239 h->next = Heaps, Heaps = h; 240 p = h->cells + CELLS-1; 241 do 242 Free(p); 243 while (--p >= h->cells); 244 } 245 246 // (heap 'flg) -> cnt 247 any doHeap(any x) { 248 long n = 0; 249 250 x = cdr(x); 251 if (isNil(EVAL(car(x)))) { 252 heap *h = Heaps; 253 do 254 ++n; 255 while (h = h->next); 256 return boxCnt(n); 257 } 258 for (x = Avail; x; x = car(x)) 259 ++n; 260 return boxCnt(n / CELLS); 261 } 262 263 // (adr 'var) -> num 264 // (adr 'num) -> var 265 any doAdr(any x) { 266 x = cdr(x); 267 if (isNum(x = EVAL(car(x)))) 268 return (any)(unDig(x) * WORD); 269 return box(num(x) / WORD); 270 } 271 272 // (env ['lst] | ['sym 'val] ..) -> lst 273 any doEnv(any x) { 274 int i; 275 bindFrame *p; 276 cell c1, c2; 277 278 Push(c1, Nil); 279 if (!isCell(x = cdr(x))) { 280 for (p = Break? Env.bind->link : Env.bind; p; p = p->link) { 281 if (p->i == 0) { 282 for (i = p->cnt; --i >= 0;) { 283 for (x = data(c1); ; x = cdr(x)) { 284 if (!isCell(x)) { 285 data(c1) = cons(cons(p->bnd[i].sym, val(p->bnd[i].sym)), data(c1)); 286 break; 287 } 288 if (caar(x) == p->bnd[i].sym) 289 break; 290 } 291 } 292 } 293 } 294 } 295 else { 296 do { 297 Push(c2, EVAL(car(x))); 298 if (isCell(data(c2))) { 299 do 300 data(c1) = cons( 301 isCell(car(data(c2)))? 302 cons(caar(data(c2)), cdar(data(c2))) : 303 cons(car(data(c2)), val(car(data(c2)))), 304 data(c1) ); 305 while (isCell(data(c2) = cdr(data(c2)))); 306 } 307 else if (!isNil(data(c2))) { 308 x = cdr(x); 309 data(c1) = cons(cons(data(c2), EVAL(car(x))), data(c1)); 310 } 311 drop(c2); 312 } 313 while (isCell(x = cdr(x))); 314 } 315 return Pop(c1); 316 } 317 318 // (up [cnt] sym ['val]) -> any 319 any doUp(any x) { 320 any y, *val; 321 int cnt, i; 322 bindFrame *p; 323 324 x = cdr(x); 325 if (!isNum(y = car(x))) 326 cnt = 1; 327 else 328 cnt = (int)unBox(y), x = cdr(x), y = car(x); 329 for (p = Break? Env.bind->link : Env.bind, val = &val(y); p; p = p->link) { 330 if (p->i <= 0) { 331 for (i = 0; i < p->cnt; ++i) 332 if (p->bnd[i].sym == y) { 333 if (!--cnt) { 334 if (isCell(x = cdr(x))) 335 return p->bnd[i].val = EVAL(car(x)); 336 return p->bnd[i].val; 337 } 338 val = &p->bnd[i].val; 339 } 340 } 341 } 342 if (isCell(x = cdr(x))) 343 return *val = EVAL(car(x)); 344 return *val; 345 } 346 347 // (sys 'any ['any]) -> sym 348 any doSys(any x) { 349 any y; 350 351 y = evSym(x = cdr(x)); 352 { 353 char nm[bufSize(y)]; 354 355 bufString(y,nm); 356 if (!isCell(x = cdr(x))) 357 return mkStr(getenv(nm)); 358 y = evSym(x); 359 { 360 char val[bufSize(y)]; 361 362 bufString(y,val); 363 return setenv(nm,val,1)? Nil : y; 364 } 365 } 366 } 367 368 /*** Primitives ***/ 369 any circ(any x) { 370 any y = x; 371 372 for (;;) { 373 *(word*)&car(y) |= 1; 374 if (!isCell(y = cdr(y))) { 375 do 376 *(word*)&car(x) &= ~1; 377 while (isCell(x = cdr(x))); 378 return NULL; 379 } 380 if (num(car(y)) & 1) { 381 while (x != y) 382 *(word*)&car(x) &= ~1, x = cdr(x); 383 do 384 *(word*)&car(x) &= ~1; 385 while (y != (x = cdr(x))); 386 return y; 387 } 388 } 389 } 390 391 /* Comparisons */ 392 bool equal(any x, any y) { 393 any a, b; 394 bool res; 395 396 for (;;) { 397 if (x == y) 398 return YES; 399 if (isNum(x)) { 400 if (!isNum(y) || unDig(x) != unDig(y)) 401 return NO; 402 x = cdr(numCell(x)), y = cdr(numCell(y)); 403 continue; 404 } 405 if (isSym(x)) { 406 if (!isSym(y) || !isNum(x = name(x)) || !isNum(y = name(y))) 407 return NO; 408 continue; 409 } 410 if (!isCell(y)) 411 return NO; 412 a = x, b = y; 413 res = NO; 414 for (;;) { 415 if (!equal(car(x), (any)(num(car(y)) & ~1))) 416 break; 417 if (!isCell(cdr(x))) { 418 res = equal(cdr(x), cdr(y)); 419 break; 420 } 421 if (!isCell(cdr(y))) 422 break; 423 *(word*)&car(x) |= 1, x = cdr(x), y = cdr(y); 424 if (num(car(x)) & 1) { 425 for (;;) { 426 if (a == x) { 427 if (b == y) { 428 for (;;) { 429 a = cdr(a); 430 if ((b = cdr(b)) == y) { 431 res = a == x; 432 break; 433 } 434 if (a == x) { 435 res = YES; 436 break; 437 } 438 } 439 } 440 break; 441 } 442 if (b == y) { 443 res = NO; 444 break; 445 } 446 *(word*)&car(a) &= ~1, a = cdr(a), b = cdr(b); 447 } 448 do 449 *(word*)&car(a) &= ~1, a = cdr(a); 450 while (a != x); 451 return res; 452 } 453 } 454 while (a != x) 455 *(word*)&car(a) &= ~1, a = cdr(a); 456 return res; 457 } 458 } 459 460 int compare(any x, any y) { 461 any a, b; 462 463 if (x == y) 464 return 0; 465 if (isNil(x)) 466 return -1; 467 if (x == T) 468 return +1; 469 if (isNum(x)) { 470 if (!isNum(y)) 471 return isNil(y)? +1 : -1; 472 return bigCompare(x,y); 473 } 474 if (isSym(x)) { 475 int b1, b2; 476 word n1, n2; 477 478 if (isNum(y) || isNil(y)) 479 return +1; 480 if (isCell(y) || y == T) 481 return -1; 482 if (!isNum(a = name(x))) 483 return !isNum(name(y))? (long)x - (long)y : -1; 484 if (!isNum(b = name(y))) 485 return +1; 486 n1 = unDig(a), n2 = unDig(b); 487 for (;;) { 488 if ((b1 = n1 & 0xFF) != (b2 = n2 & 0xFF)) 489 return b1 - b2; 490 if ((n1 >>= 8) == 0) { 491 if ((n2 >>= 8) != 0) 492 return -1; 493 if (!isNum(a = cdr(numCell(a)))) 494 return !isNum(b = cdr(numCell(b)))? 0 : -1; 495 if (!isNum(b = cdr(numCell(b)))) 496 return +1; 497 n1 = unDig(a), n2 = unDig(b); 498 } 499 else if ((n2 >>= 8) == 0) 500 return +1; 501 } 502 } 503 if (!isCell(y)) 504 return y == T? -1 : +1; 505 a = x, b = y; 506 for (;;) { 507 int n; 508 509 if (n = compare(car(x),car(y))) 510 return n; 511 if (!isCell(x = cdr(x))) 512 return compare(x, cdr(y)); 513 if (!isCell(y = cdr(y))) 514 return y == T? -1 : +1; 515 if (x == a && y == b) 516 return 0; 517 } 518 } 519 520 int binSize(any x) { 521 if (isNum(x)) { 522 int n = numBytes(x); 523 524 if (n < 63) 525 return n + 1; 526 return n + 2 + (n - 63) / 255; 527 } 528 else if (isNil(x)) 529 return 1; 530 else if (isSym(x)) 531 return binSize(name(x)); 532 else { 533 any y = x; 534 int n = 2; 535 536 while (n += binSize(car(x)), !isNil(x = cdr(x))) { 537 if (x == y) 538 return n + 1; 539 if (!isCell(x)) 540 return n + binSize(x); 541 } 542 return n; 543 } 544 } 545 546 /*** Error handling ***/ 547 void err(any ex, any x, char *fmt, ...) { 548 va_list ap; 549 char msg[240]; 550 outFrame f; 551 cell c1; 552 553 va_start(ap,fmt); 554 vsnprintf(msg, sizeof(msg), fmt, ap); 555 va_end(ap); 556 val(Up) = ex ?: Nil; 557 if (x) 558 Push(c1, x); 559 if (msg[0]) { 560 any y; 561 catchFrame *p; 562 563 val(Msg) = mkStr(msg); 564 for (p = CatchPtr; p; p = p->link) 565 if (y = p->tag) 566 while (isCell(y)) { 567 if (subStr(car(y), val(Msg))) { 568 Thrown = isNil(car(y))? val(Msg) : car(y); 569 unwind(p); 570 longjmp(p->rst, 1); 571 } 572 y = cdr(y); 573 } 574 } 575 Chr = ExtN = 0; 576 Break = NO; 577 Alarm = Line = Nil; 578 f.pid = 0, f.fd = STDERR_FILENO, pushOutFiles(&f); 579 if (InFile && InFile->name) { 580 Env.put('['); 581 outString(InFile->name), Env.put(':'), outWord(InFile->src); 582 Env.put(']'), space(); 583 } 584 if (ex) 585 outString("!? "), print(ex), newline(); 586 if (x) 587 print(x), outString(" -- "); 588 if (msg[0]) { 589 outString(msg), newline(); 590 if (!isNil(val(Err)) && !Jam) 591 Jam = YES, prog(val(Err)), Jam = NO; 592 if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) 593 bye(1); 594 load(NULL, '?', Nil); 595 } 596 unwind(NULL); 597 Env.stack = NULL; 598 Env.protect = Env.trace = 0; 599 Env.next = -1; 600 Env.task = Nil; 601 Env.make = Env.yoke = NULL; 602 Env.parser = NULL; 603 longjmp(ErrRst, +1); 604 } 605 606 // (quit ['any ['any]]) 607 any doQuit(any x) { 608 any y; 609 610 x = cdr(x), y = evSym(x); 611 { 612 char msg[bufSize(y)]; 613 614 bufString(y, msg); 615 x = isCell(x = cdr(x))? EVAL(car(x)) : NULL; 616 err(NULL, x, "%s", msg); 617 } 618 } 619 620 void argError(any ex, any x) {err(ex, x, "Bad argument");} 621 void numError(any ex, any x) {err(ex, x, "Number expected");} 622 void cntError(any ex, any x) {err(ex, x, "Small number expected");} 623 void symError(any ex, any x) {err(ex, x, "Symbol expected");} 624 void extError(any ex, any x) {err(ex, x, "External symbol expected");} 625 void pairError(any ex, any x) {err(ex, x, "Cons pair expected");} 626 void atomError(any ex, any x) {err(ex, x, "Atom expected");} 627 void lstError(any ex, any x) {err(ex, x, "List expected");} 628 void varError(any ex, any x) {err(ex, x, "Variable expected");} 629 void protError(any ex, any x) {err(ex, x, "Protected symbol");} 630 631 void pipeError(any ex, char *s) {err(ex, NULL, "Pipe %s error", s);} 632 633 void unwind(catchFrame *catch) { 634 any x; 635 int i, j, n; 636 bindFrame *p; 637 catchFrame *q; 638 639 while (q = CatchPtr) { 640 while (p = Env.bind) { 641 if ((i = p->i) < 0) { 642 j = i, n = 0; 643 while (++n, ++j && (p = p->link)) 644 if (p->i >= 0 || p->i < i) 645 --j; 646 do { 647 for (p = Env.bind, j = n; --j; p = p->link); 648 if (p->i < 0 && ((p->i -= i) > 0? (p->i = 0) : p->i) == 0) 649 for (j = p->cnt; --j >= 0;) { 650 x = val(p->bnd[j].sym); 651 val(p->bnd[j].sym) = p->bnd[j].val; 652 p->bnd[j].val = x; 653 } 654 } while (--n); 655 } 656 if (Env.bind == q->env.bind) 657 break; 658 if (Env.bind->i == 0) 659 for (i = Env.bind->cnt; --i >= 0;) 660 val(Env.bind->bnd[i].sym) = Env.bind->bnd[i].val; 661 Env.bind = Env.bind->link; 662 } 663 while (Env.inFrames != q->env.inFrames) 664 popInFiles(); 665 while (Env.outFrames != q->env.outFrames) 666 popOutFiles(); 667 while (Env.errFrames != q->env.errFrames) 668 popErrFiles(); 669 while (Env.ctlFrames != q->env.ctlFrames) 670 popCtlFiles(); 671 Env = q->env; 672 EVAL(q->fin); 673 CatchPtr = q->link; 674 if (q == catch) 675 return; 676 } 677 while (Env.bind) { 678 if (Env.bind->i == 0) 679 for (i = Env.bind->cnt; --i >= 0;) 680 val(Env.bind->bnd[i].sym) = Env.bind->bnd[i].val; 681 Env.bind = Env.bind->link; 682 } 683 while (Env.inFrames) 684 popInFiles(); 685 while (Env.outFrames) 686 popOutFiles(); 687 while (Env.errFrames) 688 popErrFiles(); 689 while (Env.ctlFrames) 690 popCtlFiles(); 691 } 692 693 /*** Evaluation ***/ 694 any evExpr(any expr, any x) { 695 any y = car(expr); 696 struct { // bindFrame 697 struct bindFrame *link; 698 int i, cnt; 699 struct {any sym; any val;} bnd[length(y)+2]; 700 } f; 701 702 f.link = Env.bind, Env.bind = (bindFrame*)&f; 703 f.i = sizeof(f.bnd) / (2*sizeof(any)) - 1; 704 f.cnt = 1, f.bnd[0].sym = At, f.bnd[0].val = val(At); 705 while (isCell(y)) { 706 f.bnd[f.cnt].sym = car(y); 707 f.bnd[f.cnt].val = EVAL(car(x)); 708 ++f.cnt, x = cdr(x), y = cdr(y); 709 } 710 if (isNil(y)) { 711 do { 712 x = val(f.bnd[--f.i].sym); 713 val(f.bnd[f.i].sym) = f.bnd[f.i].val; 714 f.bnd[f.i].val = x; 715 } while (f.i); 716 x = prog(cdr(expr)); 717 } 718 else if (y != At) { 719 f.bnd[f.cnt].sym = y, f.bnd[f.cnt++].val = val(y), val(y) = x; 720 do { 721 x = val(f.bnd[--f.i].sym); 722 val(f.bnd[f.i].sym) = f.bnd[f.i].val; 723 f.bnd[f.i].val = x; 724 } while (f.i); 725 x = prog(cdr(expr)); 726 } 727 else { 728 int n, cnt; 729 cell *arg; 730 cell c[n = cnt = length(x)]; 731 732 while (--n >= 0) 733 Push(c[n], EVAL(car(x))), x = cdr(x); 734 do { 735 x = val(f.bnd[--f.i].sym); 736 val(f.bnd[f.i].sym) = f.bnd[f.i].val; 737 f.bnd[f.i].val = x; 738 } while (f.i); 739 n = Env.next, Env.next = cnt; 740 arg = Env.arg, Env.arg = c; 741 x = prog(cdr(expr)); 742 if (cnt) 743 drop(c[cnt-1]); 744 Env.arg = arg, Env.next = n; 745 } 746 while (--f.cnt >= 0) 747 val(f.bnd[f.cnt].sym) = f.bnd[f.cnt].val; 748 Env.bind = f.link; 749 return x; 750 } 751 752 any funq(any x) { 753 any y; 754 755 if (isSym(x)) 756 return Nil; 757 if (isNum(x)) 758 return (unDig(x)&3) || isNum(cdr(numCell(x)))? Nil : x; 759 for (y = cdr(x); isCell(y); y = cdr(y)) { 760 if (y == x) 761 return Nil; 762 if (isCell(car(y))) { 763 if (isNum(caar(y))) { 764 if (isCell(cdr(y))) 765 return Nil; 766 } 767 else if (isNil(caar(y)) || caar(y) == T) 768 return Nil; 769 } 770 else if (!isNil(cdr(y))) 771 return Nil; 772 } 773 if (!isNil(y)) 774 return Nil; 775 if (isNil(x = car(x))) 776 return T; 777 for (y = x; isCell(y);) 778 if (isNum(car(y)) || isCell(car(y)) || isNil(car(y)) || car(y)==T || x==(y=cdr(y))) 779 return Nil; 780 return isNum(y) || y==T? Nil : x; 781 } 782 783 bool sharedLib(any x) { 784 void *h; 785 char *p, nm[bufSize(x)]; 786 787 bufString(x, nm); 788 if (!(p = strchr(nm,':')) || p == nm || p[1] == '\0') 789 return NO; 790 *p++ = '\0'; 791 { 792 int n = Home? strlen(Home) : 0; 793 #ifndef __CYGWIN__ 794 char buf[n + strlen(nm) + 4 + 1]; 795 #else 796 char buf[n + strlen(nm) + 4 + 4 + 1]; 797 #endif 798 799 if (strchr(nm,'/')) 800 strcpy(buf, nm); 801 else { 802 if (n) 803 memcpy(buf, Home, n); 804 strcpy(buf + n, "lib/"), strcpy(buf + n + 4, nm); 805 #ifdef __CYGWIN__ 806 strcpy(buf + n + 4 + strlen(nm), ".dll"); 807 #endif 808 } 809 if (!(h = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL)) || !(h = dlsym(h,p))) 810 return NO; 811 val(x) = box(num(h)); 812 } 813 return YES; 814 } 815 816 void undefined(any x, any ex) { 817 if (!sharedLib(x)) 818 err(ex, x, "Undefined"); 819 } 820 821 static any evList2(any foo, any ex) { 822 cell c1; 823 824 Push(c1, foo); 825 if (isCell(foo)) { 826 foo = evExpr(foo, cdr(ex)); 827 drop(c1); 828 return foo; 829 } 830 for (;;) { 831 if (isNil(val(foo))) 832 undefined(foo,ex); 833 if (*Signal) 834 sighandler(ex); 835 if (isNum(foo = val(foo))) { 836 foo = evSubr(foo,ex); 837 drop(c1); 838 return foo; 839 } 840 if (isCell(foo)) { 841 foo = evExpr(foo, cdr(ex)); 842 drop(c1); 843 return foo; 844 } 845 } 846 } 847 848 /* Evaluate a list */ 849 any evList(any ex) { 850 any foo; 851 852 if (!isSym(foo = car(ex))) { 853 if (isNum(foo)) 854 return ex; 855 if (*Signal) 856 sighandler(ex); 857 if (isNum(foo = evList(foo))) 858 return evSubr(foo,ex); 859 return evList2(foo,ex); 860 } 861 for (;;) { 862 if (isNil(val(foo))) 863 undefined(foo,ex); 864 if (*Signal) 865 sighandler(ex); 866 if (isNum(foo = val(foo))) 867 return evSubr(foo,ex); 868 if (isCell(foo)) 869 return evExpr(foo, cdr(ex)); 870 } 871 } 872 873 /* Evaluate any to sym */ 874 any evSym(any x) {return xSym(EVAL(car(x)));} 875 876 any xSym(any x) { 877 int i; 878 any nm; 879 cell c1, c2; 880 881 if (isSym(x)) 882 return x; 883 Push(c1,x); 884 nm = NULL, pack(x, &i, &nm, &c2); 885 drop(c1); 886 return nm? consStr(data(c2)) : Nil; 887 } 888 889 /* Evaluate count */ 890 long evCnt(any ex, any x) {return xCnt(ex, EVAL(car(x)));} 891 892 long xCnt(any ex, any x) { 893 NeedCnt(ex,x); 894 return unBox(x); 895 } 896 897 /* Evaluate double */ 898 double evDouble(any ex, any x) { 899 x = EVAL(car(x)); 900 NeedNum(ex,x); 901 return numToDouble(x); 902 } 903 904 // (args) -> flg 905 any doArgs(any ex __attribute__((unused))) { 906 return Env.next > 0? T : Nil; 907 } 908 909 // (next) -> any 910 any doNext(any ex __attribute__((unused))) { 911 if (Env.next > 0) 912 return data(Env.arg[--Env.next]); 913 if (Env.next == 0) 914 Env.next = -1; 915 return Nil; 916 } 917 918 // (arg ['cnt]) -> any 919 any doArg(any ex) { 920 long n; 921 922 if (Env.next < 0) 923 return Nil; 924 if (!isCell(cdr(ex))) 925 return data(Env.arg[Env.next]); 926 if ((n = evCnt(ex,cdr(ex))) > 0 && n <= Env.next) 927 return data(Env.arg[Env.next - n]); 928 return Nil; 929 } 930 931 // (rest) -> lst 932 any doRest(any x) { 933 int i; 934 cell c1; 935 936 if ((i = Env.next) <= 0) 937 return Nil; 938 Push(c1, x = cons(data(Env.arg[--i]), Nil)); 939 while (i) 940 x = cdr(x) = cons(data(Env.arg[--i]), Nil); 941 return Pop(c1); 942 } 943 944 static struct tm *TM; 945 946 any mkDat(int y, int m, int d) { 947 int n; 948 static char mon[13] = {31,31,28,31,30,31,30,31,31,30,31,30,31}; 949 950 if (m<1 || m>12 || d<1 || d>mon[m] && (m!=2 || d!=29 || y%4 || !(y%100) && y%400)) 951 return Nil; 952 n = (12*y + m - 3) / 12; 953 return boxCnt((4404*y+367*m-1094)/12 - 2*n + n/4 - n/100 + n/400 + d); 954 } 955 956 // (date ['T]) -> dat 957 // (date 'dat) -> (y m d) 958 // (date 'y 'm 'd) -> dat | NIL 959 // (date '(y m d)) -> dat | NIL 960 any doDate(any ex) { 961 any x, z; 962 int y, m, d, n; 963 cell c1; 964 965 if (!isCell(x = cdr(ex))) { 966 gettimeofday(&Tv,NULL); 967 TM = localtime(&Tv.tv_sec); 968 return mkDat(TM->tm_year+1900, TM->tm_mon+1, TM->tm_mday); 969 } 970 if ((z = EVAL(car(x))) == T) { 971 gettimeofday(&Tv,NULL); 972 TM = gmtime(&Tv.tv_sec); 973 return mkDat(TM->tm_year+1900, TM->tm_mon+1, TM->tm_mday); 974 } 975 if (isNil(z)) 976 return Nil; 977 if (isCell(z)) 978 return mkDat(xCnt(ex, car(z)), xCnt(ex, cadr(z)), xCnt(ex, caddr(z))); 979 if (!isCell(x = cdr(x))) { 980 n = xCnt(ex,z); 981 y = (100*n - 20) / 3652425; 982 n += (y - y/4); 983 y = (100*n - 20) / 36525; 984 n -= 36525*y / 100; 985 m = (10*n - 5) / 306; 986 d = (10*n - 306*m + 5) / 10; 987 if (m < 10) 988 m += 3; 989 else 990 ++y, m -= 9; 991 Push(c1, cons(boxCnt(d), Nil)); 992 data(c1) = cons(boxCnt(m), data(c1)); 993 data(c1) = cons(boxCnt(y), data(c1)); 994 return Pop(c1); 995 } 996 y = xCnt(ex,z); 997 m = evCnt(ex,x); 998 return mkDat(y, m, evCnt(ex,cdr(x))); 999 } 1000 1001 any mkTime(int h, int m, int s) { 1002 if (h < 0 || h > 23 || m < 0 || m > 59 || s < 0 || s > 60) 1003 return Nil; 1004 return boxCnt(h * 3600 + m * 60 + s); 1005 } 1006 1007 // (time ['T]) -> tim 1008 // (time 'tim) -> (h m s) 1009 // (time 'h 'm ['s]) -> tim | NIL 1010 // (time '(h m [s])) -> tim | NIL 1011 any doTime(any ex) { 1012 any x, z; 1013 int h, m, s; 1014 cell c1; 1015 struct tm *p; 1016 1017 if (!isCell(x = cdr(ex))) { 1018 gettimeofday(&Tv,NULL); 1019 p = localtime(&Tv.tv_sec); 1020 return boxCnt(p->tm_hour * 3600 + p->tm_min * 60 + p->tm_sec); 1021 } 1022 if ((z = EVAL(car(x))) == T) 1023 return TM? boxCnt(TM->tm_hour * 3600 + TM->tm_min * 60 + TM->tm_sec) : Nil; 1024 if (isNil(z)) 1025 return Nil; 1026 if (isCell(z)) 1027 return mkTime(xCnt(ex, car(z)), xCnt(ex, cadr(z)), isCell(cddr(z))? xCnt(ex, caddr(z)) : 0); 1028 if (!isCell(x = cdr(x))) { 1029 s = xCnt(ex,z); 1030 Push(c1, cons(boxCnt(s % 60), Nil)); 1031 data(c1) = cons(boxCnt(s / 60 % 60), data(c1)); 1032 data(c1) = cons(boxCnt(s / 3600), data(c1)); 1033 return Pop(c1); 1034 } 1035 h = xCnt(ex, z); 1036 m = evCnt(ex, x); 1037 return mkTime(h, m, isCell(cdr(x))? evCnt(ex, cdr(x)) : 0); 1038 } 1039 1040 // (usec ['flg]) -> num 1041 any doUsec(any ex) { 1042 if (!isNil(EVAL(cadr(ex)))) 1043 return boxCnt(Tv.tv_usec); 1044 gettimeofday(&Tv,NULL); 1045 return boxWord2((word2)Tv.tv_sec*1000000 + Tv.tv_usec - USec); 1046 } 1047 1048 // (pwd) -> sym 1049 any doPwd(any x) { 1050 char *p; 1051 1052 if ((p = getcwd(NULL,0)) == NULL) 1053 return Nil; 1054 x = mkStr(p); 1055 free(p); 1056 return x; 1057 } 1058 1059 // (cd 'any) -> sym 1060 any doCd(any x) { 1061 x = evSym(cdr(x)); 1062 { 1063 char *p, path[pathSize(x)]; 1064 1065 pathString(x, path); 1066 if ((p = getcwd(NULL,0)) == NULL || path[0] && chdir(path) < 0) 1067 return Nil; 1068 x = mkStr(p); 1069 free(p); 1070 return x; 1071 } 1072 } 1073 1074 // (ctty 'sym|pid) -> flg 1075 any doCtty(any ex) { 1076 any x; 1077 1078 if (isNum(x = EVAL(cadr(ex)))) 1079 TtyPid = unDig(x) / 2; 1080 else { 1081 if (!isSym(x)) 1082 argError(ex,x); 1083 { 1084 char tty[bufSize(x)]; 1085 1086 bufString(x, tty); 1087 if (!freopen(tty,"r",stdin) || !freopen(tty,"w",stdout) || !freopen(tty,"w",stderr)) 1088 return Nil; 1089 OutFiles[STDOUT_FILENO]->tty = YES; 1090 } 1091 } 1092 return T; 1093 } 1094 1095 // (info 'any ['flg]) -> (cnt|T dat . tim) 1096 any doInfo(any x) { 1097 any y; 1098 cell c1; 1099 struct tm *p; 1100 struct stat st; 1101 1102 y = evSym(x = cdr(x)); 1103 { 1104 char nm[pathSize(y)]; 1105 1106 pathString(y, nm); 1107 x = cdr(x); 1108 if ((isNil(EVAL(car(x)))? stat(nm, &st) : lstat(nm, &st)) < 0) 1109 return Nil; 1110 p = gmtime(&st.st_mtime); 1111 Push(c1, boxCnt(p->tm_hour * 3600 + p->tm_min * 60 + p->tm_sec)); 1112 data(c1) = cons(mkDat(p->tm_year+1900, p->tm_mon+1, p->tm_mday), data(c1)); 1113 data(c1) = cons(S_ISDIR(st.st_mode)? T : boxWord2((word2)st.st_size), data(c1)); 1114 return Pop(c1); 1115 } 1116 } 1117 1118 // (file) -> (sym1 sym2 . num) | NIL 1119 any doFile(any ex __attribute__((unused))) { 1120 char *s, *p; 1121 cell c1; 1122 1123 if (!InFile || !InFile->name) 1124 return Nil; 1125 Push(c1, boxCnt(InFile->src)); 1126 s = strdup(InFile->name); 1127 if (p = strrchr(s, '/')) { 1128 data(c1) = cons(mkStr(p+1), data(c1)); 1129 *(p+1) = '\0'; 1130 data(c1) = cons(mkStr(s), data(c1)); 1131 } 1132 else { 1133 data(c1) = cons(mkStr(s), data(c1)); 1134 data(c1) = cons(mkStr("./"), data(c1)); 1135 } 1136 free(s); 1137 return Pop(c1); 1138 } 1139 1140 // (dir ['any] ['flg]) -> lst 1141 any doDir(any x) { 1142 any y; 1143 DIR *dp; 1144 struct dirent *p; 1145 cell c1; 1146 1147 if (isNil(y = evSym(x = cdr(x)))) 1148 dp = opendir("."); 1149 else { 1150 char nm[pathSize(y)]; 1151 1152 pathString(y, nm); 1153 dp = opendir(nm); 1154 } 1155 if (!dp) 1156 return Nil; 1157 x = cdr(x), x = EVAL(car(x)); 1158 do { 1159 if (!(p = readdir(dp))) { 1160 closedir(dp); 1161 return Nil; 1162 } 1163 } while (isNil(x) && p->d_name[0] == '.'); 1164 Push(c1, y = cons(mkStr(p->d_name), Nil)); 1165 while (p = readdir(dp)) 1166 if (!isNil(x) || p->d_name[0] != '.') 1167 y = cdr(y) = cons(mkStr(p->d_name), Nil); 1168 closedir(dp); 1169 return Pop(c1); 1170 } 1171 1172 // (cmd ['any]) -> sym 1173 any doCmd(any x) { 1174 if (isNil(x = evSym(cdr(x)))) 1175 return mkStr(AV0); 1176 bufString(x, AV0); 1177 return x; 1178 } 1179 1180 // (argv [var ..] [. sym]) -> lst|sym 1181 any doArgv(any ex) { 1182 any x, y; 1183 char **p; 1184 cell c1; 1185 1186 if (*(p = AV) && strcmp(*p,"-") == 0) 1187 ++p; 1188 if (isNil(x = cdr(ex))) { 1189 if (!*p) 1190 return Nil; 1191 Push(c1, x = cons(mkStr(*p++), Nil)); 1192 while (*p) 1193 x = cdr(x) = cons(mkStr(*p++), Nil); 1194 return Pop(c1); 1195 } 1196 do { 1197 if (!isCell(x)) { 1198 NeedSym(ex,x); 1199 CheckVar(ex,x); 1200 if (!*p) 1201 return val(x) = Nil; 1202 Push(c1, y = cons(mkStr(*p++), Nil)); 1203 while (*p) 1204 y = cdr(y) = cons(mkStr(*p++), Nil); 1205 return val(x) = Pop(c1); 1206 } 1207 y = car(x); 1208 NeedVar(ex,y); 1209 CheckVar(ex,y); 1210 val(y) = *p? mkStr(*p++) : Nil; 1211 } while (!isNil(x = cdr(x))); 1212 return val(y); 1213 } 1214 1215 // (opt) -> sym 1216 any doOpt(any ex __attribute__((unused))) { 1217 return *AV && strcmp(*AV,"-")? mkStr(*AV++) : Nil; 1218 } 1219 1220 // (version ['flg]) -> lst 1221 any doVersion(any x) { 1222 int i; 1223 cell c1; 1224 1225 x = cdr(x); 1226 if (isNil(EVAL(car(x)))) { 1227 for (i = 0; i < 4; ++i) { 1228 outWord((word)Version[i]); 1229 Env.put(i == 3? ' ' : '.'); 1230 } 1231 Env.put('C'); 1232 newline(); 1233 } 1234 Push(c1, Nil); 1235 i = 4; 1236 do 1237 data(c1) = cons(box(Version[--i] * 2), data(c1)); 1238 while (i); 1239 return Pop(c1); 1240 } 1241 1242 any loadAll(any ex) { 1243 any x = Nil; 1244 1245 while (*AV && strcmp(*AV,"-") != 0) 1246 x = load(ex, 0, mkStr(*AV++)); 1247 return x; 1248 } 1249 1250 /*** Main ***/ 1251 static void init(int ac, char *av[]) { 1252 char *p; 1253 sigset_t sigs; 1254 1255 AV0 = *av++; 1256 AV = av; 1257 heapAlloc(); 1258 initSymbols(); 1259 if (ac >= 2 && strcmp(av[ac-2], "+") == 0) 1260 val(Dbg) = T, av[ac-2] = NULL; 1261 if (av[0] && *av[0] != '-' && (p = strrchr(av[0], '/')) && !(p == av[0]+1 && *av[0] == '.')) { 1262 Home = malloc(p - av[0] + 2); 1263 memcpy(Home, av[0], p - av[0] + 1); 1264 Home[p - av[0] + 1] = '\0'; 1265 } 1266 Env.get = getStdin; 1267 InFile = initInFile(STDIN_FILENO, NULL); 1268 Env.put = putStdout; 1269 initOutFile(STDERR_FILENO); 1270 OutFile = initOutFile(STDOUT_FILENO); 1271 Env.task = Alarm = Sigio = Line = Nil; 1272 setrlimit(RLIMIT_STACK, &ULim); 1273 Tio = tcgetattr(STDIN_FILENO, &OrgTermio) == 0; 1274 ApplyArgs = cons(cons(consSym(Nil,Nil), Nil), Nil); 1275 ApplyBody = cons(Nil,Nil); 1276 sigfillset(&sigs); 1277 sigprocmask(SIG_UNBLOCK, &sigs, NULL); 1278 iSignal(SIGHUP, sig); 1279 iSignal(SIGINT, sigTerm); 1280 iSignal(SIGUSR1, sig); 1281 iSignal(SIGUSR2, sig); 1282 iSignal(SIGALRM, sig); 1283 iSignal(SIGTERM, sig); 1284 iSignal(SIGIO, sig); 1285 signal(SIGCHLD, sigChld); 1286 signal(SIGPIPE, SIG_IGN); 1287 signal(SIGTTIN, SIG_IGN); 1288 signal(SIGTTOU, SIG_IGN); 1289 gettimeofday(&Tv,NULL); 1290 USec = (word2)Tv.tv_sec*1000000 + Tv.tv_usec; 1291 } 1292 1293 int MAIN(int ac, char *av[]) { 1294 init(ac,av); 1295 if (!setjmp(ErrRst)) { 1296 loadAll(NULL); 1297 ++Repl; 1298 iSignal(SIGINT, sig); 1299 } 1300 for (;;) 1301 load(NULL, ':', Nil); 1302 }