core.c revision 5dfecf96
1/* 2 * Copyright (c) 2001 by The XFree86 Project, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the XFree86 Project shall 23 * not be used in advertising or otherwise to promote the sale, use or other 24 * dealings in this Software without prior written authorization from the 25 * XFree86 Project. 26 * 27 * Author: Paulo César Pereira de Andrade 28 */ 29 30/* $XFree86: xc/programs/xedit/lisp/core.c,v 1.71tsi Exp $ */ 31 32#include "lisp/io.h" 33#include "lisp/core.h" 34#include "lisp/format.h" 35#include "lisp/helper.h" 36#include "lisp/package.h" 37#include "lisp/private.h" 38#include "lisp/write.h" 39 40/* 41 * Types 42 */ 43typedef struct _SeqInfo { 44 LispType type; 45 union { 46 LispObj *list; 47 LispObj **vector; 48 unsigned char *string; 49 } data; 50} SeqInfo; 51 52#define SETSEQ(seq, object) \ 53 switch (seq.type = XOBJECT_TYPE(object)) { \ 54 case LispString_t: \ 55 seq.data.string = (unsigned char*)THESTR(object); \ 56 break; \ 57 case LispCons_t: \ 58 seq.data.list = object; \ 59 break; \ 60 default: \ 61 seq.data.list = object->data.array.list; \ 62 break; \ 63 } 64 65#ifdef __UNIXOS2__ 66# define finite(x) isfinite(x) 67#endif 68 69#ifdef NEED_SETENV 70extern int setenv(const char *name, const char *value, int overwrite); 71extern void unsetenv(const char *name); 72#endif 73 74/* 75 * Prototypes 76 */ 77#define NONE 0 78 79#define REMOVE 1 80#define SUBSTITUTE 2 81#define DELETE 3 82#define NSUBSTITUTE 4 83 84#define ASSOC 1 85#define MEMBER 2 86 87#define FIND 1 88#define POSITION 2 89 90#define IF 1 91#define IFNOT 2 92 93#define UNION 1 94#define INTERSECTION 2 95#define SETDIFFERENCE 3 96#define SETEXCLUSIVEOR 4 97#define SUBSETP 5 98#define NSETDIFFERENCE 6 99#define NINTERSECTION 7 100#define NUNION 8 101#define NSETEXCLUSIVEOR 9 102 103#define COPY_LIST 1 104#define COPY_ALIST 2 105#define COPY_TREE 3 106 107#define EVERY 1 108#define SOME 2 109#define NOTEVERY 3 110#define NOTANY 4 111 112/* Call directly LispObjectCompare() if possible */ 113#define FCODE(predicate) \ 114 predicate == Oeql ? FEQL : \ 115 predicate == Oequal ? FEQUAL : \ 116 predicate == Oeq ? FEQ : \ 117 predicate == Oequalp ? FEQUALP : 0 118#define FCOMPARE(predicate, left, right, code) \ 119 code == FEQ ? left == right : \ 120 code ? LispObjectCompare(left, right, code) != NIL : \ 121 APPLY2(predicate, left, right) != NIL 122 123#define FUNCTION_CHECK(predicate) \ 124 if (FUNCTIONP(predicate)) \ 125 predicate = (predicate)->data.atom->object 126 127#define CHECK_TEST_0() \ 128 if (test != UNSPEC && test_not != UNSPEC) \ 129 LispDestroy("%s: specify either :TEST or :TEST-NOT", \ 130 STRFUN(builtin)) 131 132#define CHECK_TEST() \ 133 CHECK_TEST_0(); \ 134 if (test_not == UNSPEC) { \ 135 if (test == UNSPEC) \ 136 lambda = Oeql; \ 137 else \ 138 lambda = test; \ 139 expect = 1; \ 140 } \ 141 else { \ 142 lambda = test_not; \ 143 expect = 0; \ 144 } \ 145 FUNCTION_CHECK(lambda); \ 146 code = FCODE(lambda) 147 148 149static LispObj *LispAdjoin(LispBuiltin*, 150 LispObj*, LispObj*, LispObj*, LispObj*, LispObj*); 151static LispObj *LispAssocOrMember(LispBuiltin*, int, int); 152static LispObj *LispEverySomeAnyNot(LispBuiltin*, int); 153static LispObj *LispFindOrPosition(LispBuiltin*, int, int); 154static LispObj *LispDeleteOrRemoveDuplicates(LispBuiltin*, int); 155static LispObj *LispDeleteRemoveXSubstitute(LispBuiltin*, int, int); 156static LispObj *LispListSet(LispBuiltin*, int); 157static LispObj *LispMapc(LispBuiltin*, int); 158static LispObj *LispMapl(LispBuiltin*, int); 159static LispObj *LispMapnconc(LispObj*); 160extern LispObj *LispRunSetf(LispArgList*, LispObj*, LispObj*, LispObj*); 161extern LispObj *LispRunSetfMacro(LispAtom*, LispObj*, LispObj*); 162static LispObj *LispMergeSort(LispObj*, LispObj*, LispObj*, int); 163static LispObj *LispXReverse(LispBuiltin*, int); 164static LispObj *LispCopyList(LispBuiltin*, LispObj*, int); 165static LispObj *LispValuesList(LispBuiltin*, int); 166static LispObj *LispTreeEqual(LispObj*, LispObj*, LispObj*, int); 167static LispDocType_t LispDocumentationType(LispBuiltin*, LispObj*); 168 169extern void LispSetAtomObjectProperty(LispAtom*, LispObj*); 170 171/* 172 * Initialization 173 */ 174LispObj *Oeq, *Oeql, *Oequal, *Oequalp, *Omake_array, 175 *Kinitial_contents, *Osetf, *Ootherwise, *Oquote; 176LispObj *Ogensym_counter; 177 178Atom_id Svariable, Sstructure, Stype, Ssetf; 179 180/* 181 * Implementation 182 */ 183void 184LispCoreInit(void) 185{ 186 Oeq = STATIC_ATOM("EQ"); 187 Oeql = STATIC_ATOM("EQL"); 188 Oequal = STATIC_ATOM("EQUAL"); 189 Oequalp = STATIC_ATOM("EQUALP"); 190 Omake_array = STATIC_ATOM("MAKE-ARRAY"); 191 Kinitial_contents = KEYWORD("INITIAL-CONTENTS"); 192 Osetf = STATIC_ATOM("SETF"); 193 Ootherwise = STATIC_ATOM("OTHERWISE"); 194 LispExportSymbol(Ootherwise); 195 Oquote = STATIC_ATOM("QUOTE"); 196 LispExportSymbol(Oquote); 197 198 Svariable = GETATOMID("VARIABLE"); 199 Sstructure = GETATOMID("STRUCTURE"); 200 Stype = GETATOMID("TYPE"); 201 202 /* Create as a constant so that only the C code should change the value */ 203 Ogensym_counter = STATIC_ATOM("*GENSYM-COUNTER*"); 204 LispDefconstant(Ogensym_counter, FIXNUM(0), NIL); 205 LispExportSymbol(Ogensym_counter); 206 207 Ssetf = ATOMID(Osetf); 208} 209 210LispObj * 211Lisp_Acons(LispBuiltin *builtin) 212/* 213 acons key datum alist 214 */ 215{ 216 LispObj *key, *datum, *alist; 217 218 alist = ARGUMENT(2); 219 datum = ARGUMENT(1); 220 key = ARGUMENT(0); 221 222 return (CONS(CONS(key, datum), alist)); 223} 224 225static LispObj * 226LispAdjoin(LispBuiltin*builtin, LispObj *item, LispObj *list, 227 LispObj *key, LispObj *test, LispObj *test_not) 228{ 229 GC_ENTER(); 230 int code, expect, value; 231 LispObj *lambda, *compare, *object; 232 233 CHECK_LIST(list); 234 CHECK_TEST(); 235 236 if (key != UNSPEC) { 237 item = APPLY1(key, item); 238 /* Result is not guaranteed to be gc protected */ 239 GC_PROTECT(item); 240 } 241 242 /* Check if item is not already in place */ 243 for (object = list; CONSP(object); object = CDR(object)) { 244 compare = CAR(object); 245 if (key != UNSPEC) { 246 compare = APPLY1(key, compare); 247 GC_PROTECT(compare); 248 value = FCOMPARE(lambda, item, compare, code); 249 /* Unprotect compare... */ 250 --lisp__data.protect.length; 251 } 252 else 253 value = FCOMPARE(lambda, item, compare, code); 254 255 if (value == expect) { 256 /* Item is already in list */ 257 GC_LEAVE(); 258 259 return (list); 260 } 261 } 262 GC_LEAVE(); 263 264 return (CONS(item, list)); 265} 266 267LispObj * 268Lisp_Adjoin(LispBuiltin *builtin) 269/* 270 adjoin item list &key key test test-not 271 */ 272{ 273 LispObj *item, *list, *key, *test, *test_not; 274 275 test_not = ARGUMENT(4); 276 test = ARGUMENT(3); 277 key = ARGUMENT(2); 278 list = ARGUMENT(1); 279 item = ARGUMENT(0); 280 281 return (LispAdjoin(builtin, item, list, key, test, test_not)); 282} 283 284LispObj * 285Lisp_Append(LispBuiltin *builtin) 286/* 287 append &rest lists 288 */ 289{ 290 GC_ENTER(); 291 LispObj *result, *cons, *list; 292 293 LispObj *lists; 294 295 lists = ARGUMENT(0); 296 297 /* no arguments */ 298 if (!CONSP(lists)) 299 return (NIL); 300 301 /* skip initial nil lists */ 302 for (; CONSP(CDR(lists)) && CAR(lists) == NIL; lists = CDR(lists)) 303 ; 304 305 /* last argument is not copied (even if it is the single argument) */ 306 if (!CONSP(CDR(lists))) 307 return (CAR(lists)); 308 309 /* make sure result is a list */ 310 list = CAR(lists); 311 CHECK_CONS(list); 312 result = cons = CONS(CAR(list), NIL); 313 GC_PROTECT(result); 314 for (list = CDR(list); CONSP(list); list = CDR(list)) { 315 RPLACD(cons, CONS(CAR(list), NIL)); 316 cons = CDR(cons); 317 } 318 lists = CDR(lists); 319 320 /* copy intermediate lists */ 321 for (; CONSP(CDR(lists)); lists = CDR(lists)) { 322 list = CAR(lists); 323 if (list == NIL) 324 continue; 325 /* intermediate elements must be lists */ 326 CHECK_CONS(list); 327 for (; CONSP(list); list = CDR(list)) { 328 RPLACD(cons, CONS(CAR(list), NIL)); 329 cons = CDR(cons); 330 } 331 } 332 333 /* add last element */ 334 RPLACD(cons, CAR(lists)); 335 336 GC_LEAVE(); 337 338 return (result); 339} 340 341LispObj * 342Lisp_Aref(LispBuiltin *builtin) 343/* 344 aref array &rest subscripts 345 */ 346{ 347 long c, count, idx, seq; 348 LispObj *obj, *dim; 349 350 LispObj *array, *subscripts; 351 352 subscripts = ARGUMENT(1); 353 array = ARGUMENT(0); 354 355 /* accept strings also */ 356 if (STRINGP(array) && CONSP(subscripts) && CDR(subscripts) == NIL) { 357 long offset, length = STRLEN(array); 358 359 CHECK_INDEX(CAR(subscripts)); 360 offset = FIXNUM_VALUE(CAR(subscripts)); 361 362 if (offset >= length) 363 LispDestroy("%s: index %ld too large for sequence length %ld", 364 STRFUN(builtin), offset, length); 365 366 return (SCHAR(THESTR(array)[offset])); 367 } 368 369 CHECK_ARRAY(array); 370 371 for (count = 0, dim = subscripts, obj = array->data.array.dim; CONSP(dim); 372 count++, dim = CDR(dim), obj = CDR(obj)) { 373 if (count >= array->data.array.rank) 374 LispDestroy("%s: too many subscripts %s", 375 STRFUN(builtin), STROBJ(subscripts)); 376 if (!INDEXP(CAR(dim)) || 377 FIXNUM_VALUE(CAR(dim)) >= FIXNUM_VALUE(CAR(obj))) 378 LispDestroy("%s: %s is out of range or a bad index", 379 STRFUN(builtin), STROBJ(CAR(dim))); 380 } 381 if (count < array->data.array.rank) 382 LispDestroy("%s: too few subscripts %s", 383 STRFUN(builtin), STROBJ(subscripts)); 384 385 for (count = seq = 0, dim = subscripts; CONSP(dim); dim = CDR(dim), seq++) { 386 for (idx = 0, obj = array->data.array.dim; idx < seq; 387 obj = CDR(obj), ++idx) 388 ; 389 for (c = 1, obj = CDR(obj); obj != NIL; obj = CDR(obj)) 390 c *= FIXNUM_VALUE(CAR(obj)); 391 count += c * FIXNUM_VALUE(CAR(dim)); 392 } 393 394 for (array = array->data.array.list; count > 0; array = CDR(array), count--) 395 ; 396 397 return (CAR(array)); 398} 399 400static LispObj * 401LispAssocOrMember(LispBuiltin *builtin, int function, int comparison) 402/* 403 assoc item list &key test test-not key 404 assoc-if predicate list &key key 405 assoc-if-not predicate list &key key 406 member item list &key test test-not key 407 member-if predicate list &key key 408 member-if-not predicate list &key key 409 */ 410{ 411 int code = 0, expect, value; 412 LispObj *lambda, *result, *compare; 413 414 LispObj *item, *list, *test, *test_not, *key; 415 416 if (comparison == NONE) { 417 key = ARGUMENT(4); 418 test_not = ARGUMENT(3); 419 test = ARGUMENT(2); 420 list = ARGUMENT(1); 421 item = ARGUMENT(0); 422 lambda = NIL; 423 } 424 else { 425 key = ARGUMENT(2); 426 list = ARGUMENT(1); 427 lambda = ARGUMENT(0); 428 test = test_not = UNSPEC; 429 item = NIL; 430 } 431 432 if (list == NIL) 433 return (NIL); 434 CHECK_CONS(list); 435 436 /* Resolve compare function, and expected result of comparison */ 437 if (comparison == NONE) { 438 CHECK_TEST(); 439 } 440 else 441 expect = comparison == IFNOT ? 0 : 1; 442 443 result = NIL; 444 for (; CONSP(list); list = CDR(list)) { 445 compare = CAR(list); 446 if (function == ASSOC) { 447 if (!CONSP(compare)) 448 continue; 449 compare = CAR(compare); 450 } 451 if (key != UNSPEC) 452 compare = APPLY1(key, compare); 453 454 if (comparison == NONE) 455 value = FCOMPARE(lambda, item, compare, code); 456 else 457 value = APPLY1(lambda, compare) != NIL; 458 if (value == expect) { 459 result = list; 460 if (function == ASSOC) 461 result = CAR(result); 462 break; 463 } 464 } 465 if (function == MEMBER) { 466 CHECK_LIST(list); 467 } 468 469 return (result); 470} 471 472LispObj * 473Lisp_Assoc(LispBuiltin *builtin) 474/* 475 assoc item list &key test test-not key 476 */ 477{ 478 return (LispAssocOrMember(builtin, ASSOC, NONE)); 479} 480 481LispObj * 482Lisp_AssocIf(LispBuiltin *builtin) 483/* 484 assoc-if predicate list &key key 485 */ 486{ 487 return (LispAssocOrMember(builtin, ASSOC, IF)); 488} 489 490LispObj * 491Lisp_AssocIfNot(LispBuiltin *builtin) 492/* 493 assoc-if-not predicate list &key key 494 */ 495{ 496 return (LispAssocOrMember(builtin, ASSOC, IFNOT)); 497} 498 499LispObj * 500Lisp_And(LispBuiltin *builtin) 501/* 502 and &rest args 503 */ 504{ 505 LispObj *result = T, *args; 506 507 args = ARGUMENT(0); 508 509 for (; CONSP(args); args = CDR(args)) { 510 result = EVAL(CAR(args)); 511 if (result == NIL) 512 break; 513 } 514 515 return (result); 516} 517 518LispObj * 519Lisp_Apply(LispBuiltin *builtin) 520/* 521 apply function arg &rest more-args 522 */ 523{ 524 GC_ENTER(); 525 LispObj *result, *arguments; 526 527 LispObj *function, *arg, *more_args; 528 529 more_args = ARGUMENT(2); 530 arg = ARGUMENT(1); 531 function = ARGUMENT(0); 532 533 if (more_args == NIL) { 534 CHECK_LIST(arg); 535 arguments = arg; 536 for (; CONSP(arg); arg = CDR(arg)) 537 ; 538 CHECK_LIST(arg); 539 } 540 else { 541 LispObj *cons; 542 543 CHECK_CONS(more_args); 544 arguments = cons = CONS(arg, NIL); 545 GC_PROTECT(arguments); 546 for (arg = CDR(more_args); 547 CONSP(arg); 548 more_args = arg, arg = CDR(arg)) { 549 RPLACD(cons, CONS(CAR(more_args), NIL)); 550 cons = CDR(cons); 551 } 552 more_args = CAR(more_args); 553 if (more_args != NIL) { 554 for (arg = more_args; CONSP(arg); arg = CDR(arg)) 555 ; 556 CHECK_LIST(arg); 557 RPLACD(cons, more_args); 558 } 559 } 560 561 result = APPLY(function, arguments); 562 GC_LEAVE(); 563 564 return (result); 565} 566 567LispObj * 568Lisp_Atom(LispBuiltin *builtin) 569/* 570 atom object 571 */ 572{ 573 LispObj *object; 574 575 object = ARGUMENT(0); 576 577 return (CONSP(object) ? NIL : T); 578} 579 580LispObj * 581Lisp_Block(LispBuiltin *builtin) 582/* 583 block name &rest body 584 */ 585{ 586 int did_jump, *pdid_jump = &did_jump; 587 LispObj *res, **pres = &res; 588 LispBlock *block; 589 590 LispObj *name, *body; 591 592 body = ARGUMENT(1); 593 name = ARGUMENT(0); 594 595 if (!SYMBOLP(name) && name != NIL && name != T) 596 LispDestroy("%s: %s cannot name a block", 597 STRFUN(builtin), STROBJ(name)); 598 599 *pres = NIL; 600 *pdid_jump = 1; 601 block = LispBeginBlock(name, LispBlockTag); 602 if (setjmp(block->jmp) == 0) { 603 for (; CONSP(body); body = CDR(body)) 604 res = EVAL(CAR(body)); 605 *pdid_jump = 0; 606 } 607 LispEndBlock(block); 608 if (*pdid_jump) 609 *pres = lisp__data.block.block_ret; 610 611 return (res); 612} 613 614LispObj * 615Lisp_Boundp(LispBuiltin *builtin) 616/* 617 boundp symbol 618 */ 619{ 620 LispAtom *atom; 621 622 LispObj *symbol = ARGUMENT(0); 623 624 CHECK_SYMBOL(symbol); 625 626 atom = symbol->data.atom; 627 if (atom->package == lisp__data.keyword || 628 (atom->a_object && atom->property->value != UNBOUND)) 629 return (T); 630 631 return (NIL); 632} 633 634LispObj * 635Lisp_Butlast(LispBuiltin *builtin) 636/* 637 butlast list &optional count 638 */ 639{ 640 GC_ENTER(); 641 long length, count; 642 LispObj *result, *cons, *list, *ocount; 643 644 ocount = ARGUMENT(1); 645 list = ARGUMENT(0); 646 647 CHECK_LIST(list); 648 if (ocount == UNSPEC) 649 count = 1; 650 else { 651 CHECK_INDEX(ocount); 652 count = FIXNUM_VALUE(ocount); 653 } 654 length = LispLength(list); 655 656 if (count == 0) 657 return (list); 658 else if (count >= length) 659 return (NIL); 660 661 length -= count + 1; 662 result = cons = CONS(CAR(list), NIL); 663 GC_PROTECT(result); 664 for (list = CDR(list); length > 0; list = CDR(list), length--) { 665 RPLACD(cons, CONS(CAR(list), NIL)); 666 cons = CDR(cons); 667 } 668 GC_LEAVE(); 669 670 return (result); 671} 672 673LispObj * 674Lisp_Nbutlast(LispBuiltin *builtin) 675/* 676 nbutlast list &optional count 677 */ 678{ 679 long length, count; 680 LispObj *result, *list, *ocount; 681 682 ocount = ARGUMENT(1); 683 list = ARGUMENT(0); 684 685 CHECK_LIST(list); 686 if (ocount == UNSPEC) 687 count = 1; 688 else { 689 CHECK_INDEX(ocount); 690 count = FIXNUM_VALUE(ocount); 691 } 692 length = LispLength(list); 693 694 if (count == 0) 695 return (list); 696 else if (count >= length) 697 return (NIL); 698 699 length -= count + 1; 700 result = list; 701 for (; length > 0; list = CDR(list), length--) 702 ; 703 RPLACD(list, NIL); 704 705 return (result); 706} 707 708LispObj * 709Lisp_Car(LispBuiltin *builtin) 710/* 711 car list 712 */ 713{ 714 LispObj *list, *result = NULL; 715 716 list = ARGUMENT(0); 717 718 if (list == NIL) 719 result = NIL; 720 else { 721 CHECK_CONS(list); 722 result = CAR(list); 723 } 724 725 return (result); 726} 727 728LispObj * 729Lisp_Case(LispBuiltin *builtin) 730/* 731 case keyform &rest body 732 */ 733{ 734 LispObj *result, *code, *keyform, *body, *form; 735 736 body = ARGUMENT(1); 737 keyform = ARGUMENT(0); 738 739 result = NIL; 740 keyform = EVAL(keyform); 741 742 for (; CONSP(body); body = CDR(body)) { 743 code = CAR(body); 744 CHECK_CONS(code); 745 746 form = CAR(code); 747 if (form == T || form == Ootherwise) { 748 if (CONSP(CDR(body))) 749 LispDestroy("%s: %s must be the last clause", 750 STRFUN(builtin), STROBJ(CAR(code))); 751 result = CDR(code); 752 break; 753 } 754 else if (CONSP(form)) { 755 for (; CONSP(form); form = CDR(form)) 756 if (XEQL(keyform, CAR(form)) == T) { 757 result = CDR(code); 758 break; 759 } 760 if (CONSP(form)) /* if found match */ 761 break; 762 } 763 else if (XEQL(keyform, form) == T) { 764 result = CDR(code); 765 break; 766 } 767 } 768 769 for (body = result; CONSP(body); body = CDR(body)) 770 result = EVAL(CAR(body)); 771 772 return (result); 773} 774 775LispObj * 776Lisp_Catch(LispBuiltin *builtin) 777/* 778 catch tag &rest body 779 */ 780{ 781 int did_jump, *pdid_jump = &did_jump; 782 LispObj *res, **pres = &res; 783 LispBlock *block; 784 785 LispObj *tag, *body; 786 787 body = ARGUMENT(1); 788 tag = ARGUMENT(0); 789 790 *pres = NIL; 791 *pdid_jump = 1; 792 block = LispBeginBlock(tag, LispBlockCatch); 793 if (setjmp(block->jmp) == 0) { 794 for (; CONSP(body); body = CDR(body)) 795 res = EVAL(CAR(body)); 796 *pdid_jump = 0; 797 } 798 LispEndBlock(block); 799 if (*pdid_jump) 800 *pres = lisp__data.block.block_ret; 801 802 return (res); 803} 804 805LispObj * 806Lisp_Coerce(LispBuiltin *builtin) 807/* 808 coerce object result-type 809 */ 810{ 811 LispObj *object, *result_type; 812 813 result_type = ARGUMENT(1); 814 object = ARGUMENT(0); 815 816 return (LispCoerce(builtin, object, result_type)); 817} 818 819LispObj * 820Lisp_Cdr(LispBuiltin *builtin) 821/* 822 cdr list 823 */ 824{ 825 LispObj *list, *result = NULL; 826 827 list = ARGUMENT(0); 828 829 if (list == NIL) 830 result = NIL; 831 else { 832 CHECK_CONS(list); 833 result = CDR(list); 834 } 835 836 return (result); 837} 838 839LispObj * 840Lisp_C_r(LispBuiltin *builtin) 841/* 842 c[ad]{2,4}r list 843 */ 844{ 845 char *desc; 846 847 LispObj *list, *result = NULL; 848 849 list = ARGUMENT(0); 850 851 result = list; 852 desc = STRFUN(builtin); 853 while (desc[1] != 'R') 854 ++desc; 855 while (*desc != 'C') { 856 if (result == NIL) 857 break; 858 CHECK_CONS(result); 859 result = *desc == 'A' ? CAR(result) : CDR(result); 860 --desc; 861 } 862 863 return (result); 864} 865 866LispObj * 867Lisp_Cond(LispBuiltin *builtin) 868/* 869 cond &rest body 870 */ 871{ 872 LispObj *result, *code, *body; 873 874 body = ARGUMENT(0); 875 876 result = NIL; 877 for (; CONSP(body); body = CDR(body)) { 878 code = CAR(body); 879 880 CHECK_CONS(code); 881 result = EVAL(CAR(code)); 882 if (result == NIL) 883 continue; 884 for (code = CDR(code); CONSP(code); code = CDR(code)) 885 result = EVAL(CAR(code)); 886 break; 887 } 888 889 return (result); 890} 891 892static LispObj * 893LispCopyList(LispBuiltin *builtin, LispObj *list, int function) 894{ 895 GC_ENTER(); 896 LispObj *result, *cons; 897 898 if (list == NIL) 899 return (list); 900 CHECK_CONS(list); 901 902 result = cons = CONS(NIL, NIL); 903 GC_PROTECT(result); 904 if (CONSP(CAR(list))) { 905 switch (function) { 906 case COPY_LIST: 907 RPLACA(result, CAR(list)); 908 break; 909 case COPY_ALIST: 910 RPLACA(result, CONS(CAR(CAR(list)), CDR(CAR(list)))); 911 break; 912 case COPY_TREE: 913 RPLACA(result, LispCopyList(builtin, CAR(list), COPY_TREE)); 914 break; 915 } 916 } 917 else 918 RPLACA(result, CAR(list)); 919 920 for (list = CDR(list); CONSP(list); list = CDR(list)) { 921 CDR(cons) = CONS(NIL, NIL); 922 cons = CDR(cons); 923 if (CONSP(CAR(list))) { 924 switch (function) { 925 case COPY_LIST: 926 RPLACA(cons, CAR(list)); 927 break; 928 case COPY_ALIST: 929 RPLACA(cons, CONS(CAR(CAR(list)), CDR(CAR(list)))); 930 break; 931 case COPY_TREE: 932 RPLACA(cons, LispCopyList(builtin, CAR(list), COPY_TREE)); 933 break; 934 } 935 } 936 else 937 RPLACA(cons, CAR(list)); 938 } 939 /* in case list is dotted */ 940 RPLACD(cons, list); 941 GC_LEAVE(); 942 943 return (result); 944} 945 946LispObj * 947Lisp_CopyAlist(LispBuiltin *builtin) 948/* 949 copy-alist list 950 */ 951{ 952 LispObj *list; 953 954 list = ARGUMENT(0); 955 956 return (LispCopyList(builtin, list, COPY_ALIST)); 957} 958 959LispObj * 960Lisp_CopyList(LispBuiltin *builtin) 961/* 962 copy-list list 963 */ 964{ 965 LispObj *list; 966 967 list = ARGUMENT(0); 968 969 return (LispCopyList(builtin, list, COPY_LIST)); 970} 971 972LispObj * 973Lisp_CopyTree(LispBuiltin *builtin) 974/* 975 copy-tree list 976 */ 977{ 978 LispObj *list; 979 980 list = ARGUMENT(0); 981 982 return (LispCopyList(builtin, list, COPY_TREE)); 983} 984 985LispObj * 986Lisp_Cons(LispBuiltin *builtin) 987/* 988 cons car cdr 989 */ 990{ 991 LispObj *car, *cdr; 992 993 cdr = ARGUMENT(1); 994 car = ARGUMENT(0); 995 996 return (CONS(car, cdr)); 997} 998 999LispObj * 1000Lisp_Consp(LispBuiltin *builtin) 1001/* 1002 consp object 1003 */ 1004{ 1005 LispObj *object; 1006 1007 object = ARGUMENT(0); 1008 1009 return (CONSP(object) ? T : NIL); 1010} 1011 1012LispObj * 1013Lisp_Constantp(LispBuiltin *builtin) 1014/* 1015 constantp form &optional environment 1016 */ 1017{ 1018 LispObj *form; 1019 1020 form = ARGUMENT(0); 1021 1022 /* not all self-evaluating objects are considered constants */ 1023 if (!POINTERP(form) || 1024 NUMBERP(form) || 1025 XQUOTEP(form) || 1026 (XCONSP(form) && CAR(form) == Oquote) || 1027 (XSYMBOLP(form) && form->data.atom->constant) || 1028 XSTRINGP(form) || 1029 XARRAYP(form)) 1030 return (T); 1031 1032 return (NIL); 1033} 1034 1035LispObj * 1036Lisp_Defconstant(LispBuiltin *builtin) 1037/* 1038 defconstant name initial-value &optional documentation 1039 */ 1040{ 1041 LispObj *name, *initial_value, *documentation; 1042 1043 documentation = ARGUMENT(2); 1044 initial_value = ARGUMENT(1); 1045 name = ARGUMENT(0); 1046 1047 CHECK_SYMBOL(name); 1048 if (documentation != UNSPEC) { 1049 CHECK_STRING(documentation); 1050 } 1051 else 1052 documentation = NIL; 1053 LispDefconstant(name, EVAL(initial_value), documentation); 1054 1055 return (name); 1056} 1057 1058LispObj * 1059Lisp_Defmacro(LispBuiltin *builtin) 1060/* 1061 defmacro name lambda-list &rest body 1062 */ 1063{ 1064 LispArgList *alist; 1065 1066 LispObj *lambda, *name, *lambda_list, *body; 1067 1068 body = ARGUMENT(2); 1069 lambda_list = ARGUMENT(1); 1070 name = ARGUMENT(0); 1071 1072 CHECK_SYMBOL(name); 1073 alist = LispCheckArguments(LispMacro, lambda_list, ATOMID(name), 0); 1074 1075 if (CONSP(body) && STRINGP(CAR(body))) { 1076 LispAddDocumentation(name, CAR(body), LispDocFunction); 1077 body = CDR(body); 1078 } 1079 1080 lambda_list = LispListProtectedArguments(alist); 1081 lambda = LispNewLambda(name, body, lambda_list, LispMacro); 1082 1083 if (name->data.atom->a_builtin || name->data.atom->a_compiled) { 1084 if (name->data.atom->a_builtin) { 1085 ERROR_CHECK_SPECIAL_FORM(name->data.atom); 1086 } 1087 /* redefining these may cause surprises if bytecode 1088 * compiled functions references them */ 1089 LispWarning("%s: %s is being redefined", STRFUN(builtin), ATOMID(name)); 1090 1091 LispRemAtomBuiltinProperty(name->data.atom); 1092 } 1093 1094 LispSetAtomFunctionProperty(name->data.atom, lambda, alist); 1095 LispUseArgList(alist); 1096 1097 return (name); 1098} 1099 1100LispObj * 1101Lisp_Defun(LispBuiltin *builtin) 1102/* 1103 defun name lambda-list &rest body 1104 */ 1105{ 1106 LispArgList *alist; 1107 1108 LispObj *lambda, *name, *lambda_list, *body; 1109 1110 body = ARGUMENT(2); 1111 lambda_list = ARGUMENT(1); 1112 name = ARGUMENT(0); 1113 1114 CHECK_SYMBOL(name); 1115 alist = LispCheckArguments(LispFunction, lambda_list, ATOMID(name), 0); 1116 1117 if (CONSP(body) && STRINGP(CAR(body))) { 1118 LispAddDocumentation(name, CAR(body), LispDocFunction); 1119 body = CDR(body); 1120 } 1121 1122 lambda_list = LispListProtectedArguments(alist); 1123 lambda = LispNewLambda(name, body, lambda_list, LispFunction); 1124 1125 if (name->data.atom->a_builtin || name->data.atom->a_compiled) { 1126 if (name->data.atom->a_builtin) { 1127 ERROR_CHECK_SPECIAL_FORM(name->data.atom); 1128 } 1129 /* redefining these may cause surprises if bytecode 1130 * compiled functions references them */ 1131 LispWarning("%s: %s is being redefined", STRFUN(builtin), ATOMID(name)); 1132 1133 LispRemAtomBuiltinProperty(name->data.atom); 1134 } 1135 LispSetAtomFunctionProperty(name->data.atom, lambda, alist); 1136 LispUseArgList(alist); 1137 1138 return (name); 1139} 1140 1141LispObj * 1142Lisp_Defsetf(LispBuiltin *builtin) 1143/* 1144 defsetf function lambda-list &rest body 1145 */ 1146{ 1147 LispArgList *alist; 1148 LispObj *obj; 1149 LispObj *lambda, *function, *lambda_list, *store, *body; 1150 1151 body = ARGUMENT(2); 1152 lambda_list = ARGUMENT(1); 1153 function = ARGUMENT(0); 1154 1155 CHECK_SYMBOL(function); 1156 1157 if (body == NIL || (CONSP(body) && STRINGP(CAR(body)))) { 1158 if (!SYMBOLP(lambda_list)) 1159 LispDestroy("%s: syntax error %s %s", 1160 STRFUN(builtin), STROBJ(function), STROBJ(lambda_list)); 1161 if (body != NIL) 1162 LispAddDocumentation(function, CAR(body), LispDocSetf); 1163 1164 LispSetAtomSetfProperty(function->data.atom, lambda_list, NULL); 1165 1166 return (function); 1167 } 1168 1169 alist = LispCheckArguments(LispSetf, lambda_list, ATOMID(function), 0); 1170 1171 store = CAR(body); 1172 if (!CONSP(store)) 1173 LispDestroy("%s: %s is a bad store value", 1174 STRFUN(builtin), STROBJ(store)); 1175 for (obj = store; CONSP(obj); obj = CDR(obj)) { 1176 CHECK_SYMBOL(CAR(obj)); 1177 } 1178 1179 body = CDR(body); 1180 if (CONSP(body) && STRINGP(CAR(body))) { 1181 LispAddDocumentation(function, CAR(body), LispDocSetf); 1182 body = CDR(body); 1183 } 1184 1185 lambda = LispNewLambda(function, body, store, LispSetf); 1186 LispSetAtomSetfProperty(function->data.atom, lambda, alist); 1187 LispUseArgList(alist); 1188 1189 return (function); 1190} 1191 1192LispObj * 1193Lisp_Defparameter(LispBuiltin *builtin) 1194/* 1195 defparameter name initial-value &optional documentation 1196 */ 1197{ 1198 LispObj *name, *initial_value, *documentation; 1199 1200 documentation = ARGUMENT(2); 1201 initial_value = ARGUMENT(1); 1202 name = ARGUMENT(0); 1203 1204 CHECK_SYMBOL(name); 1205 if (documentation != UNSPEC) { 1206 CHECK_STRING(documentation); 1207 } 1208 else 1209 documentation = NIL; 1210 1211 LispProclaimSpecial(name, EVAL(initial_value), documentation); 1212 1213 return (name); 1214} 1215 1216LispObj * 1217Lisp_Defvar(LispBuiltin *builtin) 1218/* 1219 defvar name &optional initial-value documentation 1220 */ 1221{ 1222 LispObj *name, *initial_value, *documentation; 1223 1224 documentation = ARGUMENT(2); 1225 initial_value = ARGUMENT(1); 1226 name = ARGUMENT(0); 1227 1228 CHECK_SYMBOL(name); 1229 if (documentation != UNSPEC) { 1230 CHECK_STRING(documentation); 1231 } 1232 else 1233 documentation = NIL; 1234 1235 LispProclaimSpecial(name, 1236 initial_value != UNSPEC ? EVAL(initial_value) : NULL, 1237 documentation); 1238 1239 return (name); 1240} 1241 1242LispObj * 1243Lisp_Delete(LispBuiltin *builtin) 1244/* 1245 delete item sequence &key from-end test test-not start end count key 1246 */ 1247{ 1248 return (LispDeleteRemoveXSubstitute(builtin, DELETE, NONE)); 1249} 1250 1251LispObj * 1252Lisp_DeleteIf(LispBuiltin *builtin) 1253/* 1254 delete-if predicate sequence &key from-end start end count key 1255 */ 1256{ 1257 return (LispDeleteRemoveXSubstitute(builtin, DELETE, IF)); 1258} 1259 1260LispObj * 1261Lisp_DeleteIfNot(LispBuiltin *builtin) 1262/* 1263 delete-if-not predicate sequence &key from-end start end count key 1264 */ 1265{ 1266 return (LispDeleteRemoveXSubstitute(builtin, DELETE, IFNOT)); 1267} 1268 1269LispObj * 1270Lisp_DeleteDuplicates(LispBuiltin *builtin) 1271/* 1272 delete-duplicates sequence &key from-end test test-not start end key 1273 */ 1274{ 1275 return (LispDeleteOrRemoveDuplicates(builtin, DELETE)); 1276} 1277 1278LispObj * 1279Lisp_Do(LispBuiltin *builtin) 1280/* 1281 do init test &rest body 1282 */ 1283{ 1284 return (LispDo(builtin, 0)); 1285} 1286 1287LispObj * 1288Lisp_DoP(LispBuiltin *builtin) 1289/* 1290 do* init test &rest body 1291 */ 1292{ 1293 return (LispDo(builtin, 1)); 1294} 1295 1296static LispDocType_t 1297LispDocumentationType(LispBuiltin *builtin, LispObj *type) 1298{ 1299 Atom_id atom; 1300 LispDocType_t doc_type = LispDocVariable; 1301 1302 CHECK_SYMBOL(type); 1303 atom = ATOMID(type); 1304 1305 if (atom == Svariable) 1306 doc_type = LispDocVariable; 1307 else if (atom == Sfunction) 1308 doc_type = LispDocFunction; 1309 else if (atom == Sstructure) 1310 doc_type = LispDocStructure; 1311 else if (atom == Stype) 1312 doc_type = LispDocType; 1313 else if (atom == Ssetf) 1314 doc_type = LispDocSetf; 1315 else { 1316 LispDestroy("%s: unknown documentation type %s", 1317 STRFUN(builtin), STROBJ(type)); 1318 /*NOTREACHED*/ 1319 } 1320 1321 return (doc_type); 1322} 1323 1324LispObj * 1325Lisp_Documentation(LispBuiltin *builtin) 1326/* 1327 documentation symbol type 1328 */ 1329{ 1330 LispObj *symbol, *type; 1331 1332 type = ARGUMENT(1); 1333 symbol = ARGUMENT(0); 1334 1335 CHECK_SYMBOL(symbol); 1336 /* type is checked in LispDocumentationType() */ 1337 1338 return (LispGetDocumentation(symbol, LispDocumentationType(builtin, type))); 1339} 1340 1341LispObj * 1342Lisp_DoList(LispBuiltin *builtin) 1343{ 1344 return (LispDoListTimes(builtin, 0)); 1345} 1346 1347LispObj * 1348Lisp_DoTimes(LispBuiltin *builtin) 1349{ 1350 return (LispDoListTimes(builtin, 1)); 1351} 1352 1353LispObj * 1354Lisp_Elt(LispBuiltin *builtin) 1355/* 1356 elt sequence index 1357 svref sequence index 1358 */ 1359{ 1360 long offset, length; 1361 LispObj *result, *sequence, *oindex; 1362 1363 oindex = ARGUMENT(1); 1364 sequence = ARGUMENT(0); 1365 1366 length = LispLength(sequence); 1367 1368 CHECK_INDEX(oindex); 1369 offset = FIXNUM_VALUE(oindex); 1370 1371 if (offset >= length) 1372 LispDestroy("%s: index %ld too large for sequence length %ld", 1373 STRFUN(builtin), offset, length); 1374 1375 if (STRINGP(sequence)) 1376 result = SCHAR(THESTR(sequence)[offset]); 1377 else { 1378 if (ARRAYP(sequence)) 1379 sequence = sequence->data.array.list; 1380 1381 for (; offset > 0; offset--, sequence = CDR(sequence)) 1382 ; 1383 result = CAR(sequence); 1384 } 1385 1386 return (result); 1387} 1388 1389LispObj * 1390Lisp_Endp(LispBuiltin *builtin) 1391/* 1392 endp object 1393 */ 1394{ 1395 LispObj *object; 1396 1397 object = ARGUMENT(0); 1398 1399 if (object == NIL) 1400 return (T); 1401 CHECK_CONS(object); 1402 1403 return (NIL); 1404} 1405 1406LispObj * 1407Lisp_Eq(LispBuiltin *builtin) 1408/* 1409 eq left right 1410 */ 1411{ 1412 LispObj *left, *right; 1413 1414 right = ARGUMENT(1); 1415 left = ARGUMENT(0); 1416 1417 return (XEQ(left, right)); 1418} 1419 1420LispObj * 1421Lisp_Eql(LispBuiltin *builtin) 1422/* 1423 eql left right 1424 */ 1425{ 1426 LispObj *left, *right; 1427 1428 right = ARGUMENT(1); 1429 left = ARGUMENT(0); 1430 1431 return (XEQL(left, right)); 1432} 1433 1434LispObj * 1435Lisp_Equal(LispBuiltin *builtin) 1436/* 1437 equal left right 1438 */ 1439{ 1440 LispObj *left, *right; 1441 1442 right = ARGUMENT(1); 1443 left = ARGUMENT(0); 1444 1445 return (XEQUAL(left, right)); 1446} 1447 1448LispObj * 1449Lisp_Equalp(LispBuiltin *builtin) 1450/* 1451 equalp left right 1452 */ 1453{ 1454 LispObj *left, *right; 1455 1456 right = ARGUMENT(1); 1457 left = ARGUMENT(0); 1458 1459 return (XEQUALP(left, right)); 1460} 1461 1462LispObj * 1463Lisp_Error(LispBuiltin *builtin) 1464/* 1465 error control-string &rest arguments 1466 */ 1467{ 1468 LispObj *string, *arglist; 1469 1470 LispObj *control_string, *arguments; 1471 1472 arguments = ARGUMENT(1); 1473 control_string = ARGUMENT(0); 1474 1475 arglist = CONS(NIL, CONS(control_string, arguments)); 1476 GC_PROTECT(arglist); 1477 string = APPLY(Oformat, arglist); 1478 LispDestroy("%s", THESTR(string)); 1479 /*NOTREACHED*/ 1480 1481 /* No need to call GC_ENTER() and GC_LEAVE() macros */ 1482 return (NIL); 1483} 1484 1485LispObj * 1486Lisp_Eval(LispBuiltin *builtin) 1487/* 1488 eval form 1489 */ 1490{ 1491 int lex; 1492 LispObj *form, *result; 1493 1494 form = ARGUMENT(0); 1495 1496 /* make sure eval form will not access local variables */ 1497 lex = lisp__data.env.lex; 1498 lisp__data.env.lex = lisp__data.env.length; 1499 result = EVAL(form); 1500 lisp__data.env.lex = lex; 1501 1502 return (result); 1503} 1504 1505static LispObj * 1506LispEverySomeAnyNot(LispBuiltin *builtin, int function) 1507/* 1508 every predicate sequence &rest more-sequences 1509 some predicate sequence &rest more-sequences 1510 notevery predicate sequence &rest more-sequences 1511 notany predicate sequence &rest more-sequences 1512 */ 1513{ 1514 GC_ENTER(); 1515 long i, j, length, count; 1516 LispObj *result, *list, *item, *arguments, *acons, *value; 1517 SeqInfo stk[8], *seqs; 1518 1519 LispObj *predicate, *sequence, *more_sequences; 1520 1521 more_sequences = ARGUMENT(2); 1522 sequence = ARGUMENT(1); 1523 predicate = ARGUMENT(0); 1524 1525 count = 1; 1526 length = LispLength(sequence); 1527 for (list = more_sequences; CONSP(list); list = CDR(list), count++) { 1528 i = LispLength(CAR(list)); 1529 if (i < length) 1530 length = i; 1531 } 1532 1533 result = function == EVERY || function == NOTANY ? T : NIL; 1534 1535 /* if at least one sequence has length zero */ 1536 if (length == 0) 1537 return (result); 1538 1539 if (count > sizeof(stk) / sizeof(stk[0])) 1540 seqs = LispMalloc(count * sizeof(SeqInfo)); 1541 else 1542 seqs = &stk[0]; 1543 1544 /* build information about sequences */ 1545 SETSEQ(seqs[0], sequence); 1546 for (i = 1, list = more_sequences; CONSP(list); list = CDR(list), i++) { 1547 item = CAR(list); 1548 SETSEQ(seqs[i], item); 1549 } 1550 1551 /* prepare argument list */ 1552 arguments = acons = CONS(NIL, NIL); 1553 GC_PROTECT(arguments); 1554 for (i = 1; i < count; i++) { 1555 RPLACD(acons, CONS(NIL, NIL)); 1556 acons = CDR(acons); 1557 } 1558 1559 /* loop applying predicate in sequence elements */ 1560 for (i = 0; i < length; i++) { 1561 1562 /* build argument list */ 1563 for (acons = arguments, j = 0; j < count; acons = CDR(acons), j++) { 1564 if (seqs[j].type == LispString_t) 1565 item = SCHAR(*seqs[j].data.string++); 1566 else { 1567 item = CAR(seqs[j].data.list); 1568 seqs[j].data.list = CDR(seqs[j].data.list); 1569 } 1570 RPLACA(acons, item); 1571 } 1572 1573 /* apply predicate */ 1574 value = APPLY(predicate, arguments); 1575 1576 /* check if needs to terminate loop */ 1577 if (value == NIL) { 1578 if (function == EVERY) { 1579 result = NIL; 1580 break; 1581 } 1582 if (function == NOTEVERY) { 1583 result = T; 1584 break; 1585 } 1586 } 1587 else { 1588 if (function == SOME) { 1589 result = value; 1590 break; 1591 } 1592 if (function == NOTANY) { 1593 result = NIL; 1594 break; 1595 } 1596 } 1597 } 1598 1599 GC_LEAVE(); 1600 if (seqs != &stk[0]) 1601 LispFree(seqs); 1602 1603 return (result); 1604} 1605 1606LispObj * 1607Lisp_Every(LispBuiltin *builtin) 1608/* 1609 every predicate sequence &rest more-sequences 1610 */ 1611{ 1612 return (LispEverySomeAnyNot(builtin, EVERY)); 1613} 1614 1615LispObj * 1616Lisp_Some(LispBuiltin *builtin) 1617/* 1618 some predicate sequence &rest more-sequences 1619 */ 1620{ 1621 return (LispEverySomeAnyNot(builtin, SOME)); 1622} 1623 1624LispObj * 1625Lisp_Notevery(LispBuiltin *builtin) 1626/* 1627 notevery predicate sequence &rest more-sequences 1628 */ 1629{ 1630 return (LispEverySomeAnyNot(builtin, NOTEVERY)); 1631} 1632 1633LispObj * 1634Lisp_Notany(LispBuiltin *builtin) 1635/* 1636 notany predicate sequence &rest more-sequences 1637 */ 1638{ 1639 return (LispEverySomeAnyNot(builtin, NOTANY)); 1640} 1641 1642LispObj * 1643Lisp_Fboundp(LispBuiltin *builtin) 1644/* 1645 fboundp symbol 1646 */ 1647{ 1648 LispAtom *atom; 1649 1650 LispObj *symbol = ARGUMENT(0); 1651 1652 CHECK_SYMBOL(symbol); 1653 1654 atom = symbol->data.atom; 1655 if (atom->a_function || atom->a_builtin || atom->a_compiled) 1656 return (T); 1657 1658 return (NIL); 1659} 1660 1661LispObj * 1662Lisp_Find(LispBuiltin *builtin) 1663/* 1664 find item sequence &key from-end test test-not start end key 1665 */ 1666{ 1667 return (LispFindOrPosition(builtin, FIND, NONE)); 1668} 1669 1670LispObj * 1671Lisp_FindIf(LispBuiltin *builtin) 1672/* 1673 find-if predicate sequence &key from-end start end key 1674 */ 1675{ 1676 return (LispFindOrPosition(builtin, FIND, IF)); 1677} 1678 1679LispObj * 1680Lisp_FindIfNot(LispBuiltin *builtin) 1681/* 1682 find-if-not predicate sequence &key from-end start end key 1683 */ 1684{ 1685 return (LispFindOrPosition(builtin, FIND, IFNOT)); 1686} 1687 1688LispObj * 1689Lisp_Fill(LispBuiltin *builtin) 1690/* 1691 fill sequence item &key start end 1692 */ 1693{ 1694 long i, start, end, length; 1695 1696 LispObj *sequence, *item, *ostart, *oend; 1697 1698 oend = ARGUMENT(3); 1699 ostart = ARGUMENT(2); 1700 item = ARGUMENT(1); 1701 sequence = ARGUMENT(0); 1702 1703 LispCheckSequenceStartEnd(builtin, sequence, ostart, oend, 1704 &start, &end, &length); 1705 1706 if (STRINGP(sequence)) { 1707 int ch; 1708 char *string = THESTR(sequence); 1709 1710 CHECK_STRING_WRITABLE(sequence); 1711 CHECK_SCHAR(item); 1712 ch = SCHAR_VALUE(item); 1713 for (i = start; i < end; i++) 1714 string[i] = ch; 1715 } 1716 else { 1717 LispObj *list; 1718 1719 if (CONSP(sequence)) 1720 list = sequence; 1721 else 1722 list = sequence->data.array.list; 1723 1724 for (i = 0; i < start; i++, list = CDR(list)) 1725 ; 1726 for (; i < end; i++, list = CDR(list)) 1727 RPLACA(list, item); 1728 } 1729 1730 return (sequence); 1731} 1732 1733LispObj * 1734Lisp_Fmakunbound(LispBuiltin *builtin) 1735/* 1736 fmkaunbound symbol 1737 */ 1738{ 1739 LispObj *symbol; 1740 1741 symbol = ARGUMENT(0); 1742 1743 CHECK_SYMBOL(symbol); 1744 if (symbol->data.atom->a_function) 1745 LispRemAtomFunctionProperty(symbol->data.atom); 1746 else if (symbol->data.atom->a_builtin) 1747 LispRemAtomBuiltinProperty(symbol->data.atom); 1748 else if (symbol->data.atom->a_compiled) 1749 LispRemAtomCompiledProperty(symbol->data.atom); 1750 1751 return (symbol); 1752} 1753 1754LispObj * 1755Lisp_Funcall(LispBuiltin *builtin) 1756/* 1757 funcall function &rest arguments 1758 */ 1759{ 1760 LispObj *result; 1761 1762 LispObj *function, *arguments; 1763 1764 arguments = ARGUMENT(1); 1765 function = ARGUMENT(0); 1766 1767 result = APPLY(function, arguments); 1768 1769 return (result); 1770} 1771 1772LispObj * 1773Lisp_Functionp(LispBuiltin *builtin) 1774/* 1775 functionp object 1776 */ 1777{ 1778 LispObj *object; 1779 1780 object = ARGUMENT(0); 1781 1782 return (FUNCTIONP(object) || LAMBDAP(object) ? T : NIL); 1783} 1784 1785LispObj * 1786Lisp_Get(LispBuiltin *builtin) 1787/* 1788 get symbol indicator &optional default 1789 */ 1790{ 1791 LispObj *result; 1792 1793 LispObj *symbol, *indicator, *defalt; 1794 1795 defalt = ARGUMENT(2); 1796 indicator = ARGUMENT(1); 1797 symbol = ARGUMENT(0); 1798 1799 CHECK_SYMBOL(symbol); 1800 1801 result = LispGetAtomProperty(symbol->data.atom, indicator); 1802 1803 if (result != NIL) 1804 result = CAR(result); 1805 else 1806 result = defalt == UNSPEC ? NIL : defalt; 1807 1808 return (result); 1809} 1810 1811/* 1812 * ext::getenv 1813 */ 1814LispObj * 1815Lisp_Getenv(LispBuiltin *builtin) 1816/* 1817 getenv name 1818 */ 1819{ 1820 char *value; 1821 1822 LispObj *name; 1823 1824 name = ARGUMENT(0); 1825 1826 CHECK_STRING(name); 1827 value = getenv(THESTR(name)); 1828 1829 return (value ? STRING(value) : NIL); 1830} 1831 1832LispObj * 1833Lisp_Gc(LispBuiltin *builtin) 1834/* 1835 gc &optional car cdr 1836 */ 1837{ 1838 LispObj *car, *cdr; 1839 1840 cdr = ARGUMENT(1); 1841 car = ARGUMENT(0); 1842 1843 LispGC(car, cdr); 1844 1845 return (NIL); 1846} 1847 1848LispObj * 1849Lisp_Gensym(LispBuiltin *builtin) 1850/* 1851 gensym &optional arg 1852 */ 1853{ 1854 char *preffix = "G", name[132]; 1855 long counter = LONGINT_VALUE(Ogensym_counter->data.atom->property->value); 1856 LispObj *symbol; 1857 1858 LispObj *arg; 1859 1860 arg = ARGUMENT(0); 1861 if (arg != UNSPEC) { 1862 if (STRINGP(arg)) 1863 preffix = THESTR(arg); 1864 else { 1865 CHECK_INDEX(arg); 1866 counter = FIXNUM_VALUE(arg); 1867 } 1868 } 1869 snprintf(name, sizeof(name), "%s%ld", preffix, counter); 1870 if (strlen(name) >= 128) 1871 LispDestroy("%s: name %s too long", STRFUN(builtin), name); 1872 Ogensym_counter->data.atom->property->value = INTEGER(counter + 1); 1873 1874 symbol = UNINTERNED_ATOM(name); 1875 symbol->data.atom->unreadable = !LispCheckAtomString(name); 1876 1877 return (symbol); 1878} 1879 1880LispObj * 1881Lisp_Go(LispBuiltin *builtin) 1882/* 1883 go tag 1884 */ 1885{ 1886 unsigned blevel = lisp__data.block.block_level; 1887 1888 LispObj *tag; 1889 1890 tag = ARGUMENT(0); 1891 1892 while (blevel) { 1893 LispBlock *block = lisp__data.block.block[--blevel]; 1894 1895 if (block->type == LispBlockClosure) 1896 /* if reached a function call */ 1897 break; 1898 if (block->type == LispBlockBody) { 1899 lisp__data.block.block_ret = tag; 1900 LispBlockUnwind(block); 1901 BLOCKJUMP(block); 1902 } 1903 } 1904 1905 LispDestroy("%s: no visible tagbody for %s", 1906 STRFUN(builtin), STROBJ(tag)); 1907 /*NOTREACHED*/ 1908 return (NIL); 1909} 1910 1911LispObj * 1912Lisp_If(LispBuiltin *builtin) 1913/* 1914 if test then &optional else 1915 */ 1916{ 1917 LispObj *result, *test, *then, *oelse; 1918 1919 oelse = ARGUMENT(2); 1920 then = ARGUMENT(1); 1921 test = ARGUMENT(0); 1922 1923 test = EVAL(test); 1924 if (test != NIL) 1925 result = EVAL(then); 1926 else if (oelse != UNSPEC) 1927 result = EVAL(oelse); 1928 else 1929 result = NIL; 1930 1931 return (result); 1932} 1933 1934LispObj * 1935Lisp_IgnoreErrors(LispBuiltin *builtin) 1936/* 1937 ignore-erros &rest body 1938 */ 1939{ 1940 LispObj *result; 1941 int i, jumped; 1942 LispBlock *block; 1943 1944 /* interpreter state */ 1945 GC_ENTER(); 1946 int stack, lex, length; 1947 1948 /* memory allocation */ 1949 int mem_level; 1950 void **mem; 1951 1952 LispObj *body; 1953 1954 body = ARGUMENT(0); 1955 1956 /* Save environment information */ 1957 stack = lisp__data.stack.length; 1958 lex = lisp__data.env.lex; 1959 length = lisp__data.env.length; 1960 1961 /* Save memory allocation information */ 1962 mem_level = lisp__data.mem.level; 1963 mem = LispMalloc(mem_level * sizeof(void*)); 1964 memcpy(mem, lisp__data.mem.mem, mem_level * sizeof(void*)); 1965 1966 ++lisp__data.ignore_errors; 1967 result = NIL; 1968 jumped = 1; 1969 block = LispBeginBlock(NIL, LispBlockProtect); 1970 if (setjmp(block->jmp) == 0) { 1971 for (; CONSP(body); body = CDR(body)) 1972 result = EVAL(CAR(body)); 1973 jumped = 0; 1974 } 1975 LispEndBlock(block); 1976 if (!lisp__data.destroyed && jumped) 1977 result = lisp__data.block.block_ret; 1978 1979 if (lisp__data.destroyed) { 1980 /* Restore environment */ 1981 lisp__data.stack.length = stack; 1982 lisp__data.env.lex = lex; 1983 lisp__data.env.head = lisp__data.env.length = length; 1984 GC_LEAVE(); 1985 1986 /* Check for possible leaks due to ignoring errors */ 1987 for (i = 0; i < mem_level; i++) { 1988 if (lisp__data.mem.mem[i] && mem[i] != lisp__data.mem.mem[i]) 1989 LispFree(lisp__data.mem.mem[i]); 1990 } 1991 for (; i < lisp__data.mem.level; i++) { 1992 if (lisp__data.mem.mem[i]) 1993 LispFree(lisp__data.mem.mem[i]); 1994 } 1995 1996 lisp__data.destroyed = 0; 1997 result = NIL; 1998 RETURN_COUNT = 1; 1999 RETURN(0) = lisp__data.error_condition; 2000 } 2001 LispFree(mem); 2002 --lisp__data.ignore_errors; 2003 2004 return (result); 2005} 2006 2007LispObj * 2008Lisp_Intersection(LispBuiltin *builtin) 2009/* 2010 intersection list1 list2 &key test test-not key 2011 */ 2012{ 2013 return (LispListSet(builtin, INTERSECTION)); 2014} 2015 2016LispObj * 2017Lisp_Nintersection(LispBuiltin *builtin) 2018/* 2019 nintersection list1 list2 &key test test-not key 2020 */ 2021{ 2022 return (LispListSet(builtin, NINTERSECTION)); 2023} 2024 2025LispObj * 2026Lisp_Keywordp(LispBuiltin *builtin) 2027/* 2028 keywordp object 2029 */ 2030{ 2031 LispObj *object; 2032 2033 object = ARGUMENT(0); 2034 2035 return (KEYWORDP(object) ? T : NIL); 2036} 2037 2038LispObj * 2039Lisp_Lambda(LispBuiltin *builtin) 2040/* 2041 lambda lambda-list &rest body 2042 */ 2043{ 2044 GC_ENTER(); 2045 LispObj *name; 2046 LispArgList *alist; 2047 2048 LispObj *lambda, *lambda_list, *body; 2049 2050 body = ARGUMENT(1); 2051 lambda_list = ARGUMENT(0); 2052 2053 alist = LispCheckArguments(LispLambda, lambda_list, Snil, 0); 2054 2055 name = OPAQUE(alist, LispArgList_t); 2056 lambda_list = LispListProtectedArguments(alist); 2057 GC_PROTECT(name); 2058 GC_PROTECT(lambda_list); 2059 lambda = LispNewLambda(name, body, lambda_list, LispLambda); 2060 LispUseArgList(alist); 2061 GC_LEAVE(); 2062 2063 return (lambda); 2064} 2065 2066LispObj * 2067Lisp_Last(LispBuiltin *builtin) 2068/* 2069 last list &optional count 2070 */ 2071{ 2072 long count, length; 2073 LispObj *list, *ocount; 2074 2075 ocount = ARGUMENT(1); 2076 list = ARGUMENT(0); 2077 2078 if (!CONSP(list)) 2079 return (list); 2080 2081 length = LispLength(list); 2082 2083 if (ocount == UNSPEC) 2084 count = 1; 2085 else { 2086 CHECK_INDEX(ocount); 2087 count = FIXNUM_VALUE(ocount); 2088 } 2089 2090 if (count >= length) 2091 return (list); 2092 2093 length -= count; 2094 for (; length > 0; length--) 2095 list = CDR(list); 2096 2097 return (list); 2098} 2099 2100LispObj * 2101Lisp_Length(LispBuiltin *builtin) 2102/* 2103 length sequence 2104 */ 2105{ 2106 LispObj *sequence; 2107 2108 sequence = ARGUMENT(0); 2109 2110 return (FIXNUM(LispLength(sequence))); 2111} 2112 2113LispObj * 2114Lisp_Let(LispBuiltin *builtin) 2115/* 2116 let init &rest body 2117 */ 2118{ 2119 GC_ENTER(); 2120 int head = lisp__data.env.length; 2121 LispObj *init, *body, *pair, *result, *list, *cons = NIL; 2122 2123 body = ARGUMENT(1); 2124 init = ARGUMENT(0); 2125 2126 CHECK_LIST(init); 2127 for (list = NIL; CONSP(init); init = CDR(init)) { 2128 LispObj *symbol, *value; 2129 2130 pair = CAR(init); 2131 if (SYMBOLP(pair)) { 2132 symbol = pair; 2133 value = NIL; 2134 } 2135 else { 2136 CHECK_CONS(pair); 2137 symbol = CAR(pair); 2138 CHECK_SYMBOL(symbol); 2139 pair = CDR(pair); 2140 if (CONSP(pair)) { 2141 value = CAR(pair); 2142 if (CDR(pair) != NIL) 2143 LispDestroy("%s: too much arguments to initialize %s", 2144 STRFUN(builtin), STROBJ(symbol)); 2145 value = EVAL(value); 2146 } 2147 else 2148 value = NIL; 2149 } 2150 pair = CONS(symbol, value); 2151 if (list == NIL) { 2152 list = cons = CONS(pair, NIL); 2153 GC_PROTECT(list); 2154 } 2155 else { 2156 RPLACD(cons, CONS(pair, NIL)); 2157 cons = CDR(cons); 2158 } 2159 } 2160 /* Add variables */ 2161 for (; CONSP(list); list = CDR(list)) { 2162 pair = CAR(list); 2163 CHECK_CONSTANT(CAR(pair)); 2164 LispAddVar(CAR(pair), CDR(pair)); 2165 ++lisp__data.env.head; 2166 } 2167 /* Values of symbols are now protected */ 2168 GC_LEAVE(); 2169 2170 /* execute body */ 2171 for (result = NIL; CONSP(body); body = CDR(body)) 2172 result = EVAL(CAR(body)); 2173 2174 lisp__data.env.head = lisp__data.env.length = head; 2175 2176 return (result); 2177} 2178 2179LispObj * 2180Lisp_LetP(LispBuiltin *builtin) 2181/* 2182 let* init &rest body 2183 */ 2184{ 2185 int head = lisp__data.env.length; 2186 LispObj *init, *body, *pair, *result; 2187 2188 body = ARGUMENT(1); 2189 init = ARGUMENT(0); 2190 2191 CHECK_LIST(init); 2192 for (; CONSP(init); init = CDR(init)) { 2193 LispObj *symbol, *value; 2194 2195 pair = CAR(init); 2196 if (SYMBOLP(pair)) { 2197 symbol = pair; 2198 value = NIL; 2199 } 2200 else { 2201 CHECK_CONS(pair); 2202 symbol = CAR(pair); 2203 CHECK_SYMBOL(symbol); 2204 pair = CDR(pair); 2205 if (CONSP(pair)) { 2206 value = CAR(pair); 2207 if (CDR(pair) != NIL) 2208 LispDestroy("%s: too much arguments to initialize %s", 2209 STRFUN(builtin), STROBJ(symbol)); 2210 value = EVAL(value); 2211 } 2212 else 2213 value = NIL; 2214 } 2215 2216 CHECK_CONSTANT(symbol); 2217 LispAddVar(symbol, value); 2218 ++lisp__data.env.head; 2219 } 2220 2221 /* execute body */ 2222 for (result = NIL; CONSP(body); body = CDR(body)) 2223 result = EVAL(CAR(body)); 2224 2225 lisp__data.env.head = lisp__data.env.length = head; 2226 2227 return (result); 2228} 2229 2230LispObj * 2231Lisp_List(LispBuiltin *builtin) 2232/* 2233 list &rest args 2234 */ 2235{ 2236 LispObj *args; 2237 2238 args = ARGUMENT(0); 2239 2240 return (args); 2241} 2242 2243LispObj * 2244Lisp_ListP(LispBuiltin *builtin) 2245/* 2246 list* object &rest more-objects 2247 */ 2248{ 2249 GC_ENTER(); 2250 LispObj *result, *cons; 2251 2252 LispObj *object, *more_objects; 2253 2254 more_objects = ARGUMENT(1); 2255 object = ARGUMENT(0); 2256 2257 if (!CONSP(more_objects)) 2258 return (object); 2259 2260 result = cons = CONS(object, CAR(more_objects)); 2261 GC_PROTECT(result); 2262 for (more_objects = CDR(more_objects); CONSP(more_objects); 2263 more_objects = CDR(more_objects)) { 2264 object = CAR(more_objects); 2265 RPLACD(cons, CONS(CDR(cons), object)); 2266 cons = CDR(cons); 2267 } 2268 GC_LEAVE(); 2269 2270 return (result); 2271} 2272 2273/* "classic" list-length */ 2274LispObj * 2275Lisp_ListLength(LispBuiltin *builtin) 2276/* 2277 list-length list 2278 */ 2279{ 2280 long length; 2281 LispObj *fast, *slow; 2282 2283 LispObj *list; 2284 2285 list = ARGUMENT(0); 2286 2287 CHECK_LIST(list); 2288 for (fast = slow = list, length = 0; 2289 CONSP(slow); 2290 slow = CDR(slow), length += 2) { 2291 if (fast == NIL) 2292 break; 2293 CHECK_CONS(fast); 2294 fast = CDR(fast); 2295 if (fast == NIL) { 2296 ++length; 2297 break; 2298 } 2299 CHECK_CONS(fast); 2300 fast = CDR(fast); 2301 if (slow == fast) 2302 /* circular list */ 2303 return (NIL); 2304 } 2305 2306 return (FIXNUM(length)); 2307} 2308 2309LispObj * 2310Lisp_Listp(LispBuiltin *builtin) 2311/* 2312 listp object 2313 */ 2314{ 2315 LispObj *object; 2316 2317 object = ARGUMENT(0); 2318 2319 return (object == NIL || CONSP(object) ? T : NIL); 2320} 2321 2322static LispObj * 2323LispListSet(LispBuiltin *builtin, int function) 2324/* 2325 intersection list1 list2 &key test test-not key 2326 nintersection list1 list2 &key test test-not key 2327 set-difference list1 list2 &key test test-not key 2328 nset-difference list1 list2 &key test test-not key 2329 set-exclusive-or list1 list2 &key test test-not key 2330 nset-exclusive-or list1 list2 &key test test-not key 2331 subsetp list1 list2 &key test test-not key 2332 union list1 list2 &key test test-not key 2333 nunion list1 list2 &key test test-not key 2334 */ 2335{ 2336 GC_ENTER(); 2337 int code, expect, value, inplace, check_list2, 2338 intersection, setdifference, xunion, setexclusiveor; 2339 LispObj *lambda, *result, *cmp, *cmp1, *cmp2, 2340 *item, *clist1, *clist2, *cons, *cdr; 2341 2342 LispObj *list1, *list2, *test, *test_not, *key; 2343 2344 key = ARGUMENT(4); 2345 test_not = ARGUMENT(3); 2346 test = ARGUMENT(2); 2347 list2 = ARGUMENT(1); 2348 list1 = ARGUMENT(0); 2349 2350 /* Check if arguments are valid lists */ 2351 CHECK_LIST(list1); 2352 CHECK_LIST(list2); 2353 2354 setdifference = intersection = xunion = setexclusiveor = inplace = 0; 2355 switch (function) { 2356 case NSETDIFFERENCE: 2357 inplace = 1; 2358 case SETDIFFERENCE: 2359 setdifference = 1; 2360 break; 2361 case NINTERSECTION: 2362 inplace = 1; 2363 case INTERSECTION: 2364 intersection = 1; 2365 break; 2366 case NUNION: 2367 inplace = 1; 2368 case UNION: 2369 xunion = 1; 2370 break; 2371 case NSETEXCLUSIVEOR: 2372 inplace = 1; 2373 case SETEXCLUSIVEOR: 2374 setexclusiveor = 1; 2375 break; 2376 } 2377 2378 /* Check for fast return */ 2379 if (list1 == NIL) 2380 return (setdifference || intersection ? 2381 NIL : function == SUBSETP ? T : list2); 2382 if (list2 == NIL) 2383 return (intersection || xunion || function == SUBSETP ? NIL : list1); 2384 2385 CHECK_TEST(); 2386 clist1 = cdr = NIL; 2387 2388 /* Make a copy of list2 with the key predicate applied */ 2389 if (key != UNSPEC) { 2390 result = cons = CONS(APPLY1(key, CAR(list2)), NIL); 2391 GC_PROTECT(result); 2392 for (cmp2 = CDR(list2); CONSP(cmp2); cmp2 = CDR(cmp2)) { 2393 item = APPLY1(key, CAR(cmp2)); 2394 RPLACD(cons, CONS(APPLY1(key, CAR(cmp2)), NIL)); 2395 cons = CDR(cons); 2396 } 2397 /* check if list2 is a proper list */ 2398 CHECK_LIST(cmp2); 2399 clist2 = result; 2400 check_list2 = 0; 2401 } 2402 else { 2403 clist2 = list2; 2404 check_list2 = 1; 2405 } 2406 result = cons = NIL; 2407 2408 /* Compare elements of lists 2409 * Logic: 2410 * UNION 2411 * 1) Walk list1 and if CAR(list1) not in list2, add it to result 2412 * 2) Add list2 to result 2413 * INTERSECTION 2414 * 1) Walk list1 and if CAR(list1) in list2, add it to result 2415 * SET-DIFFERENCE 2416 * 1) Walk list1 and if CAR(list1) not in list2, add it to result 2417 * SET-EXCLUSIVE-OR 2418 * 1) Walk list1 and if CAR(list1) not in list2, add it to result 2419 * 2) Walk list2 and if CAR(list2) not in list1, add it to result 2420 * SUBSETP 2421 * 1) Walk list1 and if CAR(list1) not in list2, return NIL 2422 * 2) Return T 2423 */ 2424 value = 0; 2425 for (cmp1 = list1; CONSP(cmp1); cmp1 = CDR(cmp1)) { 2426 item = CAR(cmp1); 2427 2428 /* Apply key predicate if required */ 2429 if (key != UNSPEC) { 2430 cmp = APPLY1(key, item); 2431 if (setexclusiveor) { 2432 if (clist1 == NIL) { 2433 clist1 = cdr = CONS(cmp, NIL); 2434 GC_PROTECT(clist1); 2435 } 2436 else { 2437 RPLACD(cdr, CONS(cmp, NIL)); 2438 cdr = CDR(cdr); 2439 } 2440 } 2441 } 2442 else 2443 cmp = item; 2444 2445 /* Compare against list2 */ 2446 for (cmp2 = clist2; CONSP(cmp2); cmp2 = CDR(cmp2)) { 2447 value = FCOMPARE(lambda, cmp, CAR(cmp2), code); 2448 if (value == expect) 2449 break; 2450 } 2451 if (check_list2 && value != expect) { 2452 /* check if list2 is a proper list */ 2453 CHECK_LIST(cmp2); 2454 check_list2 = 0; 2455 } 2456 2457 if (function == SUBSETP) { 2458 /* Element of list1 not in list2? */ 2459 if (value != expect) { 2460 GC_LEAVE(); 2461 2462 return (NIL); 2463 } 2464 } 2465 /* If need to add item to result */ 2466 else if (((setdifference || xunion || setexclusiveor) && 2467 value != expect) || 2468 (intersection && value == expect)) { 2469 if (inplace) { 2470 if (result == NIL) 2471 result = cons = cmp1; 2472 else { 2473 if (setexclusiveor) { 2474 /* don't remove elements yet, will need 2475 * to check agains't list2 later */ 2476 for (cmp2 = cons; CDR(cmp2) != cmp1; cmp2 = CDR(cmp2)) 2477 ; 2478 if (cmp2 != cons) { 2479 RPLACD(cmp2, list1); 2480 list1 = cmp2; 2481 } 2482 } 2483 RPLACD(cons, cmp1); 2484 cons = cmp1; 2485 } 2486 } 2487 else { 2488 if (result == NIL) { 2489 result = cons = CONS(item, NIL); 2490 GC_PROTECT(result); 2491 } 2492 else { 2493 RPLACD(cons, CONS(item, NIL)); 2494 cons = CDR(cons); 2495 } 2496 } 2497 } 2498 } 2499 /* check if list1 is a proper list */ 2500 CHECK_LIST(cmp1); 2501 2502 if (function == SUBSETP) { 2503 GC_LEAVE(); 2504 2505 return (T); 2506 } 2507 else if (xunion) { 2508 /* Add list2 to tail of result */ 2509 if (result == NIL) 2510 result = list2; 2511 else 2512 RPLACD(cons, list2); 2513 } 2514 else if (setexclusiveor) { 2515 LispObj *result2, *cons2; 2516 2517 result2 = cons2 = NIL; 2518 for (cmp2 = list2; CONSP(cmp2); cmp2 = CDR(cmp2)) { 2519 item = CAR(cmp2); 2520 2521 if (key != UNSPEC) { 2522 cmp = CAR(clist2); 2523 /* XXX changing clist2 */ 2524 clist2 = CDR(clist2); 2525 cmp1 = clist1; 2526 } 2527 else { 2528 cmp = item; 2529 cmp1 = list1; 2530 } 2531 2532 /* Compare against list1 */ 2533 for (; CONSP(cmp1); cmp1 = CDR(cmp1)) { 2534 value = FCOMPARE(lambda, cmp, CAR(cmp1), code); 2535 if (value == expect) 2536 break; 2537 } 2538 2539 if (value != expect) { 2540 if (inplace) { 2541 if (result2 == NIL) 2542 result2 = cons2 = cmp2; 2543 else { 2544 RPLACD(cons2, cmp2); 2545 cons2 = cmp2; 2546 } 2547 } 2548 else { 2549 if (result == NIL) { 2550 result = cons = CONS(item, NIL); 2551 GC_PROTECT(result); 2552 } 2553 else { 2554 RPLACD(cons, CONS(item, NIL)); 2555 cons = CDR(cons); 2556 } 2557 } 2558 } 2559 } 2560 if (inplace) { 2561 if (CONSP(cons2)) 2562 RPLACD(cons2, NIL); 2563 if (result == NIL) 2564 result = result2; 2565 else 2566 RPLACD(cons, result2); 2567 } 2568 } 2569 else if ((function == NSETDIFFERENCE || function == NINTERSECTION) && 2570 CONSP(cons)) 2571 RPLACD(cons, NIL); 2572 2573 GC_LEAVE(); 2574 2575 return (result); 2576} 2577 2578LispObj * 2579Lisp_Loop(LispBuiltin *builtin) 2580/* 2581 loop &rest body 2582 */ 2583{ 2584 LispObj *code, *result; 2585 LispBlock *block; 2586 2587 LispObj *body; 2588 2589 body = ARGUMENT(0); 2590 2591 result = NIL; 2592 block = LispBeginBlock(NIL, LispBlockTag); 2593 if (setjmp(block->jmp) == 0) { 2594 for (;;) 2595 for (code = body; CONSP(code); code = CDR(code)) 2596 (void)EVAL(CAR(code)); 2597 } 2598 LispEndBlock(block); 2599 result = lisp__data.block.block_ret; 2600 2601 return (result); 2602} 2603 2604/* XXX This function is broken, needs a review 2605 (being delayed until true array/vectors be implemented) */ 2606LispObj * 2607Lisp_MakeArray(LispBuiltin *builtin) 2608/* 2609 make-array dimensions &key element-type initial-element initial-contents 2610 adjustable fill-pointer displaced-to 2611 displaced-index-offset 2612 */ 2613{ 2614 long rank = 0, count = 1, offset, zero, c; 2615 LispObj *obj, *dim, *array; 2616 LispType type; 2617 2618 LispObj *dimensions, *element_type, *initial_element, *initial_contents, 2619 *displaced_to, *displaced_index_offset; 2620 2621 dim = array = NIL; 2622 type = LispNil_t; 2623 2624 displaced_index_offset = ARGUMENT(7); 2625 displaced_to = ARGUMENT(6); 2626 initial_contents = ARGUMENT(3); 2627 initial_element = ARGUMENT(2); 2628 element_type = ARGUMENT(1); 2629 dimensions = ARGUMENT(0); 2630 2631 if (INDEXP(dimensions)) { 2632 dim = CONS(dimensions, NIL); 2633 rank = 1; 2634 count = FIXNUM_VALUE(dimensions); 2635 } 2636 else if (CONSP(dimensions)) { 2637 dim = dimensions; 2638 2639 for (rank = 0; CONSP(dim); rank++, dim = CDR(dim)) { 2640 obj = CAR(dim); 2641 CHECK_INDEX(obj); 2642 count *= FIXNUM_VALUE(obj); 2643 } 2644 dim = dimensions; 2645 } 2646 else if (dimensions == NIL) { 2647 dim = NIL; 2648 rank = count = 0; 2649 } 2650 else 2651 LispDestroy("%s: %s is a bad array dimension", 2652 STRFUN(builtin), STROBJ(dimensions)); 2653 2654 /* check element-type */ 2655 if (element_type != UNSPEC) { 2656 if (element_type == T) 2657 type = LispNil_t; 2658 else if (!SYMBOLP(element_type)) 2659 LispDestroy("%s: unsupported element type %s", 2660 STRFUN(builtin), STROBJ(element_type)); 2661 else { 2662 Atom_id atom = ATOMID(element_type); 2663 2664 if (atom == Satom) 2665 type = LispAtom_t; 2666 else if (atom == Sinteger) 2667 type = LispInteger_t; 2668 else if (atom == Scharacter) 2669 type = LispSChar_t; 2670 else if (atom == Sstring) 2671 type = LispString_t; 2672 else if (atom == Slist) 2673 type = LispCons_t; 2674 else if (atom == Sopaque) 2675 type = LispOpaque_t; 2676 else 2677 LispDestroy("%s: unsupported element type %s", 2678 STRFUN(builtin), ATOMID(element_type)); 2679 } 2680 } 2681 2682 /* check initial-contents */ 2683 if (rank) { 2684 CHECK_LIST(initial_contents); 2685 } 2686 2687 /* check displaced-to */ 2688 if (displaced_to != UNSPEC) { 2689 CHECK_ARRAY(displaced_to); 2690 } 2691 2692 /* check displaced-index-offset */ 2693 offset = -1; 2694 if (displaced_index_offset != UNSPEC) { 2695 CHECK_INDEX(displaced_index_offset); 2696 offset = FIXNUM_VALUE(displaced_index_offset); 2697 } 2698 2699 c = 0; 2700 if (initial_element != UNSPEC) 2701 ++c; 2702 if (initial_contents != UNSPEC) 2703 ++c; 2704 if (displaced_to != UNSPEC || offset >= 0) 2705 ++c; 2706 if (c > 1) 2707 LispDestroy("%s: more than one initialization specified", 2708 STRFUN(builtin)); 2709 if (initial_element == UNSPEC) 2710 initial_element = NIL; 2711 2712 zero = count == 0; 2713 if (displaced_to != UNSPEC) { 2714 CHECK_ARRAY(displaced_to); 2715 if (offset < 0) 2716 offset = 0; 2717 for (c = 1, obj = displaced_to->data.array.dim; obj != NIL; 2718 obj = CDR(obj)) 2719 c *= FIXNUM_VALUE(CAR(obj)); 2720 if (c < count + offset) 2721 LispDestroy("%s: array-total-size + displaced-index-offset " 2722 "exceeds total size", STRFUN(builtin)); 2723 for (c = 0, array = displaced_to->data.array.list; c < offset; c++) 2724 array = CDR(array); 2725 } 2726 else if (initial_contents != UNSPEC) { 2727 CHECK_CONS(initial_contents); 2728 if (rank == 0) 2729 array = initial_contents; 2730 else if (rank == 1) { 2731 for (array = initial_contents, c = 0; c < count; 2732 array = CDR(array), c++) 2733 if (!CONSP(array)) 2734 LispDestroy("%s: bad argument or size %s", 2735 STRFUN(builtin), STROBJ(array)); 2736 if (array != NIL) 2737 LispDestroy("%s: bad argument or size %s", 2738 STRFUN(builtin), STROBJ(array)); 2739 array = initial_contents; 2740 } 2741 else { 2742 LispObj *err = NIL; 2743 /* check if list matches */ 2744 int i, j, k, *dims, *loop; 2745 2746 /* create iteration variables */ 2747 dims = LispMalloc(sizeof(int) * rank); 2748 loop = LispCalloc(1, sizeof(int) * (rank - 1)); 2749 for (i = 0, obj = dim; CONSP(obj); i++, obj = CDR(obj)) 2750 dims[i] = FIXNUM_VALUE(CAR(obj)); 2751 2752 /* check if list matches specified dimensions */ 2753 while (loop[0] < dims[0]) { 2754 for (obj = initial_contents, i = 0; i < rank - 1; i++) { 2755 for (j = 0; j < loop[i]; j++) 2756 obj = CDR(obj); 2757 err = obj; 2758 if (!CONSP(obj = CAR(obj))) 2759 goto make_array_error; 2760 err = obj; 2761 } 2762 --i; 2763 for (;;) { 2764 ++loop[i]; 2765 if (i && loop[i] >= dims[i]) 2766 loop[i] = 0; 2767 else 2768 break; 2769 --i; 2770 } 2771 for (k = 0; k < dims[rank - 1]; obj = CDR(obj), k++) { 2772 if (!CONSP(obj)) 2773 goto make_array_error; 2774 } 2775 if (obj == NIL) 2776 continue; 2777make_array_error: 2778 LispFree(dims); 2779 LispFree(loop); 2780 LispDestroy("%s: bad argument or size %s", 2781 STRFUN(builtin), STROBJ(err)); 2782 } 2783 2784 /* list is correct, use it to fill initial values */ 2785 2786 /* reset loop */ 2787 memset(loop, 0, sizeof(int) * (rank - 1)); 2788 2789 GCDisable(); 2790 /* fill array with supplied values */ 2791 array = NIL; 2792 while (loop[0] < dims[0]) { 2793 for (obj = initial_contents, i = 0; i < rank - 1; i++) { 2794 for (j = 0; j < loop[i]; j++) 2795 obj = CDR(obj); 2796 obj = CAR(obj); 2797 } 2798 --i; 2799 for (;;) { 2800 ++loop[i]; 2801 if (i && loop[i] >= dims[i]) 2802 loop[i] = 0; 2803 else 2804 break; 2805 --i; 2806 } 2807 for (k = 0; k < dims[rank - 1]; obj = CDR(obj), k++) { 2808 if (array == NIL) 2809 array = CONS(CAR(obj), NIL); 2810 else { 2811 RPLACD(array, CONS(CAR(array), CDR(array))); 2812 RPLACA(array, CAR(obj)); 2813 } 2814 } 2815 } 2816 LispFree(dims); 2817 LispFree(loop); 2818 array = LispReverse(array); 2819 GCEnable(); 2820 } 2821 } 2822 else { 2823 GCDisable(); 2824 /* allocate array */ 2825 if (count) { 2826 --count; 2827 array = CONS(initial_element, NIL); 2828 while (count) { 2829 RPLACD(array, CONS(CAR(array), CDR(array))); 2830 RPLACA(array, initial_element); 2831 count--; 2832 } 2833 } 2834 GCEnable(); 2835 } 2836 2837 obj = LispNew(array, dim); 2838 obj->type = LispArray_t; 2839 obj->data.array.list = array; 2840 obj->data.array.dim = dim; 2841 obj->data.array.rank = rank; 2842 obj->data.array.type = type; 2843 obj->data.array.zero = zero; 2844 2845 return (obj); 2846} 2847 2848LispObj * 2849Lisp_MakeList(LispBuiltin *builtin) 2850/* 2851 make-list size &key initial-element 2852 */ 2853{ 2854 GC_ENTER(); 2855 long count; 2856 LispObj *result, *cons; 2857 2858 LispObj *size, *initial_element; 2859 2860 initial_element = ARGUMENT(1); 2861 size = ARGUMENT(0); 2862 2863 CHECK_INDEX(size); 2864 count = FIXNUM_VALUE(size); 2865 2866 if (count == 0) 2867 return (NIL); 2868 if (initial_element == UNSPEC) 2869 initial_element = NIL; 2870 2871 result = cons = CONS(initial_element, NIL); 2872 GC_PROTECT(result); 2873 for (; count > 1; count--) { 2874 RPLACD(cons, CONS(initial_element, NIL)); 2875 cons = CDR(cons); 2876 } 2877 GC_LEAVE(); 2878 2879 return (result); 2880} 2881 2882LispObj * 2883Lisp_MakeSymbol(LispBuiltin *builtin) 2884/* 2885 make-symbol name 2886 */ 2887{ 2888 LispObj *name, *symbol; 2889 2890 name = ARGUMENT(0); 2891 CHECK_STRING(name); 2892 2893 symbol = UNINTERNED_ATOM(THESTR(name)); 2894 symbol->data.atom->unreadable = !LispCheckAtomString(THESTR(name)); 2895 2896 return (symbol); 2897} 2898 2899LispObj * 2900Lisp_Makunbound(LispBuiltin *builtin) 2901/* 2902 makunbound symbol 2903 */ 2904{ 2905 LispObj *symbol; 2906 2907 symbol = ARGUMENT(0); 2908 2909 CHECK_SYMBOL(symbol); 2910 LispUnsetVar(symbol); 2911 2912 return (symbol); 2913} 2914 2915LispObj * 2916Lisp_Mapc(LispBuiltin *builtin) 2917/* 2918 mapc function list &rest more-lists 2919 */ 2920{ 2921 return (LispMapc(builtin, 0)); 2922} 2923 2924LispObj * 2925Lisp_Mapcar(LispBuiltin *builtin) 2926/* 2927 mapcar function list &rest more-lists 2928 */ 2929{ 2930 return (LispMapc(builtin, 1)); 2931} 2932 2933/* Like nconc but ignore non list arguments */ 2934LispObj * 2935LispMapnconc(LispObj *list) 2936{ 2937 LispObj *result = NIL; 2938 2939 if (CONSP(list)) { 2940 LispObj *cons, *head, *tail; 2941 2942 cons = NIL; 2943 for (; CONSP(CDR(list)); list = CDR(list)) { 2944 head = CAR(list); 2945 if (CONSP(head)) { 2946 for (tail = head; CONSP(CDR(tail)); tail = CDR(tail)) 2947 ; 2948 if (cons != NIL) 2949 RPLACD(cons, head); 2950 else 2951 result = head; 2952 cons = tail; 2953 } 2954 } 2955 head = CAR(list); 2956 if (CONSP(head)) { 2957 if (cons != NIL) 2958 RPLACD(cons, head); 2959 else 2960 result = head; 2961 } 2962 } 2963 2964 return (result); 2965} 2966 2967LispObj * 2968Lisp_Mapcan(LispBuiltin *builtin) 2969/* 2970 mapcan function list &rest more-lists 2971 */ 2972{ 2973 return (LispMapnconc(LispMapc(builtin, 1))); 2974} 2975 2976static LispObj * 2977LispMapc(LispBuiltin *builtin, int mapcar) 2978{ 2979 GC_ENTER(); 2980 long i, offset, count, length; 2981 LispObj *result = NIL, *cons, *arguments, *acons, *rest, *alist, *value; 2982 LispObj *stk[8], **cdrs; 2983 2984 LispObj *function, *list, *more_lists; 2985 2986 more_lists = ARGUMENT(2); 2987 list = ARGUMENT(1); 2988 function = ARGUMENT(0); 2989 2990 /* Result will be no longer than this */ 2991 for (length = 0, alist = list; CONSP(alist); length++, alist = CDR(alist)) 2992 ; 2993 2994 /* If first argument is not a list... */ 2995 if (length == 0) 2996 return (NIL); 2997 2998 /* At least one argument will be passed to function, count how many 2999 * extra arguments will be used, and calculate result length. */ 3000 count = 0; 3001 for (rest = more_lists; CONSP(rest); rest = CDR(rest), count++) { 3002 3003 /* Check if extra list is really a list, and if it is smaller 3004 * than the first list */ 3005 for (i = 0, alist = CAR(rest); 3006 i < length && CONSP(alist); 3007 i++, alist = CDR(alist)) 3008 ; 3009 3010 /* If it is not a true list */ 3011 if (i == 0) 3012 return (NIL); 3013 3014 /* If it is smaller than the currently calculated result length */ 3015 if (i < length) 3016 length = i; 3017 } 3018 3019 if (mapcar) { 3020 /* Initialize gc protected object cells for resulting list */ 3021 result = cons = CONS(NIL, NIL); 3022 GC_PROTECT(result); 3023 } 3024 else 3025 result = cons = list; 3026 3027 if (count >= sizeof(stk) / sizeof(stk[0])) 3028 cdrs = LispMalloc(count * sizeof(LispObj*)); 3029 else 3030 cdrs = &stk[0]; 3031 for (i = 0, rest = more_lists; i < count; i++, rest = CDR(rest)) 3032 cdrs[i] = CAR(rest); 3033 3034 /* Initialize gc protected object cells for argument list */ 3035 arguments = acons = CONS(NIL, NIL); 3036 GC_PROTECT(arguments); 3037 3038 /* Allocate space for extra arguments */ 3039 for (i = 0; i < count; i++) { 3040 RPLACD(acons, CONS(NIL, NIL)); 3041 acons = CDR(acons); 3042 } 3043 3044 /* For every element of the list that will be used */ 3045 for (offset = 0;; list = CDR(list)) { 3046 acons = arguments; 3047 3048 /* Add first argument */ 3049 RPLACA(acons, CAR(list)); 3050 acons = CDR(acons); 3051 3052 /* For every extra list argument */ 3053 for (i = 0; i < count; i++) { 3054 alist = cdrs[i]; 3055 cdrs[i] = CDR(cdrs[i]); 3056 3057 /* Add element to argument list */ 3058 RPLACA(acons, CAR(alist)); 3059 acons = CDR(acons); 3060 } 3061 3062 value = APPLY(function, arguments); 3063 3064 if (mapcar) { 3065 /* Store result */ 3066 RPLACA(cons, value); 3067 3068 /* Allocate new result cell */ 3069 if (++offset < length) { 3070 RPLACD(cons, CONS(NIL, NIL)); 3071 cons = CDR(cons); 3072 } 3073 else 3074 break; 3075 } 3076 else if (++offset >= length) 3077 break; 3078 } 3079 3080 /* Unprotect argument and result list */ 3081 GC_LEAVE(); 3082 if (cdrs != &stk[0]) 3083 LispFree(cdrs); 3084 3085 return (result); 3086} 3087 3088static LispObj * 3089LispMapl(LispBuiltin *builtin, int maplist) 3090{ 3091 GC_ENTER(); 3092 long i, offset, count, length; 3093 LispObj *result = NIL, *cons, *arguments, *acons, *rest, *alist, *value; 3094 LispObj *stk[8], **cdrs; 3095 3096 LispObj *function, *list, *more_lists; 3097 3098 more_lists = ARGUMENT(2); 3099 list = ARGUMENT(1); 3100 function = ARGUMENT(0); 3101 3102 /* count is the number of lists, length is the length of the result */ 3103 for (length = 0, alist = list; CONSP(alist); length++, alist = CDR(alist)) 3104 ; 3105 3106 /* first argument is not a list */ 3107 if (length == 0) 3108 return (NIL); 3109 3110 /* check remaining arguments */ 3111 for (count = 0, rest = more_lists; CONSP(rest); rest = CDR(rest), count++) { 3112 for (i = 0, alist = CAR(rest); 3113 i < length && CONSP(alist); 3114 i++, alist = CDR(alist)) 3115 ; 3116 /* argument is not a list */ 3117 if (i == 0) 3118 return (NIL); 3119 /* result will have the length of the smallest list */ 3120 if (i < length) 3121 length = i; 3122 } 3123 3124 /* result will be a list */ 3125 if (maplist) { 3126 result = cons = CONS(NIL, NIL); 3127 GC_PROTECT(result); 3128 } 3129 else 3130 result = cons = list; 3131 3132 if (count >= sizeof(stk) / sizeof(stk[0])) 3133 cdrs = LispMalloc(count * sizeof(LispObj*)); 3134 else 3135 cdrs = &stk[0]; 3136 for (i = 0, rest = more_lists; i < count; i++, rest = CDR(rest)) 3137 cdrs[i] = CAR(rest); 3138 3139 /* initialize argument list */ 3140 arguments = acons = CONS(NIL, NIL); 3141 GC_PROTECT(arguments); 3142 for (i = 0; i < count; i++) { 3143 RPLACD(acons, CONS(NIL, NIL)); 3144 acons = CDR(acons); 3145 } 3146 3147 /* for every used list element */ 3148 for (offset = 0;; list = CDR(list)) { 3149 acons = arguments; 3150 3151 /* first argument */ 3152 RPLACA(acons, list); 3153 acons = CDR(acons); 3154 3155 /* for every extra list */ 3156 for (i = 0; i < count; i++) { 3157 RPLACA(acons, cdrs[i]); 3158 cdrs[i] = CDR(cdrs[i]); 3159 acons = CDR(acons); 3160 } 3161 3162 value = APPLY(function, arguments); 3163 3164 if (maplist) { 3165 /* store result */ 3166 RPLACA(cons, value); 3167 3168 /* allocate new cell */ 3169 if (++offset < length) { 3170 RPLACD(cons, CONS(NIL, NIL)); 3171 cons = CDR(cons); 3172 } 3173 else 3174 break; 3175 } 3176 else if (++offset >= length) 3177 break; 3178 } 3179 3180 GC_LEAVE(); 3181 if (cdrs != &stk[0]) 3182 LispFree(cdrs); 3183 3184 return (result); 3185} 3186 3187LispObj * 3188Lisp_Mapl(LispBuiltin *builtin) 3189/* 3190 mapl function list &rest more-lists 3191 */ 3192{ 3193 return (LispMapl(builtin, 0)); 3194} 3195 3196LispObj * 3197Lisp_Maplist(LispBuiltin *builtin) 3198/* 3199 maplist function list &rest more-lists 3200 */ 3201{ 3202 return (LispMapl(builtin, 1)); 3203} 3204 3205LispObj * 3206Lisp_Mapcon(LispBuiltin *builtin) 3207/* 3208 mapcon function list &rest more-lists 3209 */ 3210{ 3211 return (LispMapnconc(LispMapl(builtin, 1))); 3212} 3213 3214LispObj * 3215Lisp_Member(LispBuiltin *builtin) 3216/* 3217 member item list &key test test-not key 3218 */ 3219{ 3220 int code, expect; 3221 LispObj *compare, *lambda; 3222 LispObj *item, *list, *test, *test_not, *key; 3223 3224 key = ARGUMENT(4); 3225 test_not = ARGUMENT(3); 3226 test = ARGUMENT(2); 3227 list = ARGUMENT(1); 3228 item = ARGUMENT(0); 3229 3230 if (list == NIL) 3231 return (NIL); 3232 CHECK_CONS(list); 3233 3234 CHECK_TEST(); 3235 if (key == UNSPEC) { 3236 if (code == FEQ) { 3237 for (; CONSP(list); list = CDR(list)) 3238 if (item == CAR(list)) 3239 return (list); 3240 } 3241 else { 3242 for (; CONSP(list); list = CDR(list)) 3243 if (FCOMPARE(lambda, item, CAR(list), code) == expect) 3244 return (list); 3245 } 3246 } 3247 else { 3248 if (code == FEQ) { 3249 for (; CONSP(list); list = CDR(list)) 3250 if (item == APPLY1(key, CAR(list))) 3251 return (list); 3252 } 3253 else { 3254 for (; CONSP(list); list = CDR(list)) { 3255 compare = APPLY1(key, CAR(list)); 3256 if (FCOMPARE(lambda, item, compare, code) == expect) 3257 return (list); 3258 } 3259 } 3260 } 3261 /* check if is a proper list */ 3262 CHECK_LIST(list); 3263 3264 return (NIL); 3265} 3266 3267LispObj * 3268Lisp_MemberIf(LispBuiltin *builtin) 3269/* 3270 member-if predicate list &key key 3271 */ 3272{ 3273 return (LispAssocOrMember(builtin, MEMBER, IF)); 3274} 3275 3276LispObj * 3277Lisp_MemberIfNot(LispBuiltin *builtin) 3278/* 3279 member-if-not predicate list &key key 3280 */ 3281{ 3282 return (LispAssocOrMember(builtin, MEMBER, IFNOT)); 3283} 3284 3285LispObj * 3286Lisp_MultipleValueBind(LispBuiltin *builtin) 3287/* 3288 multiple-value-bind symbols values &rest body 3289 */ 3290{ 3291 int i, head = lisp__data.env.length; 3292 LispObj *result, *symbol, *value; 3293 3294 LispObj *symbols, *values, *body; 3295 3296 body = ARGUMENT(2); 3297 values = ARGUMENT(1); 3298 symbols = ARGUMENT(0); 3299 3300 result = EVAL(values); 3301 for (i = -1; CONSP(symbols); symbols = CDR(symbols), i++) { 3302 symbol = CAR(symbols); 3303 CHECK_SYMBOL(symbol); 3304 CHECK_CONSTANT(symbol); 3305 if (i >= 0 && i < RETURN_COUNT) 3306 value = RETURN(i); 3307 else if (i < 0) 3308 value = result; 3309 else 3310 value = NIL; 3311 LispAddVar(symbol, value); 3312 ++lisp__data.env.head; 3313 } 3314 3315 /* Execute code with binded variables (if any) */ 3316 for (result = NIL; CONSP(body); body = CDR(body)) 3317 result = EVAL(CAR(body)); 3318 3319 lisp__data.env.head = lisp__data.env.length = head; 3320 3321 return (result); 3322} 3323 3324LispObj * 3325Lisp_MultipleValueCall(LispBuiltin *builtin) 3326/* 3327 multiple-value-call function &rest form 3328 */ 3329{ 3330 GC_ENTER(); 3331 int i; 3332 LispObj *arguments, *cons, *result; 3333 3334 LispObj *function, *form; 3335 3336 form = ARGUMENT(1); 3337 function = ARGUMENT(0); 3338 3339 /* build argument list */ 3340 arguments = cons = NIL; 3341 for (; CONSP(form); form = CDR(form)) { 3342 RETURN_COUNT = 0; 3343 result = EVAL(CAR(form)); 3344 if (RETURN_COUNT >= 0) { 3345 if (arguments == NIL) { 3346 arguments = cons = CONS(result, NIL); 3347 GC_PROTECT(arguments); 3348 } 3349 else { 3350 RPLACD(cons, CONS(result, NIL)); 3351 cons = CDR(cons); 3352 } 3353 for (i = 0; i < RETURN_COUNT; i++) { 3354 RPLACD(cons, CONS(RETURN(i), NIL)); 3355 cons = CDR(cons); 3356 } 3357 } 3358 } 3359 3360 /* apply function */ 3361 if (POINTERP(function) && !XSYMBOLP(function) && !XFUNCTIONP(function)) { 3362 function = EVAL(function); 3363 GC_PROTECT(function); 3364 } 3365 result = APPLY(function, arguments); 3366 GC_LEAVE(); 3367 3368 return (result); 3369} 3370 3371LispObj * 3372Lisp_MultipleValueProg1(LispBuiltin *builtin) 3373/* 3374 multiple-value-prog1 first-form &rest form 3375 */ 3376{ 3377 GC_ENTER(); 3378 int i, count; 3379 LispObj *values, *cons; 3380 3381 LispObj *first_form, *form; 3382 3383 form = ARGUMENT(1); 3384 first_form = ARGUMENT(0); 3385 3386 values = EVAL(first_form); 3387 if (!CONSP(form)) 3388 return (values); 3389 3390 cons = NIL; 3391 count = RETURN_COUNT; 3392 if (count < 0) 3393 values = NIL; 3394 else if (count == 0) { 3395 GC_PROTECT(values); 3396 } 3397 else { 3398 values = cons = CONS(values, NIL); 3399 GC_PROTECT(values); 3400 for (i = 0; i < count; i++) { 3401 RPLACD(cons, CONS(RETURN(i), NIL)); 3402 cons = CDR(cons); 3403 } 3404 } 3405 3406 for (; CONSP(form); form = CDR(form)) 3407 EVAL(CAR(form)); 3408 3409 RETURN_COUNT = count; 3410 if (count > 0) { 3411 for (i = 0, cons = CDR(values); CONSP(cons); cons = CDR(cons), i++) 3412 RETURN(i) = CAR(cons); 3413 values = CAR(values); 3414 } 3415 GC_LEAVE(); 3416 3417 return (values); 3418} 3419 3420LispObj * 3421Lisp_MultipleValueList(LispBuiltin *builtin) 3422/* 3423 multiple-value-list form 3424 */ 3425{ 3426 int i; 3427 GC_ENTER(); 3428 LispObj *form, *result, *cons; 3429 3430 form = ARGUMENT(0); 3431 3432 result = EVAL(form); 3433 3434 if (RETURN_COUNT < 0) 3435 return (NIL); 3436 3437 result = cons = CONS(result, NIL); 3438 GC_PROTECT(result); 3439 for (i = 0; i < RETURN_COUNT; i++) { 3440 RPLACD(cons, CONS(RETURN(i), NIL)); 3441 cons = CDR(cons); 3442 } 3443 GC_LEAVE(); 3444 3445 return (result); 3446} 3447 3448LispObj * 3449Lisp_MultipleValueSetq(LispBuiltin *builtin) 3450/* 3451 multiple-value-setq symbols form 3452 */ 3453{ 3454 int i; 3455 LispObj *result, *symbol, *value; 3456 3457 LispObj *symbols, *form; 3458 3459 form = ARGUMENT(1); 3460 symbols = ARGUMENT(0); 3461 3462 CHECK_LIST(symbols); 3463 result = EVAL(form); 3464 if (CONSP(symbols)) { 3465 symbol = CAR(symbols); 3466 CHECK_SYMBOL(symbol); 3467 CHECK_CONSTANT(symbol); 3468 LispSetVar(symbol, result); 3469 symbols = CDR(symbols); 3470 } 3471 for (i = 0; CONSP(symbols); symbols = CDR(symbols), i++) { 3472 symbol = CAR(symbols); 3473 CHECK_SYMBOL(symbol); 3474 CHECK_CONSTANT(symbol); 3475 if (i < RETURN_COUNT && RETURN_COUNT > 0) 3476 value = RETURN(i); 3477 else 3478 value = NIL; 3479 LispSetVar(symbol, value); 3480 } 3481 3482 return (result); 3483} 3484 3485LispObj * 3486Lisp_Nconc(LispBuiltin *builtin) 3487/* 3488 nconc &rest lists 3489 */ 3490{ 3491 LispObj *list, *lists, *cons, *head, *tail; 3492 3493 lists = ARGUMENT(0); 3494 3495 /* skip any initial empty lists */ 3496 for (; CONSP(lists); lists = CDR(lists)) 3497 if (CAR(lists) != NIL) 3498 break; 3499 3500 /* don't check if a proper list */ 3501 if (!CONSP(lists)) 3502 return (lists); 3503 3504 /* setup to concatenate lists */ 3505 list = CAR(lists); 3506 CHECK_CONS(list); 3507 for (cons = list; CONSP(CDR(cons)); cons = CDR(cons)) 3508 ; 3509 3510 /* if only two lists */ 3511 lists = CDR(lists); 3512 if (!CONSP(lists)) { 3513 RPLACD(cons, lists); 3514 3515 return (list); 3516 } 3517 3518 /* concatenate */ 3519 for (; CONSP(CDR(lists)); lists = CDR(lists)) { 3520 head = CAR(lists); 3521 if (head == NIL) 3522 continue; 3523 CHECK_CONS(head); 3524 for (tail = head; CONSP(CDR(tail)); tail = CDR(tail)) 3525 ; 3526 RPLACD(cons, head); 3527 cons = tail; 3528 } 3529 /* add last list */ 3530 RPLACD(cons, CAR(lists)); 3531 3532 return (list); 3533} 3534 3535LispObj * 3536Lisp_Nreverse(LispBuiltin *builtin) 3537/* 3538 nreverse sequence 3539 */ 3540{ 3541 return (LispXReverse(builtin, 1)); 3542} 3543 3544LispObj * 3545Lisp_NsetDifference(LispBuiltin *builtin) 3546/* 3547 nset-difference list1 list2 &key test test-not key 3548 */ 3549{ 3550 return (LispListSet(builtin, NSETDIFFERENCE)); 3551} 3552 3553LispObj * 3554Lisp_Nsubstitute(LispBuiltin *builtin) 3555/* 3556 nsubstitute newitem olditem sequence &key from-end test test-not start end count key 3557 */ 3558{ 3559 return (LispDeleteRemoveXSubstitute(builtin, NSUBSTITUTE, NONE)); 3560} 3561 3562LispObj * 3563Lisp_NsubstituteIf(LispBuiltin *builtin) 3564/* 3565 nsubstitute-if newitem test sequence &key from-end start end count key 3566 */ 3567{ 3568 return (LispDeleteRemoveXSubstitute(builtin, NSUBSTITUTE, IF)); 3569} 3570 3571LispObj * 3572Lisp_NsubstituteIfNot(LispBuiltin *builtin) 3573/* 3574 nsubstitute-if-not newitem test sequence &key from-end start end count key 3575 */ 3576{ 3577 return (LispDeleteRemoveXSubstitute(builtin, NSUBSTITUTE, IFNOT)); 3578} 3579 3580LispObj * 3581Lisp_Nth(LispBuiltin *builtin) 3582/* 3583 nth index list 3584 */ 3585{ 3586 long position; 3587 LispObj *oindex, *list; 3588 3589 list = ARGUMENT(1); 3590 oindex = ARGUMENT(0); 3591 3592 CHECK_INDEX(oindex); 3593 position = FIXNUM_VALUE(oindex); 3594 3595 if (list == NIL) 3596 return (NIL); 3597 3598 CHECK_CONS(list); 3599 for (; position > 0; position--) { 3600 if (!CONSP(list)) 3601 return (NIL); 3602 list = CDR(list); 3603 } 3604 3605 return (CONSP(list) ? CAR(list) : NIL); 3606} 3607 3608LispObj * 3609Lisp_Nthcdr(LispBuiltin *builtin) 3610/* 3611 nthcdr index list 3612 */ 3613{ 3614 long position; 3615 LispObj *oindex, *list; 3616 3617 list = ARGUMENT(1); 3618 oindex = ARGUMENT(0); 3619 3620 CHECK_INDEX(oindex); 3621 position = FIXNUM_VALUE(oindex); 3622 3623 if (list == NIL) 3624 return (NIL); 3625 CHECK_CONS(list); 3626 3627 for (; position > 0; position--) { 3628 if (!CONSP(list)) 3629 return (NIL); 3630 list = CDR(list); 3631 } 3632 3633 return (list); 3634} 3635 3636LispObj * 3637Lisp_NthValue(LispBuiltin *builtin) 3638/* 3639 nth-value index form 3640 */ 3641{ 3642 long i; 3643 LispObj *oindex, *form, *result; 3644 3645 form = ARGUMENT(1); 3646 oindex = ARGUMENT(0); 3647 3648 oindex = EVAL(oindex); 3649 CHECK_INDEX(oindex); 3650 i = FIXNUM_VALUE(oindex) - 1; 3651 3652 result = EVAL(form); 3653 if (RETURN_COUNT < 0 || i >= RETURN_COUNT) 3654 result = NIL; 3655 else if (i >= 0) 3656 result = RETURN(i); 3657 3658 return (result); 3659} 3660 3661LispObj * 3662Lisp_Null(LispBuiltin *builtin) 3663/* 3664 null list 3665 */ 3666{ 3667 LispObj *list; 3668 3669 list = ARGUMENT(0); 3670 3671 return (list == NIL ? T : NIL); 3672} 3673 3674LispObj * 3675Lisp_Or(LispBuiltin *builtin) 3676/* 3677 or &rest args 3678 */ 3679{ 3680 LispObj *result = NIL, *args; 3681 3682 args = ARGUMENT(0); 3683 3684 for (; CONSP(args); args = CDR(args)) { 3685 result = EVAL(CAR(args)); 3686 if (result != NIL) 3687 break; 3688 } 3689 3690 return (result); 3691} 3692 3693LispObj * 3694Lisp_Pairlis(LispBuiltin *builtin) 3695/* 3696 pairlis key data &optional alist 3697 */ 3698{ 3699 LispObj *result, *cons; 3700 3701 LispObj *key, *data, *alist; 3702 3703 alist = ARGUMENT(2); 3704 data = ARGUMENT(1); 3705 key = ARGUMENT(0); 3706 3707 if (CONSP(key) && CONSP(data)) { 3708 GC_ENTER(); 3709 3710 result = cons = CONS(CONS(CAR(key), CAR(data)), NIL); 3711 GC_PROTECT(result); 3712 key = CDR(key); 3713 data = CDR(data); 3714 for (; CONSP(key) && CONSP(data); key = CDR(key), data = CDR(data)) { 3715 RPLACD(cons, CONS(CONS(CAR(key), CAR(data)), NIL)); 3716 cons = CDR(cons); 3717 } 3718 if (CONSP(key) || CONSP(data)) 3719 LispDestroy("%s: different length lists", STRFUN(builtin)); 3720 GC_LEAVE(); 3721 if (alist != UNSPEC) 3722 RPLACD(cons, alist); 3723 } 3724 else 3725 result = alist == UNSPEC ? NIL : alist; 3726 3727 return (result); 3728} 3729 3730static LispObj * 3731LispFindOrPosition(LispBuiltin *builtin, 3732 int function, int comparison) 3733/* 3734 find item sequence &key from-end test test-not start end key 3735 find-if predicate sequence &key from-end start end key 3736 find-if-not predicate sequence &key from-end start end key 3737 position item sequence &key from-end test test-not start end key 3738 position-if predicate sequence &key from-end start end key 3739 position-if-not predicate sequence &key from-end start end key 3740 */ 3741{ 3742 int code = 0, istring, expect, value; 3743 char *string = NULL; 3744 long offset = -1, start, end, length, i = comparison == NONE ? 7 : 5; 3745 LispObj *cmp, *element, **objects = NULL; 3746 3747 LispObj *item, *predicate, *sequence, *from_end, 3748 *test, *test_not, *ostart, *oend, *key; 3749 3750 key = ARGUMENT(i); --i; 3751 oend = ARGUMENT(i); --i; 3752 ostart = ARGUMENT(i); --i; 3753 if (comparison == NONE) { 3754 test_not = ARGUMENT(i); --i; 3755 test = ARGUMENT(i); --i; 3756 } 3757 else 3758 test_not = test = UNSPEC; 3759 from_end = ARGUMENT(i); --i; 3760 if (from_end == UNSPEC) 3761 from_end = NIL; 3762 sequence = ARGUMENT(i); --i; 3763 if (comparison == NONE) { 3764 item = ARGUMENT(i); 3765 predicate = Oeql; 3766 } 3767 else { 3768 predicate = ARGUMENT(i); 3769 item = NIL; 3770 } 3771 3772 LispCheckSequenceStartEnd(builtin, sequence, ostart, oend, 3773 &start, &end, &length); 3774 3775 if (sequence == NIL) 3776 return (NIL); 3777 3778 /* Cannot specify both :test and :test-not */ 3779 if (test != UNSPEC && test_not != UNSPEC) 3780 LispDestroy("%s: specify either :TEST or :TEST-NOT", STRFUN(builtin)); 3781 3782 expect = 1; 3783 if (comparison == NONE) { 3784 if (test != UNSPEC) 3785 predicate = test; 3786 else if (test_not != UNSPEC) { 3787 predicate = test_not; 3788 expect = 0; 3789 } 3790 FUNCTION_CHECK(predicate); 3791 code = FCODE(predicate); 3792 } 3793 3794 cmp = element = NIL; 3795 istring = STRINGP(sequence); 3796 if (istring) 3797 string = THESTR(sequence); 3798 else { 3799 if (!CONSP(sequence)) 3800 sequence = sequence->data.array.list; 3801 for (i = 0; i < start; i++) 3802 sequence = CDR(sequence); 3803 } 3804 3805 if ((length = end - start) == 0) 3806 return (NIL); 3807 3808 if (from_end != NIL && !istring) { 3809 objects = LispMalloc(sizeof(LispObj*) * length); 3810 for (i = length - 1; i >= 0; i--, sequence = CDR(sequence)) 3811 objects[i] = CAR(sequence); 3812 } 3813 3814 for (i = 0; i < length; i++) { 3815 if (istring) 3816 element = SCHAR(string[from_end == NIL ? i + start : end - i - 1]); 3817 else 3818 element = from_end == NIL ? CAR(sequence) : objects[i]; 3819 3820 if (key != UNSPEC) 3821 cmp = APPLY1(key, element); 3822 else 3823 cmp = element; 3824 3825 /* Update list */ 3826 if (!istring && from_end == NIL) 3827 sequence = CDR(sequence); 3828 3829 if (comparison == NONE) 3830 value = FCOMPARE(predicate, item, cmp, code); 3831 else 3832 value = APPLY1(predicate, cmp) != NIL; 3833 3834 if ((!value && 3835 (comparison == IFNOT || 3836 (comparison == NONE && !expect))) || 3837 (value && 3838 (comparison == IF || 3839 (comparison == NONE && expect)))) { 3840 offset = from_end == NIL ? i + start : end - i - 1; 3841 break; 3842 } 3843 } 3844 3845 if (from_end != NIL && !istring) 3846 LispFree(objects); 3847 3848 return (offset == -1 ? NIL : function == FIND ? element : FIXNUM(offset)); 3849} 3850 3851LispObj * 3852Lisp_Pop(LispBuiltin *builtin) 3853/* 3854 pop place 3855 */ 3856{ 3857 LispObj *result, *value; 3858 3859 LispObj *place; 3860 3861 place = ARGUMENT(0); 3862 3863 if (SYMBOLP(place)) { 3864 result = LispGetVar(place); 3865 if (result == NULL) 3866 LispDestroy("EVAL: the variable %s is unbound", STROBJ(place)); 3867 CHECK_CONSTANT(place); 3868 if (result != NIL) { 3869 CHECK_CONS(result); 3870 value = CDR(result); 3871 result = CAR(result); 3872 } 3873 else 3874 value = NIL; 3875 LispSetVar(place, value); 3876 } 3877 else { 3878 GC_ENTER(); 3879 LispObj quote; 3880 3881 result = EVAL(place); 3882 if (result != NIL) { 3883 CHECK_CONS(result); 3884 value = CDR(result); 3885 GC_PROTECT(value); 3886 result = CAR(result); 3887 } 3888 else 3889 value = NIL; 3890 quote.type = LispQuote_t; 3891 quote.data.quote = value; 3892 APPLY2(Osetf, place, "e); 3893 GC_LEAVE(); 3894 } 3895 3896 return (result); 3897} 3898 3899LispObj * 3900Lisp_Position(LispBuiltin *builtin) 3901/* 3902 position item sequence &key from-end test test-not start end key 3903 */ 3904{ 3905 return (LispFindOrPosition(builtin, POSITION, NONE)); 3906} 3907 3908LispObj * 3909Lisp_PositionIf(LispBuiltin *builtin) 3910/* 3911 position-if predicate sequence &key from-end start end key 3912 */ 3913{ 3914 return (LispFindOrPosition(builtin, POSITION, IF)); 3915} 3916 3917LispObj * 3918Lisp_PositionIfNot(LispBuiltin *builtin) 3919/* 3920 position-if-not predicate sequence &key from-end start end key 3921 */ 3922{ 3923 return (LispFindOrPosition(builtin, POSITION, IFNOT)); 3924} 3925 3926LispObj * 3927Lisp_Proclaim(LispBuiltin *builtin) 3928/* 3929 proclaim declaration 3930 */ 3931{ 3932 LispObj *arguments, *object; 3933 char *operation; 3934 3935 LispObj *declaration; 3936 3937 declaration = ARGUMENT(0); 3938 3939 CHECK_CONS(declaration); 3940 3941 arguments = declaration; 3942 object = CAR(arguments); 3943 CHECK_SYMBOL(object); 3944 3945 operation = ATOMID(object); 3946 if (strcmp(operation, "SPECIAL") == 0) { 3947 for (arguments = CDR(arguments); CONSP(arguments); 3948 arguments = CDR(arguments)) { 3949 object = CAR(arguments); 3950 CHECK_SYMBOL(object); 3951 LispProclaimSpecial(object, NULL, NIL); 3952 } 3953 } 3954 else if (strcmp(operation, "TYPE") == 0) { 3955 /* XXX no type checking yet, but should be added */ 3956 } 3957 /* else do nothing */ 3958 3959 return (NIL); 3960} 3961 3962LispObj * 3963Lisp_Prog1(LispBuiltin *builtin) 3964/* 3965 prog1 first &rest body 3966 */ 3967{ 3968 GC_ENTER(); 3969 LispObj *result; 3970 3971 LispObj *first, *body; 3972 3973 body = ARGUMENT(1); 3974 first = ARGUMENT(0); 3975 3976 result = EVAL(first); 3977 3978 GC_PROTECT(result); 3979 for (; CONSP(body); body = CDR(body)) 3980 (void)EVAL(CAR(body)); 3981 GC_LEAVE(); 3982 3983 return (result); 3984} 3985 3986LispObj * 3987Lisp_Prog2(LispBuiltin *builtin) 3988/* 3989 prog2 first second &rest body 3990 */ 3991{ 3992 GC_ENTER(); 3993 LispObj *result; 3994 3995 LispObj *first, *second, *body; 3996 3997 body = ARGUMENT(2); 3998 second = ARGUMENT(1); 3999 first = ARGUMENT(0); 4000 4001 (void)EVAL(first); 4002 result = EVAL(second); 4003 GC_PROTECT(result); 4004 for (; CONSP(body); body = CDR(body)) 4005 (void)EVAL(CAR(body)); 4006 GC_LEAVE(); 4007 4008 return (result); 4009} 4010 4011LispObj * 4012Lisp_Progn(LispBuiltin *builtin) 4013/* 4014 progn &rest body 4015 */ 4016{ 4017 LispObj *result = NIL; 4018 4019 LispObj *body; 4020 4021 body = ARGUMENT(0); 4022 4023 for (; CONSP(body); body = CDR(body)) 4024 result = EVAL(CAR(body)); 4025 4026 return (result); 4027} 4028 4029/* 4030 * This does what I believe is the expected behaviour (or at least 4031 * acceptable for the the interpreter), if the code being executed 4032 * ever tries to change/bind a progv symbol, the symbol state will 4033 * be restored when exiting the progv block, so, code like: 4034 * (progv '(*x*) '(1) (defvar *x* 10)) 4035 * when exiting the block, will have *x* unbound, and not a dynamic 4036 * symbol; if it was already bound, will have the old value. 4037 * Symbols already dynamic can be freely changed, even unbounded in 4038 * the progv block. 4039 */ 4040LispObj * 4041Lisp_Progv(LispBuiltin *builtin) 4042/* 4043 progv symbols values &rest body 4044 */ 4045{ 4046 GC_ENTER(); 4047 int head = lisp__data.env.length, i, count, ostk[32], *offsets; 4048 LispObj *result, *list, *symbol, *value; 4049 int jumped; 4050 char fstk[32], *flags; 4051 LispBlock *block; 4052 LispAtom *atom; 4053 4054 LispObj *symbols, *values, *body; 4055 4056 /* Possible states */ 4057#define DYNAMIC_SYMBOL 1 4058#define GLOBAL_SYMBOL 2 4059#define UNBOUND_SYMBOL 3 4060 4061 body = ARGUMENT(2); 4062 values = ARGUMENT(1); 4063 symbols = ARGUMENT(0); 4064 4065 /* get symbol names */ 4066 symbols = EVAL(symbols); 4067 GC_PROTECT(symbols); 4068 4069 /* get symbol values */ 4070 values = EVAL(values); 4071 GC_PROTECT(values); 4072 4073 /* count/check symbols and allocate space to remember symbol state */ 4074 for (count = 0, list = symbols; CONSP(list); count++, list = CDR(list)) { 4075 symbol = CAR(list); 4076 CHECK_SYMBOL(symbol); 4077 CHECK_CONSTANT(symbol); 4078 } 4079 if (count > sizeof(fstk)) { 4080 flags = LispMalloc(count); 4081 offsets = LispMalloc(count * sizeof(int)); 4082 } 4083 else { 4084 flags = &fstk[0]; 4085 offsets = &ostk[0]; 4086 } 4087 4088 /* store flags and save old value if required */ 4089 for (i = 0, list = symbols; i < count; i++, list = CDR(list)) { 4090 atom = CAR(list)->data.atom; 4091 if (atom->dyn) 4092 flags[i] = DYNAMIC_SYMBOL; 4093 else if (atom->a_object) { 4094 flags[i] = GLOBAL_SYMBOL; 4095 offsets[i] = lisp__data.protect.length; 4096 GC_PROTECT(atom->property->value); 4097 } 4098 else 4099 flags[i] = UNBOUND_SYMBOL; 4100 } 4101 4102 /* bind the symbols */ 4103 for (i = 0, list = symbols; i < count; i++, list = CDR(list)) { 4104 symbol = CAR(list); 4105 atom = symbol->data.atom; 4106 if (CONSP(values)) { 4107 value = CAR(values); 4108 values = CDR(values); 4109 } 4110 else 4111 value = NIL; 4112 if (flags[i] != DYNAMIC_SYMBOL) { 4113 if (!atom->a_object) 4114 LispSetAtomObjectProperty(atom, value); 4115 else 4116 SETVALUE(atom, value); 4117 } 4118 else 4119 LispAddVar(symbol, value); 4120 } 4121 /* bind dynamic symbols */ 4122 lisp__data.env.head = lisp__data.env.length; 4123 4124 jumped = 0; 4125 result = NIL; 4126 block = LispBeginBlock(NIL, LispBlockProtect); 4127 if (setjmp(block->jmp) == 0) { 4128 for (; CONSP(body); body = CDR(body)) 4129 result = EVAL(CAR(body)); 4130 } 4131 4132 /* restore symbols */ 4133 for (i = 0, list = symbols; i < count; i++, list = CDR(list)) { 4134 symbol = CAR(list); 4135 atom = symbol->data.atom; 4136 if (flags[i] != DYNAMIC_SYMBOL) { 4137 if (flags[i] == UNBOUND_SYMBOL) 4138 LispUnsetVar(symbol); 4139 else { 4140 /* restore global symbol value */ 4141 LispSetAtomObjectProperty(atom, lisp__data.protect.objects 4142 [offsets[i]]); 4143 atom->dyn = 0; 4144 } 4145 } 4146 } 4147 /* unbind dynamic symbols */ 4148 lisp__data.env.head = lisp__data.env.length = head; 4149 GC_LEAVE(); 4150 4151 if (count > sizeof(fstk)) { 4152 LispFree(flags); 4153 LispFree(offsets); 4154 } 4155 4156 LispEndBlock(block); 4157 if (!lisp__data.destroyed) { 4158 if (jumped) 4159 result = lisp__data.block.block_ret; 4160 } 4161 else { 4162 /* check if there is an unwind-protect block */ 4163 LispBlockUnwind(NULL); 4164 4165 /* no unwind-protect block, return to the toplevel */ 4166 LispDestroy("."); 4167 } 4168 4169 return (result); 4170} 4171 4172LispObj * 4173Lisp_Provide(LispBuiltin *builtin) 4174/* 4175 provide module 4176 */ 4177{ 4178 LispObj *module, *obj; 4179 4180 module = ARGUMENT(0); 4181 4182 CHECK_STRING(module); 4183 for (obj = MOD; obj != NIL; obj = CDR(obj)) { 4184 if (STRLEN(CAR(obj)) == STRLEN(module) && 4185 memcmp(THESTR(CAR(obj)), THESTR(module), STRLEN(module)) == 0) 4186 return (module); 4187 } 4188 4189 if (MOD == NIL) 4190 MOD = CONS(module, NIL); 4191 else { 4192 RPLACD(MOD, CONS(CAR(MOD), CDR(MOD))); 4193 RPLACA(MOD, module); 4194 } 4195 4196 LispSetVar(lisp__data.modules, MOD); 4197 4198 return (MOD); 4199} 4200 4201LispObj * 4202Lisp_Push(LispBuiltin *builtin) 4203/* 4204 push item place 4205 */ 4206{ 4207 LispObj *result, *list; 4208 4209 LispObj *item, *place; 4210 4211 place = ARGUMENT(1); 4212 item = ARGUMENT(0); 4213 4214 item = EVAL(item); 4215 4216 if (SYMBOLP(place)) { 4217 list = LispGetVar(place); 4218 if (list == NULL) 4219 LispDestroy("EVAL: the variable %s is unbound", STROBJ(place)); 4220 CHECK_CONSTANT(place); 4221 LispSetVar(place, result = CONS(item, list)); 4222 } 4223 else { 4224 GC_ENTER(); 4225 LispObj quote; 4226 4227 list = EVAL(place); 4228 result = CONS(item, list); 4229 GC_PROTECT(result); 4230 quote.type = LispQuote_t; 4231 quote.data.quote = result; 4232 APPLY2(Osetf, place, "e); 4233 GC_LEAVE(); 4234 } 4235 4236 return (result); 4237} 4238 4239LispObj * 4240Lisp_Pushnew(LispBuiltin *builtin) 4241/* 4242 pushnew item place &key key test test-not 4243 */ 4244{ 4245 GC_ENTER(); 4246 LispObj *result, *list; 4247 4248 LispObj *item, *place, *key, *test, *test_not; 4249 4250 test_not = ARGUMENT(4); 4251 test = ARGUMENT(3); 4252 key = ARGUMENT(2); 4253 place = ARGUMENT(1); 4254 item = ARGUMENT(0); 4255 4256 /* Evaluate place */ 4257 if (SYMBOLP(place)) { 4258 list = LispGetVar(place); 4259 if (list == NULL) 4260 LispDestroy("EVAL: the variable %s is unbound", STROBJ(place)); 4261 /* Do error checking now. */ 4262 CHECK_CONSTANT(place); 4263 } 4264 else 4265 /* It is possible that list is not gc protected? */ 4266 list = EVAL(place); 4267 4268 item = EVAL(item); 4269 GC_PROTECT(item); 4270 if (key != UNSPEC) { 4271 key = EVAL(key); 4272 GC_PROTECT(key); 4273 } 4274 if (test != UNSPEC) { 4275 test = EVAL(test); 4276 GC_PROTECT(test); 4277 } 4278 else if (test_not != UNSPEC) { 4279 test_not = EVAL(test_not); 4280 GC_PROTECT(test_not); 4281 } 4282 4283 result = LispAdjoin(builtin, item, list, key, test, test_not); 4284 4285 /* Item already in list */ 4286 if (result == list) { 4287 GC_LEAVE(); 4288 4289 return (result); 4290 } 4291 4292 if (SYMBOLP(place)) { 4293 CHECK_CONSTANT(place); 4294 LispSetVar(place, result); 4295 } 4296 else { 4297 LispObj quote; 4298 4299 GC_PROTECT(result); 4300 quote.type = LispQuote_t; 4301 quote.data.quote = result; 4302 APPLY2(Osetf, place, "e); 4303 } 4304 GC_LEAVE(); 4305 4306 return (result); 4307} 4308 4309LispObj * 4310Lisp_Quit(LispBuiltin *builtin) 4311/* 4312 quit &optional status 4313 */ 4314{ 4315 int status = 0; 4316 LispObj *ostatus; 4317 4318 ostatus = ARGUMENT(0); 4319 4320 if (FIXNUMP(ostatus)) 4321 status = (int)FIXNUM_VALUE(ostatus); 4322 else if (ostatus != UNSPEC) 4323 LispDestroy("%s: bad exit status argument %s", 4324 STRFUN(builtin), STROBJ(ostatus)); 4325 4326 exit(status); 4327} 4328 4329LispObj * 4330Lisp_Quote(LispBuiltin *builtin) 4331/* 4332 quote object 4333 */ 4334{ 4335 LispObj *object; 4336 4337 object = ARGUMENT(0); 4338 4339 return (object); 4340} 4341 4342LispObj * 4343Lisp_Replace(LispBuiltin *builtin) 4344/* 4345 replace sequence1 sequence2 &key start1 end1 start2 end2 4346 */ 4347{ 4348 long length, length1, length2, start1, end1, start2, end2; 4349 LispObj *sequence1, *sequence2, *ostart1, *oend1, *ostart2, *oend2; 4350 4351 oend2 = ARGUMENT(5); 4352 ostart2 = ARGUMENT(4); 4353 oend1 = ARGUMENT(3); 4354 ostart1 = ARGUMENT(2); 4355 sequence2 = ARGUMENT(1); 4356 sequence1 = ARGUMENT(0); 4357 4358 LispCheckSequenceStartEnd(builtin, sequence1, ostart1, oend1, 4359 &start1, &end1, &length1); 4360 LispCheckSequenceStartEnd(builtin, sequence2, ostart2, oend2, 4361 &start2, &end2, &length2); 4362 4363 if (start1 == end1 || start2 == end2) 4364 return (sequence1); 4365 4366 length = end1 - start1; 4367 if (length > end2 - start2) 4368 length = end2 - start2; 4369 4370 if (STRINGP(sequence1)) { 4371 CHECK_STRING_WRITABLE(sequence1); 4372 if (!STRINGP(sequence2)) 4373 LispDestroy("%s: cannot store %s in %s", 4374 STRFUN(builtin), STROBJ(sequence2), THESTR(sequence1)); 4375 4376 memmove(THESTR(sequence1) + start1, THESTR(sequence2) + start2, length); 4377 } 4378 else { 4379 int i; 4380 LispObj *from, *to; 4381 4382 if (ARRAYP(sequence1)) 4383 sequence1 = sequence1->data.array.list; 4384 if (ARRAYP(sequence2)) 4385 sequence2 = sequence2->data.array.list; 4386 4387 /* adjust pointers */ 4388 for (i = 0, from = sequence2; i < start2; i++, from = CDR(from)) 4389 ; 4390 for (i = 0, to = sequence1; i < start1; i++, to = CDR(to)) 4391 ; 4392 4393 /* copy data */ 4394 for (i = 0; i < length; i++, from = CDR(from), to = CDR(to)) 4395 RPLACA(to, CAR(from)); 4396 } 4397 4398 return (sequence1); 4399} 4400 4401static LispObj * 4402LispDeleteOrRemoveDuplicates(LispBuiltin *builtin, int function) 4403/* 4404 delete-duplicates sequence &key from-end test test-not start end key 4405 remove-duplicates sequence &key from-end test test-not start end key 4406 */ 4407{ 4408 GC_ENTER(); 4409 int code, expect, value = 0; 4410 long i, j, start, end, length, count; 4411 LispObj *lambda, *result, *cons, *compare; 4412 4413 LispObj *sequence, *from_end, *test, *test_not, *ostart, *oend, *key; 4414 4415 key = ARGUMENT(6); 4416 oend = ARGUMENT(5); 4417 ostart = ARGUMENT(4); 4418 test_not = ARGUMENT(3); 4419 test = ARGUMENT(2); 4420 from_end = ARGUMENT(1); 4421 if (from_end == UNSPEC) 4422 from_end = NIL; 4423 sequence = ARGUMENT(0); 4424 4425 LispCheckSequenceStartEnd(builtin, sequence, ostart, oend, 4426 &start, &end, &length); 4427 4428 /* Check if need to do something */ 4429 if (start == end) 4430 return (sequence); 4431 4432 CHECK_TEST(); 4433 4434 /* Initialize */ 4435 count = 0; 4436 4437 result = cons = NIL; 4438 if (STRINGP(sequence)) { 4439 char *ptr, *string, *buffer = LispMalloc(length + 1); 4440 4441 /* Use same code, update start/end offsets */ 4442 if (from_end != NIL) { 4443 i = length - start; 4444 start = length - end; 4445 end = i; 4446 } 4447 4448 if (from_end == NIL) 4449 string = THESTR(sequence); 4450 else { 4451 /* Make a reversed copy of the sequence */ 4452 string = LispMalloc(length + 1); 4453 for (ptr = THESTR(sequence) + length - 1, i = 0; i < length; i++) 4454 string[i] = *ptr--; 4455 string[i] = '\0'; 4456 } 4457 4458 ptr = buffer; 4459 /* Copy leading bytes */ 4460 for (i = 0; i < start; i++) 4461 *ptr++ = string[i]; 4462 4463 compare = SCHAR(string[i]); 4464 if (key != UNSPEC) 4465 compare = APPLY1(key, compare); 4466 result = cons = CONS(compare, NIL); 4467 GC_PROTECT(result); 4468 for (++i; i < end; i++) { 4469 compare = SCHAR(string[i]); 4470 if (key != UNSPEC) 4471 compare = APPLY1(key, compare); 4472 RPLACD(cons, CONS(compare, NIL)); 4473 cons = CDR(cons); 4474 } 4475 4476 for (i = start; i < end; i++, result = CDR(result)) { 4477 compare = CAR(result); 4478 for (j = i + 1, cons = CDR(result); j < end; j++, cons = CDR(cons)) { 4479 value = FCOMPARE(lambda, compare, CAR(cons), code); 4480 if (value == expect) 4481 break; 4482 } 4483 if (value != expect) 4484 *ptr++ = string[i]; 4485 else 4486 ++count; 4487 } 4488 4489 if (count) { 4490 /* Copy ending bytes */ 4491 for (; i <= length; i++) /* Also copy the ending nul */ 4492 *ptr++ = string[i]; 4493 4494 if (from_end == NIL) 4495 ptr = buffer; 4496 else { 4497 for (i = 0, ptr = buffer + strlen(buffer); 4498 ptr > buffer; 4499 i++) 4500 string[i] = *--ptr; 4501 string[i] = '\0'; 4502 ptr = string; 4503 LispFree(buffer); 4504 } 4505 if (function == REMOVE) 4506 result = STRING2(ptr); 4507 else { 4508 CHECK_STRING_WRITABLE(sequence); 4509 result = sequence; 4510 free(THESTR(result)); 4511 THESTR(result) = ptr; 4512 LispMused(ptr); 4513 } 4514 } 4515 else { 4516 result = sequence; 4517 if (from_end != NIL) 4518 LispFree(string); 4519 } 4520 } 4521 else { 4522 long xlength = end - start; 4523 LispObj *list, *object, **kobjects = NULL, **xobjects; 4524 LispObj **objects = LispMalloc(sizeof(LispObj*) * xlength); 4525 4526 if (!CONSP(sequence)) 4527 object = sequence->data.array.list; 4528 else 4529 object = sequence; 4530 list = object; 4531 4532 for (i = 0; i < start; i++) 4533 object = CDR(object); 4534 4535 /* Put data in a vector */ 4536 if (from_end == NIL) { 4537 for (i = 0; i < xlength; i++, object = CDR(object)) 4538 objects[i] = CAR(object); 4539 } 4540 else { 4541 for (i = xlength - 1; i >= 0; i--, object = CDR(object)) 4542 objects[i] = CAR(object); 4543 } 4544 4545 /* Apply key predicate if required */ 4546 if (key != UNSPEC) { 4547 kobjects = LispMalloc(sizeof(LispObj*) * xlength); 4548 for (i = 0; i < xlength; i++) { 4549 kobjects[i] = APPLY1(key, objects[i]); 4550 GC_PROTECT(kobjects[i]); 4551 } 4552 xobjects = kobjects; 4553 } 4554 else 4555 xobjects = objects; 4556 4557 /* Check if needs to remove something */ 4558 for (i = 0; i < xlength; i++) { 4559 compare = xobjects[i]; 4560 for (j = i + 1; j < xlength; j++) { 4561 value = FCOMPARE(lambda, compare, xobjects[j], code); 4562 if (value == expect) { 4563 objects[i] = NULL; 4564 ++count; 4565 break; 4566 } 4567 } 4568 } 4569 4570 if (count) { 4571 /* Create/set result list */ 4572 object = list; 4573 4574 if (start) { 4575 /* Skip first elements of resulting list */ 4576 if (function == REMOVE) { 4577 result = cons = CONS(CAR(object), NIL); 4578 GC_PROTECT(result); 4579 for (i = 1, object = CDR(object); 4580 i < start; 4581 i++, object = CDR(object)) { 4582 RPLACD(cons, CONS(CAR(object), NIL)); 4583 cons = CDR(cons); 4584 } 4585 } 4586 else { 4587 result = cons = object; 4588 for (i = 1; i < start; i++, cons = CDR(cons)) 4589 ; 4590 } 4591 } 4592 else if (function == DELETE) 4593 result = list; 4594 4595 /* Skip initial removed elements */ 4596 if (function == REMOVE) { 4597 for (i = 0; objects[i] == NULL && i < xlength; i++) 4598 ; 4599 } 4600 else 4601 i = 0; 4602 4603 if (i < xlength) { 4604 int xstart, xlimit, xinc; 4605 4606 if (from_end == NIL) { 4607 xstart = i; 4608 xlimit = xlength; 4609 xinc = 1; 4610 } 4611 else { 4612 xstart = xlength - 1; 4613 xlimit = i - 1; 4614 xinc = -1; 4615 } 4616 4617 if (function == REMOVE) { 4618 for (i = xstart; i != xlimit; i += xinc) { 4619 if (objects[i] != NULL) { 4620 if (result == NIL) { 4621 result = cons = CONS(objects[i], NIL); 4622 GC_PROTECT(result); 4623 } 4624 else { 4625 RPLACD(cons, CONS(objects[i], NIL)); 4626 cons = CDR(cons); 4627 } 4628 } 4629 } 4630 } 4631 else { 4632 /* Delete duplicates */ 4633 for (i = xstart; i != xlimit; i += xinc) { 4634 if (objects[i] == NULL) { 4635 if (cons == NIL) { 4636 if (CONSP(CDR(result))) { 4637 RPLACA(result, CADR(result)); 4638 RPLACD(result, CDDR(result)); 4639 } 4640 else { 4641 RPLACA(result, CDR(result)); 4642 RPLACD(result, NIL); 4643 } 4644 } 4645 else { 4646 if (CONSP(CDR(cons))) 4647 RPLACD(cons, CDDR(cons)); 4648 else 4649 RPLACD(cons, NIL); 4650 } 4651 } 4652 else { 4653 if (cons == NIL) 4654 cons = result; 4655 else 4656 cons = CDR(cons); 4657 } 4658 } 4659 } 4660 } 4661 if (end < length && function == REMOVE) { 4662 for (i = start; i < end; i++, object = CDR(object)) 4663 ; 4664 if (result == NIL) { 4665 result = cons = CONS(CAR(object), NIL); 4666 GC_PROTECT(result); 4667 ++i; 4668 object = CDR(object); 4669 } 4670 for (; i < length; i++, object = CDR(object)) { 4671 RPLACD(cons, CONS(CAR(object), NIL)); 4672 cons = CDR(cons); 4673 } 4674 } 4675 } 4676 else 4677 result = sequence; 4678 LispFree(objects); 4679 if (key != UNSPEC) 4680 LispFree(kobjects); 4681 4682 if (count && !CONSP(sequence)) { 4683 if (function == REMOVE) 4684 result = VECTOR(result); 4685 else { 4686 length = FIXNUM_VALUE(CAR(sequence->data.array.dim)) - count; 4687 CAR(sequence->data.array.dim) = FIXNUM(length); 4688 result = sequence; 4689 } 4690 } 4691 } 4692 GC_LEAVE(); 4693 4694 return (result); 4695} 4696 4697LispObj * 4698Lisp_RemoveDuplicates(LispBuiltin *builtin) 4699/* 4700 remove-duplicates sequence &key from-end test test-not start end key 4701 */ 4702{ 4703 return (LispDeleteOrRemoveDuplicates(builtin, REMOVE)); 4704} 4705 4706static LispObj * 4707LispDeleteRemoveXSubstitute(LispBuiltin *builtin, 4708 int function, int comparison) 4709/* 4710 delete item sequence &key from-end test test-not start end count key 4711 delete-if predicate sequence &key from-end start end count key 4712 delete-if-not predicate sequence &key from-end start end count key 4713 remove item sequence &key from-end test test-not start end count key 4714 remove-if predicate sequence &key from-end start end count key 4715 remove-if-not predicate sequence &key from-end start end count key 4716 substitute newitem olditem sequence &key from-end test test-not start end count key 4717 substitute-if newitem test sequence &key from-end start end count key 4718 substitute-if-not newitem test sequence &key from-end start end count key 4719 nsubstitute newitem olditem sequence &key from-end test test-not start end count key 4720 nsubstitute-if newitem test sequence &key from-end start end count key 4721 nsubstitute-if-not newitem test sequence &key from-end start end count key 4722 */ 4723{ 4724 GC_ENTER(); 4725 int code, expect, value, inplace, substitute; 4726 long i, j, start, end, length, copy, count, xstart, xend, xinc, xlength; 4727 4728 LispObj *result, *compare; 4729 4730 LispObj *item, *newitem, *lambda, *sequence, *from_end, 4731 *test, *test_not, *ostart, *oend, *ocount, *key; 4732 4733 substitute = function == SUBSTITUTE || function == NSUBSTITUTE; 4734 if (!substitute) 4735 i = comparison == NONE ? 8 : 6; 4736 else /* substitute */ 4737 i = comparison == NONE ? 9 : 7; 4738 4739 /* Get function arguments */ 4740 key = ARGUMENT(i); --i; 4741 ocount = ARGUMENT(i); --i; 4742 oend = ARGUMENT(i); --i; 4743 ostart = ARGUMENT(i); --i; 4744 if (comparison == NONE) { 4745 test_not = ARGUMENT(i); --i; 4746 test = ARGUMENT(i); --i; 4747 } 4748 else 4749 test_not = test = UNSPEC; 4750 from_end = ARGUMENT(i); --i; 4751 if (from_end == UNSPEC) 4752 from_end = NIL; 4753 sequence = ARGUMENT(i); --i; 4754 if (comparison != NONE) { 4755 lambda = ARGUMENT(i); --i; 4756 if (substitute) 4757 newitem = ARGUMENT(0); 4758 else 4759 newitem = NIL; 4760 item = NIL; 4761 } 4762 else { 4763 lambda = NIL; 4764 if (substitute) { 4765 item = ARGUMENT(1); 4766 newitem = ARGUMENT(0); 4767 } 4768 else { 4769 item = ARGUMENT(0); 4770 newitem = NIL; 4771 } 4772 } 4773 4774 /* Check if argument is a valid sequence, and if start/end 4775 * are correctly specified. */ 4776 LispCheckSequenceStartEnd(builtin, sequence, ostart, oend, 4777 &start, &end, &length); 4778 4779 /* Check count argument */ 4780 if (ocount == UNSPEC) { 4781 count = length; 4782 /* Doesn't matter, but left to right should be slightly faster */ 4783 from_end = NIL; 4784 } 4785 else { 4786 CHECK_INDEX(ocount); 4787 count = FIXNUM_VALUE(ocount); 4788 } 4789 4790 /* Check if need to do something */ 4791 if (start == end || count == 0) 4792 return (sequence); 4793 4794 CHECK_TEST_0(); 4795 4796 /* Resolve comparison function, and expected result of comparison */ 4797 if (comparison == NONE) { 4798 if (test_not == UNSPEC) { 4799 if (test == UNSPEC) 4800 lambda = Oeql; 4801 else 4802 lambda = test; 4803 expect = 1; 4804 } 4805 else { 4806 lambda = test_not; 4807 expect = 0; 4808 } 4809 FUNCTION_CHECK(lambda); 4810 } 4811 else 4812 expect = comparison == IFNOT ? 0 : 1; 4813 4814 /* Check for fast path to comparison function */ 4815 code = FCODE(lambda); 4816 4817 /* Initialize for loop */ 4818 copy = count; 4819 result = sequence; 4820 inplace = function == DELETE || function == NSUBSTITUTE; 4821 xlength = end - start; 4822 4823 /* String is easier */ 4824 if (STRINGP(sequence)) { 4825 char *buffer, *string; 4826 4827 if (comparison == NONE) { 4828 CHECK_SCHAR(item); 4829 } 4830 if (substitute) { 4831 CHECK_SCHAR(newitem); 4832 } 4833 4834 if (from_end == NIL) { 4835 xstart = start; 4836 xend = end; 4837 xinc = 1; 4838 } 4839 else { 4840 xstart = end - 1; 4841 xend = start - 1; 4842 xinc = -1; 4843 } 4844 4845 string = THESTR(sequence); 4846 buffer = LispMalloc(length + 1); 4847 4848 /* Copy leading bytes, if any */ 4849 for (i = 0; i < start; i++) 4850 buffer[i] = string[i]; 4851 4852 for (j = xstart; i != xend && count > 0; i += xinc) { 4853 compare = SCHAR(string[i]); 4854 if (key != UNSPEC) { 4855 compare = APPLY1(key, compare); 4856 /* Value returned by the key predicate may not be protected */ 4857 GC_PROTECT(compare); 4858 if (comparison == NONE) 4859 value = FCOMPARE(lambda, item, compare, code); 4860 else 4861 value = APPLY1(lambda, compare) != NIL; 4862 /* Unprotect value returned by the key predicate */ 4863 GC_LEAVE(); 4864 } 4865 else { 4866 if (comparison == NONE) 4867 value = FCOMPARE(lambda, item, compare, code); 4868 else 4869 value = APPLY1(lambda, compare) != NIL; 4870 } 4871 4872 if (value != expect) { 4873 buffer[j] = string[i]; 4874 j += xinc; 4875 } 4876 else { 4877 if (substitute) { 4878 buffer[j] = SCHAR_VALUE(newitem); 4879 j += xinc; 4880 } 4881 else 4882 --count; 4883 } 4884 } 4885 4886 if (count != copy && from_end != NIL) 4887 memmove(buffer + start, buffer + copy - count, count); 4888 4889 /* Copy remaining bytes, if any */ 4890 for (; i < length; i++, j++) 4891 buffer[j] = string[i]; 4892 buffer[j] = '\0'; 4893 4894 xlength = length - (copy - count); 4895 if (inplace) { 4896 CHECK_STRING_WRITABLE(sequence); 4897 /* result is a pointer to sequence */ 4898 LispFree(THESTR(sequence)); 4899 LispMused(buffer); 4900 THESTR(sequence) = buffer; 4901 STRLEN(sequence) = xlength; 4902 } 4903 else 4904 result = LSTRING2(buffer, xlength); 4905 } 4906 4907 /* If inplace, need to update CAR and CDR of sequence */ 4908 else { 4909 LispObj *list, *object; 4910 LispObj **objects = LispMalloc(sizeof(LispObj*) * xlength); 4911 4912 if (!CONSP(sequence)) 4913 list = sequence->data.array.list; 4914 else 4915 list = sequence; 4916 4917 /* Put data in a vector */ 4918 for (i = 0, object = list; i < start; i++) 4919 object = CDR(object); 4920 4921 for (i = 0; i < xlength; i++, object = CDR(object)) 4922 objects[i] = CAR(object); 4923 4924 if (from_end == NIL) { 4925 xstart = 0; 4926 xend = xlength; 4927 xinc = 1; 4928 } 4929 else { 4930 xstart = xlength - 1; 4931 xend = -1; 4932 xinc = -1; 4933 } 4934 4935 /* Check if needs to remove something */ 4936 for (i = xstart; i != xend && count > 0; i += xinc) { 4937 compare = objects[i]; 4938 if (key != UNSPEC) { 4939 compare = APPLY1(key, compare); 4940 GC_PROTECT(compare); 4941 if (comparison == NONE) 4942 value = FCOMPARE(lambda, item, compare, code); 4943 else 4944 value = APPLY1(lambda, compare) != NIL; 4945 GC_LEAVE(); 4946 } 4947 else { 4948 if (comparison == NONE) 4949 value = FCOMPARE(lambda, item, compare, code); 4950 else 4951 value = APPLY1(lambda, compare) != NIL; 4952 } 4953 if (value == expect) { 4954 if (substitute) 4955 objects[i] = newitem; 4956 else 4957 objects[i] = NULL; 4958 --count; 4959 } 4960 } 4961 4962 if (copy != count) { 4963 LispObj *cons = NIL; 4964 4965 i = 0; 4966 object = list; 4967 if (inplace) { 4968 /* While result is NIL, skip initial elements of sequence */ 4969 result = start ? list : NIL; 4970 4971 /* Skip initial elements, if any */ 4972 for (; i < start; i++, cons = object, object = CDR(object)) 4973 ; 4974 } 4975 /* Copy initial elements, if any */ 4976 else { 4977 result = NIL; 4978 if (start) { 4979 result = cons = CONS(CAR(list), NIL); 4980 GC_PROTECT(result); 4981 for (++i, object = CDR(list); 4982 i < start; 4983 i++, object = CDR(object)) { 4984 RPLACD(cons, CONS(CAR(object), NIL)); 4985 cons = CDR(cons); 4986 } 4987 } 4988 } 4989 4990 /* Skip initial removed elements, if any */ 4991 for (i = 0; objects[i] == NULL && i < xlength; i++) 4992 ; 4993 4994 for (i = 0; i < xlength; i++, object = CDR(object)) { 4995 if (objects[i]) { 4996 if (inplace) { 4997 if (result == NIL) 4998 result = cons = object; 4999 else { 5000 RPLACD(cons, object); 5001 cons = CDR(cons); 5002 } 5003 if (function == NSUBSTITUTE) 5004 RPLACA(cons, objects[i]); 5005 } 5006 else { 5007 if (result == NIL) { 5008 result = cons = CONS(objects[i], NIL); 5009 GC_PROTECT(result); 5010 } 5011 else { 5012 RPLACD(cons, CONS(objects[i], NIL)); 5013 cons = CDR(cons); 5014 } 5015 } 5016 } 5017 } 5018 5019 if (inplace) { 5020 if (result == NIL) 5021 result = object; 5022 else 5023 RPLACD(cons, object); 5024 5025 if (!CONSP(sequence)) { 5026 result = sequence; 5027 CAR(result)->data.array.dim = 5028 FIXNUM(length - (copy - count)); 5029 } 5030 } 5031 else if (end < length) { 5032 i = end; 5033 /* Copy ending elements, if any */ 5034 if (result == NIL) { 5035 result = cons = CONS(CAR(object), NIL); 5036 GC_PROTECT(result); 5037 object = CDR(object); 5038 i++; 5039 } 5040 for (; i < length; i++, object = CDR(object)) { 5041 RPLACD(cons, CONS(CAR(object), NIL)); 5042 cons = CDR(cons); 5043 } 5044 } 5045 } 5046 5047 /* Release comparison vector */ 5048 LispFree(objects); 5049 } 5050 5051 GC_LEAVE(); 5052 5053 return (result); 5054} 5055 5056LispObj * 5057Lisp_Remove(LispBuiltin *builtin) 5058/* 5059 remove item sequence &key from-end test test-not start end count key 5060 */ 5061{ 5062 return (LispDeleteRemoveXSubstitute(builtin, REMOVE, NONE)); 5063} 5064 5065LispObj * 5066Lisp_RemoveIf(LispBuiltin *builtin) 5067/* 5068 remove-if predicate sequence &key from-end start end count key 5069 */ 5070{ 5071 return (LispDeleteRemoveXSubstitute(builtin, REMOVE, IF)); 5072} 5073 5074LispObj * 5075Lisp_RemoveIfNot(LispBuiltin *builtin) 5076/* 5077 remove-if-not predicate sequence &key from-end start end count key 5078 */ 5079{ 5080 return (LispDeleteRemoveXSubstitute(builtin, REMOVE, IFNOT)); 5081} 5082 5083LispObj * 5084Lisp_Remprop(LispBuiltin *builtin) 5085/* 5086 remprop symbol indicator 5087 */ 5088{ 5089 LispObj *symbol, *indicator; 5090 5091 indicator = ARGUMENT(1); 5092 symbol = ARGUMENT(0); 5093 5094 CHECK_SYMBOL(symbol); 5095 5096 return (LispRemAtomProperty(symbol->data.atom, indicator)); 5097} 5098 5099LispObj * 5100Lisp_Return(LispBuiltin *builtin) 5101/* 5102 return &optional result 5103 */ 5104{ 5105 unsigned blevel = lisp__data.block.block_level; 5106 5107 LispObj *result; 5108 5109 result = ARGUMENT(0); 5110 5111 while (blevel) { 5112 LispBlock *block = lisp__data.block.block[--blevel]; 5113 5114 if (block->type == LispBlockClosure) 5115 /* if reached a function call */ 5116 break; 5117 if (block->type == LispBlockTag && block->tag == NIL) { 5118 lisp__data.block.block_ret = result == UNSPEC ? NIL : EVAL(result); 5119 LispBlockUnwind(block); 5120 BLOCKJUMP(block); 5121 } 5122 } 5123 LispDestroy("%s: no visible NIL block", STRFUN(builtin)); 5124 5125 /*NOTREACHED*/ 5126 return (NIL); 5127} 5128 5129LispObj * 5130Lisp_ReturnFrom(LispBuiltin *builtin) 5131/* 5132 return-from name &optional result 5133 */ 5134{ 5135 unsigned blevel = lisp__data.block.block_level; 5136 5137 LispObj *name, *result; 5138 5139 result = ARGUMENT(1); 5140 name = ARGUMENT(0); 5141 5142 if (name != NIL && name != T && !SYMBOLP(name)) 5143 LispDestroy("%s: %s is not a valid block name", 5144 STRFUN(builtin), STROBJ(name)); 5145 5146 while (blevel) { 5147 LispBlock *block = lisp__data.block.block[--blevel]; 5148 5149 if (name == block->tag && 5150 (block->type == LispBlockTag || block->type == LispBlockClosure)) { 5151 lisp__data.block.block_ret = result == UNSPEC ? NIL : EVAL(result); 5152 LispBlockUnwind(block); 5153 BLOCKJUMP(block); 5154 } 5155 if (block->type == LispBlockClosure) 5156 /* can use return-from only in the current function */ 5157 break; 5158 } 5159 LispDestroy("%s: no visible block named %s", 5160 STRFUN(builtin), STROBJ(name)); 5161 5162 /*NOTREACHED*/ 5163 return (NIL); 5164} 5165 5166static LispObj * 5167LispXReverse(LispBuiltin *builtin, int inplace) 5168/* 5169 nreverse sequence 5170 reverse sequence 5171 */ 5172{ 5173 long length; 5174 LispObj *list, *result = NIL; 5175 5176 LispObj *sequence; 5177 5178 sequence = ARGUMENT(0); 5179 5180 /* Do error checking for arrays and object type. */ 5181 length = LispLength(sequence); 5182 if (length <= 1) 5183 return (sequence); 5184 5185 switch (XOBJECT_TYPE(sequence)) { 5186 case LispString_t: { 5187 long i; 5188 char *from, *to; 5189 5190 from = THESTR(sequence) + length - 1; 5191 if (inplace) { 5192 char temp; 5193 5194 CHECK_STRING_WRITABLE(sequence); 5195 to = THESTR(sequence); 5196 for (i = 0; i < length / 2; i++) { 5197 temp = to[i]; 5198 to[i] = from[-i]; 5199 from[-i] = temp; 5200 } 5201 result = sequence; 5202 } 5203 else { 5204 to = LispMalloc(length + 1); 5205 to[length] = '\0'; 5206 for (i = 0; i < length; i++) 5207 to[i] = from[-i]; 5208 result = STRING2(to); 5209 } 5210 } return (result); 5211 case LispCons_t: 5212 if (inplace) { 5213 long i, j; 5214 LispObj *temp; 5215 5216 /* For large lists this can be very slow, but for small 5217 * amounts of data, this avoid allocating a buffer to 5218 * to store the CAR of the sequence. This is only done 5219 * to not destroy the contents of a variable. 5220 */ 5221 for (i = 0, list = sequence; 5222 i < (length + 1) / 2; 5223 i++, list = CDR(list)) 5224 ; 5225 length /= 2; 5226 for (i = 0; i < length; i++, list = CDR(list)) { 5227 for (j = length - i - 1, result = sequence; 5228 j > 0; 5229 j--, result = CDR(result)) 5230 ; 5231 temp = CAR(list); 5232 RPLACA(list, CAR(result)); 5233 RPLACA(result, temp); 5234 } 5235 return (sequence); 5236 } 5237 list = sequence; 5238 break; 5239 case LispArray_t: 5240 if (inplace) { 5241 sequence->data.array.list = 5242 LispReverse(sequence->data.array.list); 5243 return (sequence); 5244 } 5245 list = sequence->data.array.list; 5246 break; 5247 default: /* LispNil_t */ 5248 return (result); 5249 } 5250 5251 { 5252 GC_ENTER(); 5253 LispObj *cons; 5254 5255 result = cons = CONS(CAR(list), NIL); 5256 GC_PROTECT(result); 5257 for (list = CDR(list); CONSP(list); list = CDR(list)) { 5258 RPLACD(cons, CONS(CAR(list), NIL)); 5259 cons = CDR(cons); 5260 } 5261 result = LispReverse(result); 5262 5263 GC_LEAVE(); 5264 } 5265 5266 if (ARRAYP(sequence)) { 5267 list = result; 5268 5269 result = LispNew(list, NIL); 5270 result->type = LispArray_t; 5271 result->data.array.list = list; 5272 result->data.array.dim = sequence->data.array.dim; 5273 result->data.array.rank = sequence->data.array.rank; 5274 result->data.array.type = sequence->data.array.type; 5275 result->data.array.zero = sequence->data.array.zero; 5276 } 5277 5278 return (result); 5279} 5280 5281LispObj * 5282Lisp_Reverse(LispBuiltin *builtin) 5283/* 5284 reverse sequence 5285 */ 5286{ 5287 return (LispXReverse(builtin, 0)); 5288} 5289 5290LispObj * 5291Lisp_Rplaca(LispBuiltin *builtin) 5292/* 5293 rplaca place value 5294 */ 5295{ 5296 LispObj *place, *value; 5297 5298 value = ARGUMENT(1); 5299 place = ARGUMENT(0); 5300 5301 CHECK_CONS(place); 5302 RPLACA(place, value); 5303 5304 return (place); 5305} 5306 5307LispObj * 5308Lisp_Rplacd(LispBuiltin *builtin) 5309/* 5310 rplacd place value 5311 */ 5312{ 5313 LispObj *place, *value; 5314 5315 value = ARGUMENT(1); 5316 place = ARGUMENT(0); 5317 5318 CHECK_CONS(place); 5319 RPLACD(place, value); 5320 5321 return (place); 5322} 5323 5324LispObj * 5325Lisp_Search(LispBuiltin *builtin) 5326/* 5327 search sequence1 sequence2 &key from-end test test-not key start1 start2 end1 end2 5328 */ 5329{ 5330 int code = 0, expect, value; 5331 long start1, start2, end1, end2, length1, length2, off1, off2, offset = -1; 5332 LispObj *cmp1, *cmp2, *list1 = NIL, *lambda; 5333 SeqInfo seq1, seq2; 5334 5335 LispObj *sequence1, *sequence2, *from_end, *test, *test_not, 5336 *key, *ostart1, *ostart2, *oend1, *oend2; 5337 5338 oend2 = ARGUMENT(9); 5339 oend1 = ARGUMENT(8); 5340 ostart2 = ARGUMENT(7); 5341 ostart1 = ARGUMENT(6); 5342 key = ARGUMENT(5); 5343 test_not = ARGUMENT(4); 5344 test = ARGUMENT(3); 5345 from_end = ARGUMENT(2); 5346 sequence2 = ARGUMENT(1); 5347 sequence1 = ARGUMENT(0); 5348 5349 LispCheckSequenceStartEnd(builtin, sequence1, ostart1, oend1, 5350 &start1, &end1, &length1); 5351 LispCheckSequenceStartEnd(builtin, sequence2, ostart2, oend2, 5352 &start2, &end2, &length2); 5353 5354 /* Check for special conditions */ 5355 if (start1 == end1) 5356 return (FIXNUM(end2)); 5357 else if (start2 == end2) 5358 return (start1 == end1 ? FIXNUM(start2) : NIL); 5359 5360 CHECK_TEST(); 5361 5362 if (from_end == UNSPEC) 5363 from_end = NIL; 5364 5365 SETSEQ(seq1, sequence1); 5366 SETSEQ(seq2, sequence2); 5367 5368 length1 = end1 - start1; 5369 length2 = end2 - start2; 5370 5371 /* update start of sequences */ 5372 if (start1) { 5373 if (seq1.type == LispString_t) 5374 seq1.data.string += start1; 5375 else { 5376 for (cmp1 = seq1.data.list; start1; cmp1 = CDR(cmp1), --start1) 5377 ; 5378 seq1.data.list = cmp1; 5379 } 5380 end1 = length1; 5381 } 5382 if (start2) { 5383 if (seq2.type == LispString_t) 5384 seq2.data.string += start2; 5385 else { 5386 for (cmp2 = seq2.data.list; start2; cmp2 = CDR(cmp2), --start2) 5387 ; 5388 seq2.data.list = cmp2; 5389 } 5390 end2 = length2; 5391 } 5392 5393 /* easier case */ 5394 if (from_end == NIL) { 5395 LispObj *list2 = NIL; 5396 5397 /* while a match is possible */ 5398 while (end2 - start2 >= length1) { 5399 5400 /* prepare to search */ 5401 off1 = 0; 5402 off2 = start2; 5403 if (seq1.type != LispString_t) 5404 list1 = seq1.data.list; 5405 if (seq2.type != LispString_t) 5406 list2 = seq2.data.list; 5407 5408 /* for every element that must match in sequence1 */ 5409 while (off1 < length1) { 5410 if (seq1.type == LispString_t) 5411 cmp1 = SCHAR(seq1.data.string[off1]); 5412 else 5413 cmp1 = CAR(list1); 5414 if (seq2.type == LispString_t) 5415 cmp2 = SCHAR(seq2.data.string[off2]); 5416 else 5417 cmp2 = CAR(list2); 5418 if (key != UNSPEC) { 5419 cmp1 = APPLY1(key, cmp1); 5420 cmp2 = APPLY1(key, cmp2); 5421 } 5422 5423 /* compare elements */ 5424 value = FCOMPARE(lambda, cmp1, cmp2, code); 5425 if (value != expect) 5426 break; 5427 5428 /* update offsets/sequence pointers */ 5429 ++off1; 5430 ++off2; 5431 if (seq1.type != LispString_t) 5432 list1 = CDR(list1); 5433 if (seq2.type != LispString_t) 5434 list2 = CDR(list2); 5435 } 5436 5437 /* if everything matched */ 5438 if (off1 == end1) { 5439 offset = off2 - length1; 5440 break; 5441 } 5442 5443 /* update offset/sequence2 pointer */ 5444 ++start2; 5445 if (seq2.type != LispString_t) 5446 seq2.data.list = CDR(seq2.data.list); 5447 } 5448 } 5449 else { 5450 /* allocate vector if required, only list2 requires it. 5451 * list1 can be traversed forward */ 5452 if (seq2.type != LispString_t) { 5453 cmp2 = seq2.data.list; 5454 seq2.data.vector = LispMalloc(sizeof(LispObj*) * length2); 5455 for (off2 = 0; off2 < end2; off2++, cmp2 = CDR(cmp2)) 5456 seq2.data.vector[off2] = CAR(cmp2); 5457 } 5458 5459 /* while a match is possible */ 5460 while (end2 >= length1) { 5461 5462 /* prepare to search */ 5463 off1 = 0; 5464 off2 = end2 - length1; 5465 if (seq1.type != LispString_t) 5466 list1 = seq1.data.list; 5467 5468 /* for every element that must match in sequence1 */ 5469 while (off1 < end1) { 5470 if (seq1.type == LispString_t) 5471 cmp1 = SCHAR(seq1.data.string[off1]); 5472 else 5473 cmp1 = CAR(list1); 5474 if (seq2.type == LispString_t) 5475 cmp2 = SCHAR(seq2.data.string[off2]); 5476 else 5477 cmp2 = seq2.data.vector[off2]; 5478 if (key != UNSPEC) { 5479 cmp1 = APPLY1(key, cmp1); 5480 cmp2 = APPLY1(key, cmp2); 5481 } 5482 5483 /* Compare elements */ 5484 value = FCOMPARE(lambda, cmp1, cmp2, code); 5485 if (value != expect) 5486 break; 5487 5488 /* Update offsets */ 5489 ++off1; 5490 ++off2; 5491 if (seq1.type != LispString_t) 5492 list1 = CDR(list1); 5493 } 5494 5495 /* If all elements matched */ 5496 if (off1 == end1) { 5497 offset = off2 - length1; 5498 break; 5499 } 5500 5501 /* Update offset */ 5502 --end2; 5503 } 5504 5505 if (seq2.type != LispString_t) 5506 LispFree(seq2.data.vector); 5507 } 5508 5509 return (offset == -1 ? NIL : FIXNUM(offset)); 5510} 5511 5512/* 5513 * ext::getenv 5514 */ 5515LispObj * 5516Lisp_Setenv(LispBuiltin *builtin) 5517/* 5518 setenv name value &optional overwrite 5519 */ 5520{ 5521 char *name, *value; 5522 5523 LispObj *oname, *ovalue, *overwrite; 5524 5525 overwrite = ARGUMENT(2); 5526 ovalue = ARGUMENT(1); 5527 oname = ARGUMENT(0); 5528 5529 CHECK_STRING(oname); 5530 name = THESTR(oname); 5531 5532 CHECK_STRING(ovalue); 5533 value = THESTR(ovalue); 5534 5535 setenv(name, value, overwrite != UNSPEC && overwrite != NIL); 5536 value = getenv(name); 5537 5538 return (value ? STRING(value) : NIL); 5539} 5540 5541LispObj * 5542Lisp_Set(LispBuiltin *builtin) 5543/* 5544 set symbol value 5545 */ 5546{ 5547 LispAtom *atom; 5548 LispObj *symbol, *value; 5549 5550 value = ARGUMENT(1); 5551 symbol = ARGUMENT(0); 5552 5553 CHECK_SYMBOL(symbol); 5554 atom = symbol->data.atom; 5555 if (atom->dyn) 5556 LispSetVar(symbol, value); 5557 else if (atom->watch || !atom->a_object) 5558 LispSetAtomObjectProperty(atom, value); 5559 else { 5560 CHECK_CONSTANT(symbol); 5561 SETVALUE(atom, value); 5562 } 5563 5564 return (value); 5565} 5566 5567LispObj * 5568Lisp_SetDifference(LispBuiltin *builtin) 5569/* 5570 set-difference list1 list2 &key test test-not key 5571 */ 5572{ 5573 return (LispListSet(builtin, SETDIFFERENCE)); 5574} 5575 5576LispObj * 5577Lisp_SetExclusiveOr(LispBuiltin *builtin) 5578/* 5579 set-exclusive-or list1 list2 &key test test-not key 5580 */ 5581{ 5582 return (LispListSet(builtin, SETEXCLUSIVEOR)); 5583} 5584 5585LispObj * 5586Lisp_NsetExclusiveOr(LispBuiltin *builtin) 5587/* 5588 nset-exclusive-or list1 list2 &key test test-not key 5589 */ 5590{ 5591 return (LispListSet(builtin, NSETEXCLUSIVEOR)); 5592} 5593 5594LispObj * 5595Lisp_SetQ(LispBuiltin *builtin) 5596/* 5597 setq &rest form 5598 */ 5599{ 5600 LispObj *result, *variable, *form; 5601 5602 form = ARGUMENT(0); 5603 5604 result = NIL; 5605 for (; CONSP(form); form = CDR(form)) { 5606 variable = CAR(form); 5607 CHECK_SYMBOL(variable); 5608 CHECK_CONSTANT(variable); 5609 form = CDR(form); 5610 if (!CONSP(form)) 5611 LispDestroy("%s: odd number of arguments", STRFUN(builtin)); 5612 result = EVAL(CAR(form)); 5613 LispSetVar(variable, result); 5614 } 5615 5616 return (result); 5617} 5618 5619LispObj * 5620Lisp_Psetq(LispBuiltin *builtin) 5621/* 5622 psetq &rest form 5623 */ 5624{ 5625 GC_ENTER(); 5626 int base = gc__protect; 5627 LispObj *value, *symbol, *list, *form; 5628 5629 form = ARGUMENT(0); 5630 5631 /* parallel setq, first pass evaluate values and basic error checking */ 5632 for (list = form; CONSP(list); list = CDR(list)) { 5633 symbol = CAR(list); 5634 CHECK_SYMBOL(symbol); 5635 list = CDR(list); 5636 if (!CONSP(list)) 5637 LispDestroy("%s: odd number of arguments", STRFUN(builtin)); 5638 value = EVAL(CAR(list)); 5639 GC_PROTECT(value); 5640 } 5641 5642 /* second pass, assign values */ 5643 for (; CONSP(form); form = CDDR(form)) { 5644 symbol = CAR(form); 5645 CHECK_CONSTANT(symbol); 5646 LispSetVar(symbol, lisp__data.protect.objects[base++]); 5647 } 5648 GC_LEAVE(); 5649 5650 return (NIL); 5651} 5652 5653LispObj * 5654Lisp_Setf(LispBuiltin *builtin) 5655/* 5656 setf &rest form 5657 */ 5658{ 5659 LispAtom *atom; 5660 LispObj *setf, *place, *value, *result = NIL, *data; 5661 5662 LispObj *form; 5663 5664 form = ARGUMENT(0); 5665 5666 for (; CONSP(form); form = CDR(form)) { 5667 place = CAR(form); 5668 form = CDR(form); 5669 if (!CONSP(form)) 5670 LispDestroy("%s: odd number of arguments", STRFUN(builtin)); 5671 value = CAR(form); 5672 5673 if (!POINTERP(place)) 5674 goto invalid_place; 5675 if (XSYMBOLP(place)) { 5676 CHECK_CONSTANT(place); 5677 result = EVAL(value); 5678 (void)LispSetVar(place, result); 5679 } 5680 else if (XCONSP(place)) { 5681 /* it really should not be required to protect any object 5682 * evaluated here, but is done for safety in case one of 5683 * the evaluated forms returns data not gc protected, what 5684 * could cause surprises if the object is garbage collected 5685 * before finishing setf. */ 5686 GC_ENTER(); 5687 5688 setf = CAR(place); 5689 if (!SYMBOLP(setf)) 5690 goto invalid_place; 5691 if (!CONSP(CDR(place))) 5692 goto invalid_place; 5693 5694 value = EVAL(value); 5695 GC_PROTECT(value); 5696 5697 atom = setf->data.atom; 5698 if (atom->a_defsetf == 0) { 5699 if (atom->a_defstruct && 5700 atom->property->structure.function >= 0) { 5701 /* Use a default setf method for the structure field, as 5702 * if this definition have been done 5703 * (defsetf THE-STRUCT-FIELD (struct) (value) 5704 * `(lisp::struct-store 'THE-STRUCT-FIELD ,struct ,value)) 5705 */ 5706 place = CDR(place); 5707 data = CAR(place); 5708 if (CONSP(CDR(place))) 5709 goto invalid_place; 5710 data = EVAL(data); 5711 GC_PROTECT(data); 5712 result = APPLY3(Ostruct_store, setf, data, value); 5713 GC_LEAVE(); 5714 continue; 5715 } 5716 /* Must also expand macros */ 5717 else if (atom->a_function && 5718 atom->property->fun.function->funtype == LispMacro) { 5719 result = LispRunSetfMacro(atom, CDR(place), value); 5720 continue; 5721 } 5722 goto invalid_place; 5723 } 5724 5725 place = CDR(place); 5726 setf = setf->data.atom->property->setf; 5727 if (SYMBOLP(setf)) { 5728 LispObj *arguments, *cons; 5729 5730 if (!CONSP(CDR(place))) { 5731 arguments = EVAL(CAR(place)); 5732 GC_PROTECT(arguments); 5733 result = APPLY2(setf, arguments, value); 5734 } 5735 else if (!CONSP(CDDR(place))) { 5736 arguments = EVAL(CAR(place)); 5737 GC_PROTECT(arguments); 5738 cons = EVAL(CADR(place)); 5739 GC_PROTECT(cons); 5740 result = APPLY3(setf, arguments, cons, value); 5741 } 5742 else { 5743 arguments = cons = CONS(EVAL(CAR(place)), NIL); 5744 GC_PROTECT(arguments); 5745 for (place = CDR(place); CONSP(place); place = CDR(place)) { 5746 RPLACD(cons, CONS(EVAL(CAR(place)), NIL)); 5747 cons = CDR(cons); 5748 } 5749 RPLACD(cons, CONS(value, NIL)); 5750 result = APPLY(setf, arguments); 5751 } 5752 } 5753 else 5754 result = LispRunSetf(atom->property->salist, setf, place, value); 5755 GC_LEAVE(); 5756 } 5757 else 5758 goto invalid_place; 5759 } 5760 5761 return (result); 5762invalid_place: 5763 LispDestroy("%s: %s is an invalid place", STRFUN(builtin), STROBJ(place)); 5764 /*NOTREACHED*/ 5765 return (NIL); 5766} 5767 5768LispObj * 5769Lisp_Psetf(LispBuiltin *builtin) 5770/* 5771 psetf &rest form 5772 */ 5773{ 5774 int base; 5775 GC_ENTER(); 5776 LispAtom *atom; 5777 LispObj *setf, *place = NIL, *value, *data; 5778 5779 LispObj *form; 5780 5781 form = ARGUMENT(0); 5782 5783 /* parallel setf, first pass evaluate values and basic error checking */ 5784 base = gc__protect; 5785 for (setf = form; CONSP(setf); setf = CDR(setf)) { 5786 if (!POINTERP(CAR(setf))) 5787 goto invalid_place; 5788 setf = CDR(setf); 5789 if (!CONSP(setf)) 5790 LispDestroy("%s: odd number of arguments", STRFUN(builtin)); 5791 value = EVAL(CAR(setf)); 5792 GC_PROTECT(value); 5793 } 5794 5795 /* second pass, assign values */ 5796 for (; CONSP(form); form = CDDR(form)) { 5797 place = CAR(form); 5798 value = lisp__data.protect.objects[base++]; 5799 5800 if (XSYMBOLP(place)) { 5801 CHECK_CONSTANT(place); 5802 (void)LispSetVar(place, value); 5803 } 5804 else if (XCONSP(place)) { 5805 LispObj *arguments, *cons; 5806 int xbase = lisp__data.protect.length; 5807 5808 setf = CAR(place); 5809 if (!SYMBOLP(setf)) 5810 goto invalid_place; 5811 if (!CONSP(CDR(place))) 5812 goto invalid_place; 5813 5814 atom = setf->data.atom; 5815 if (atom->a_defsetf == 0) { 5816 if (atom->a_defstruct && 5817 atom->property->structure.function >= 0) { 5818 place = CDR(place); 5819 data = CAR(place); 5820 if (CONSP(CDR(place))) 5821 goto invalid_place; 5822 data = EVAL(data); 5823 GC_PROTECT(data); 5824 (void)APPLY3(Ostruct_store, setf, data, value); 5825 lisp__data.protect.length = xbase; 5826 continue; 5827 } 5828 else if (atom->a_function && 5829 atom->property->fun.function->funtype == LispMacro) { 5830 (void)LispRunSetfMacro(atom, CDR(place), value); 5831 lisp__data.protect.length = xbase; 5832 continue; 5833 } 5834 goto invalid_place; 5835 } 5836 5837 place = CDR(place); 5838 setf = setf->data.atom->property->setf; 5839 if (SYMBOLP(setf)) { 5840 if (!CONSP(CDR(place))) { 5841 arguments = EVAL(CAR(place)); 5842 GC_PROTECT(arguments); 5843 (void)APPLY2(setf, arguments, value); 5844 } 5845 else if (!CONSP(CDDR(place))) { 5846 arguments = EVAL(CAR(place)); 5847 GC_PROTECT(arguments); 5848 cons = EVAL(CADR(place)); 5849 GC_PROTECT(cons); 5850 (void)APPLY3(setf, arguments, cons, value); 5851 } 5852 else { 5853 arguments = cons = CONS(EVAL(CAR(place)), NIL); 5854 GC_PROTECT(arguments); 5855 for (place = CDR(place); CONSP(place); place = CDR(place)) { 5856 RPLACD(cons, CONS(EVAL(CAR(place)), NIL)); 5857 cons = CDR(cons); 5858 } 5859 RPLACD(cons, CONS(value, NIL)); 5860 (void)APPLY(setf, arguments); 5861 } 5862 lisp__data.protect.length = xbase; 5863 } 5864 else 5865 (void)LispRunSetf(atom->property->salist, setf, place, value); 5866 } 5867 else 5868 goto invalid_place; 5869 } 5870 GC_LEAVE(); 5871 5872 return (NIL); 5873invalid_place: 5874 LispDestroy("%s: %s is an invalid place", STRFUN(builtin), STROBJ(place)); 5875 /*NOTREACHED*/ 5876 return (NIL); 5877} 5878 5879LispObj * 5880Lisp_Sleep(LispBuiltin *builtin) 5881/* 5882 sleep seconds 5883 */ 5884{ 5885 long sec, msec; 5886 double value, dsec; 5887 5888 LispObj *seconds; 5889 5890 seconds = ARGUMENT(0); 5891 5892 value = -1.0; 5893 switch (OBJECT_TYPE(seconds)) { 5894 case LispFixnum_t: 5895 value = FIXNUM_VALUE(seconds); 5896 break; 5897 case LispDFloat_t: 5898 value = DFLOAT_VALUE(seconds); 5899 break; 5900 default: 5901 break; 5902 } 5903 5904 if (value < 0.0 || value > MOST_POSITIVE_FIXNUM) 5905 LispDestroy("%s: %s is not a positive fixnum", 5906 STRFUN(builtin), STROBJ(seconds)); 5907 5908 msec = modf(value, &dsec) * 1e6; 5909 sec = dsec; 5910 5911 if (sec) 5912 sleep(sec); 5913 if (msec) 5914 usleep(msec); 5915 5916 return (NIL); 5917} 5918 5919/* 5920 * This function is called recursively, but the contents of "list2" are 5921 * kept gc protected until it returns to LispSort. This is required partly 5922 * because the "gc protection logic" protects an object, not the contents 5923 * of the c pointer. 5924 */ 5925static LispObj * 5926LispMergeSort(LispObj *list, LispObj *predicate, LispObj *key, int code) 5927{ 5928 int protect; 5929 LispObj *list1, *list2, *left, *right, *result, *cons; 5930 5931 /* Check if list length is larger than 1 */ 5932 if (!CONSP(list) || !CONSP(CDR(list))) 5933 return (list); 5934 5935 list1 = list2 = list; 5936 for (;;) { 5937 list = CDR(list); 5938 if (!CONSP(list)) 5939 break; 5940 list = CDR(list); 5941 if (!CONSP(list)) 5942 break; 5943 list2 = CDR(list2); 5944 } 5945 cons = list2; 5946 list2 = CDR(list2); 5947 RPLACD(cons, NIL); 5948 5949 protect = 0; 5950 if (lisp__data.protect.length + 2 >= lisp__data.protect.space) 5951 LispMoreProtects(); 5952 lisp__data.protect.objects[lisp__data.protect.length++] = list2; 5953 list1 = LispMergeSort(list1, predicate, key, code); 5954 list2 = LispMergeSort(list2, predicate, key, code); 5955 5956 left = CAR(list1); 5957 right = CAR(list2); 5958 if (key != UNSPEC) { 5959 protect = lisp__data.protect.length; 5960 left = APPLY1(key, left); 5961 lisp__data.protect.objects[protect] = left; 5962 right = APPLY1(key, right); 5963 lisp__data.protect.objects[protect + 1] = right; 5964 } 5965 5966 result = NIL; 5967 for (;;) { 5968 if ((FCOMPARE(predicate, left, right, code)) == 0 && 5969 (FCOMPARE(predicate, right, left, code)) == 1) { 5970 /* right is "smaller" */ 5971 if (result == NIL) 5972 result = list2; 5973 else 5974 RPLACD(cons, list2); 5975 cons = list2; 5976 list2 = CDR(list2); 5977 if (!CONSP(list2)) { 5978 RPLACD(cons, list1); 5979 break; 5980 } 5981 right = CAR(list2); 5982 if (key != UNSPEC) { 5983 right = APPLY1(key, right); 5984 lisp__data.protect.objects[protect + 1] = right; 5985 } 5986 } 5987 else { 5988 /* left is "smaller" */ 5989 if (result == NIL) 5990 result = list1; 5991 else 5992 RPLACD(cons, list1); 5993 cons = list1; 5994 list1 = CDR(list1); 5995 if (!CONSP(list1)) { 5996 RPLACD(cons, list2); 5997 break; 5998 } 5999 left = CAR(list1); 6000 if (key != UNSPEC) { 6001 left = APPLY1(key, left); 6002 lisp__data.protect.objects[protect] = left; 6003 } 6004 } 6005 } 6006 if (key != UNSPEC) 6007 lisp__data.protect.length = protect; 6008 6009 return (result); 6010} 6011 6012/* XXX The first version made a copy of the list and then adjusted 6013 * the CARs of the list. To minimize GC time now it is now doing 6014 * the sort inplace. So, instead of writing just (sort variable) 6015 * now it is required to write (setq variable (sort variable)) 6016 * if the variable should always keep all elements. 6017 */ 6018LispObj * 6019Lisp_Sort(LispBuiltin *builtin) 6020/* 6021 sort sequence predicate &key key 6022 */ 6023{ 6024 GC_ENTER(); 6025 int istring, code; 6026 long length; 6027 char *string; 6028 6029 LispObj *list, *work, *cons = NULL; 6030 6031 LispObj *sequence, *predicate, *key; 6032 6033 key = ARGUMENT(2); 6034 predicate = ARGUMENT(1); 6035 sequence = ARGUMENT(0); 6036 6037 length = LispLength(sequence); 6038 if (length < 2) 6039 return (sequence); 6040 6041 list = sequence; 6042 istring = XSTRINGP(sequence); 6043 if (istring) { 6044 CHECK_STRING_WRITABLE(sequence); 6045 /* Convert string to list */ 6046 string = THESTR(sequence); 6047 work = cons = CONS(SCHAR(string[0]), NIL); 6048 GC_PROTECT(work); 6049 for (++string; *string; ++string) { 6050 RPLACD(cons, CONS(SCHAR(*string), NIL)); 6051 cons = CDR(cons); 6052 } 6053 } 6054 else if (ARRAYP(list)) 6055 work = list->data.array.list; 6056 else 6057 work = list; 6058 6059 FUNCTION_CHECK(predicate); 6060 code = FCODE(predicate); 6061 work = LispMergeSort(work, predicate, key, code); 6062 6063 if (istring) { 6064 /* Convert list to string */ 6065 string = THESTR(sequence); 6066 for (; CONSP(work); ++string, work = CDR(work)) 6067 *string = SCHAR_VALUE(CAR(work)); 6068 } 6069 else if (ARRAYP(list)) 6070 list->data.array.list = work; 6071 else 6072 sequence = work; 6073 GC_LEAVE(); 6074 6075 return (sequence); 6076} 6077 6078LispObj * 6079Lisp_Subseq(LispBuiltin *builtin) 6080/* 6081 subseq sequence start &optional end 6082 */ 6083{ 6084 long start, end, length, seqlength; 6085 6086 LispObj *sequence, *ostart, *oend, *result; 6087 6088 oend = ARGUMENT(2); 6089 ostart = ARGUMENT(1); 6090 sequence = ARGUMENT(0); 6091 6092 LispCheckSequenceStartEnd(builtin, sequence, ostart, oend, 6093 &start, &end, &length); 6094 6095 seqlength = end - start; 6096 6097 if (sequence == NIL) 6098 result = NIL; 6099 else if (XSTRINGP(sequence)) { 6100 char *string = LispMalloc(seqlength + 1); 6101 6102 memcpy(string, THESTR(sequence) + start, seqlength); 6103 string[seqlength] = '\0'; 6104 result = STRING2(string); 6105 } 6106 else { 6107 GC_ENTER(); 6108 LispObj *object; 6109 6110 if (end > start) { 6111 /* list or array */ 6112 int count; 6113 LispObj *cons; 6114 6115 if (ARRAYP(sequence)) 6116 object = sequence->data.array.list; 6117 else 6118 object = sequence; 6119 /* goto first element to copy */ 6120 for (count = 0; count < start; count++, object = CDR(object)) 6121 ; 6122 result = cons = CONS(CAR(object), NIL); 6123 GC_PROTECT(result); 6124 for (++count, object = CDR(object); count < end; count++, 6125 object = CDR(object)) { 6126 RPLACD(cons, CONS(CAR(object), NIL)); 6127 cons = CDR(cons); 6128 } 6129 } 6130 else 6131 result = NIL; 6132 6133 if (ARRAYP(sequence)) { 6134 object = LispNew(NIL, NIL); 6135 GC_PROTECT(object); 6136 object->type = LispArray_t; 6137 object->data.array.list = result; 6138 object->data.array.dim = CONS(FIXNUM(seqlength), NIL); 6139 object->data.array.rank = 1; 6140 object->data.array.type = sequence->data.array.type; 6141 object->data.array.zero = length == 0; 6142 result = object; 6143 } 6144 GC_LEAVE(); 6145 } 6146 6147 return (result); 6148} 6149 6150LispObj * 6151Lisp_Subsetp(LispBuiltin *builtin) 6152/* 6153 subsetp list1 list2 &key test test-not key 6154 */ 6155{ 6156 return (LispListSet(builtin, SUBSETP)); 6157} 6158 6159 6160LispObj * 6161Lisp_Substitute(LispBuiltin *builtin) 6162/* 6163 substitute newitem olditem sequence &key from-end test test-not start end count key 6164 */ 6165{ 6166 return (LispDeleteRemoveXSubstitute(builtin, SUBSTITUTE, NONE)); 6167} 6168 6169LispObj * 6170Lisp_SubstituteIf(LispBuiltin *builtin) 6171/* 6172 substitute-if newitem test sequence &key from-end start end count key 6173 */ 6174{ 6175 return (LispDeleteRemoveXSubstitute(builtin, SUBSTITUTE, IF)); 6176} 6177 6178LispObj * 6179Lisp_SubstituteIfNot(LispBuiltin *builtin) 6180/* 6181 substitute-if-not newitem test sequence &key from-end start end count key 6182 */ 6183{ 6184 return (LispDeleteRemoveXSubstitute(builtin, SUBSTITUTE, IFNOT)); 6185} 6186 6187LispObj * 6188Lisp_Symbolp(LispBuiltin *builtin) 6189/* 6190 symbolp object 6191 */ 6192{ 6193 LispObj *object; 6194 6195 object = ARGUMENT(0); 6196 6197 return (SYMBOLP(object) ? T : NIL); 6198} 6199 6200LispObj * 6201Lisp_SymbolFunction(LispBuiltin *builtin) 6202/* 6203 symbol-function symbol 6204 */ 6205{ 6206 LispObj *symbol; 6207 6208 symbol = ARGUMENT(0); 6209 CHECK_SYMBOL(symbol); 6210 6211 return (LispSymbolFunction(symbol)); 6212} 6213 6214LispObj * 6215Lisp_SymbolName(LispBuiltin *builtin) 6216/* 6217 symbol-name symbol 6218 */ 6219{ 6220 LispObj *symbol; 6221 6222 symbol = ARGUMENT(0); 6223 CHECK_SYMBOL(symbol); 6224 6225 return (LispSymbolName(symbol)); 6226} 6227 6228LispObj * 6229Lisp_SymbolPackage(LispBuiltin *builtin) 6230/* 6231 symbol-package symbol 6232 */ 6233{ 6234 LispObj *symbol; 6235 6236 symbol = ARGUMENT(0); 6237 CHECK_SYMBOL(symbol); 6238 6239 symbol = symbol->data.atom->package; 6240 6241 return (symbol ? symbol : NIL); 6242} 6243 6244LispObj * 6245Lisp_SymbolPlist(LispBuiltin *builtin) 6246/* 6247 symbol-plist symbol 6248 */ 6249{ 6250 LispObj *symbol; 6251 6252 symbol = ARGUMENT(0); 6253 6254 CHECK_SYMBOL(symbol); 6255 6256 return (symbol->data.atom->a_property ? 6257 symbol->data.atom->property->properties : NIL); 6258} 6259 6260LispObj * 6261Lisp_SymbolValue(LispBuiltin *builtin) 6262/* 6263 symbol-value symbol 6264 */ 6265{ 6266 LispAtom *atom; 6267 LispObj *symbol; 6268 6269 symbol = ARGUMENT(0); 6270 6271 CHECK_SYMBOL(symbol); 6272 atom = symbol->data.atom; 6273 if (!atom->a_object || atom->property->value == UNBOUND) { 6274 if (atom->package == lisp__data.keyword) 6275 return (symbol); 6276 LispDestroy("%s: the symbol %s has no value", 6277 STRFUN(builtin), STROBJ(symbol)); 6278 } 6279 6280 return (atom->dyn ? LispGetVar(symbol) : atom->property->value); 6281} 6282 6283LispObj * 6284Lisp_Tagbody(LispBuiltin *builtin) 6285/* 6286 tagbody &rest body 6287 */ 6288{ 6289 GC_ENTER(); 6290 int stack, lex, length; 6291 LispObj *list, *body, *ptr, *tag, *labels, *map, **p_body; 6292 LispBlock *block; 6293 6294 body = ARGUMENT(0); 6295 6296 /* Save environment information */ 6297 stack = lisp__data.stack.length; 6298 lex = lisp__data.env.lex; 6299 length = lisp__data.env.length; 6300 6301 /* Since the body may be large, and the code may iterate several 6302 * thousand times, it is not a bad idea to avoid checking all 6303 * elements of the body to verify if it is a tag. */ 6304 for (labels = map = NIL, ptr = body; CONSP(ptr); ptr = CDR(ptr)) { 6305 tag = CAR(ptr); 6306 switch (OBJECT_TYPE(tag)) { 6307 case LispNil_t: 6308 case LispAtom_t: 6309 case LispFixnum_t: 6310 /* Don't allow duplicated labels */ 6311 for (list = labels; CONSP(list); list = CDDR(list)) { 6312 if (CAR(list) == tag) 6313 LispDestroy("%s: tag %s specified more than once", 6314 STRFUN(builtin), STROBJ(tag)); 6315 } 6316 if (labels == NIL) { 6317 labels = CONS(tag, CONS(NIL, NIL)); 6318 map = CDR(labels); 6319 GC_PROTECT(labels); 6320 } 6321 else { 6322 RPLACD(map, CONS(tag, CONS(NIL, NIL))); 6323 map = CDDR(map); 6324 } 6325 break; 6326 case LispCons_t: 6327 /* Restart point for tag */ 6328 if (map != NIL && CAR(map) == NIL) 6329 RPLACA(map, ptr); 6330 break; 6331 default: 6332 break; 6333 } 6334 } 6335 /* Check for consecutive labels without code between them */ 6336 for (ptr = labels; CONSP(ptr); ptr = CDDR(ptr)) { 6337 if (CADR(ptr) == NIL) { 6338 for (map = CDDR(ptr); CONSP(map); map = CDDR(map)) { 6339 if (CADR(map) != NIL) { 6340 RPLACA(CDR(ptr), CADR(map)); 6341 break; 6342 } 6343 } 6344 } 6345 } 6346 6347 /* Initialize */ 6348 list = body; 6349 p_body = &body; 6350 block = LispBeginBlock(NIL, LispBlockBody); 6351 6352 /* Loop */ 6353 if (setjmp(block->jmp) != 0) { 6354 /* Restore environment */ 6355 lisp__data.stack.length = stack; 6356 lisp__data.env.lex = lex; 6357 lisp__data.env.head = lisp__data.env.length = length; 6358 6359 tag = lisp__data.block.block_ret; 6360 for (ptr = labels; CONSP(ptr); ptr = CDDR(ptr)) { 6361 map = CAR(ptr); 6362 if (map == tag) 6363 break; 6364 } 6365 6366 if (!CONSP(ptr)) 6367 LispDestroy("%s: no such tag %s", STRFUN(builtin), STROBJ(tag)); 6368 6369 *p_body = CADR(ptr); 6370 } 6371 6372 /* Execute code */ 6373 for (; CONSP(body); body = CDR(body)) { 6374 LispObj *form = CAR(body); 6375 6376 if (CONSP(form)) 6377 EVAL(form); 6378 } 6379 /* If got here, (go) not called, else, labels will be candidate to gc 6380 * when GC_LEAVE() be called by the code in the bottom of the stack. */ 6381 GC_LEAVE(); 6382 6383 /* Finished */ 6384 LispEndBlock(block); 6385 6386 /* Always return NIL */ 6387 return (NIL); 6388} 6389 6390LispObj * 6391Lisp_The(LispBuiltin *builtin) 6392/* 6393 the value-type form 6394 */ 6395{ 6396 LispObj *value_type, *form; 6397 6398 form = ARGUMENT(1); 6399 value_type = ARGUMENT(0); 6400 6401 form = EVAL(form); 6402 6403 return (LispCoerce(builtin, form, value_type)); 6404} 6405 6406LispObj * 6407Lisp_Throw(LispBuiltin *builtin) 6408/* 6409 throw tag result 6410 */ 6411{ 6412 unsigned blevel = lisp__data.block.block_level; 6413 6414 LispObj *tag, *result; 6415 6416 result = ARGUMENT(1); 6417 tag = ARGUMENT(0); 6418 6419 tag = EVAL(tag); 6420 6421 if (blevel == 0) 6422 LispDestroy("%s: not within a block", STRFUN(builtin)); 6423 6424 while (blevel) { 6425 LispBlock *block = lisp__data.block.block[--blevel]; 6426 6427 if (block->type == LispBlockCatch && tag == block->tag) { 6428 lisp__data.block.block_ret = EVAL(result); 6429 LispBlockUnwind(block); 6430 BLOCKJUMP(block); 6431 } 6432 } 6433 LispDestroy("%s: %s is not a valid tag", STRFUN(builtin), STROBJ(tag)); 6434 6435 /*NOTREACHED*/ 6436 return (NIL); 6437} 6438 6439static LispObj * 6440LispTreeEqual(LispObj *left, LispObj *right, LispObj *test, int expect) 6441{ 6442 LispObj *cmp_left, *cmp_right; 6443 6444 if ((OBJECT_TYPE(left)) ^ (OBJECT_TYPE(right))) 6445 return (NIL); 6446 if (CONSP(left)) { 6447 for (; CONSP(left) && CONSP(right); 6448 left = CDR(left), right = CDR(right)) { 6449 cmp_left = CAR(left); 6450 cmp_right = CAR(right); 6451 if ((OBJECT_TYPE(cmp_left)) ^ (OBJECT_TYPE(cmp_right))) 6452 return (NIL); 6453 if (CONSP(cmp_left)) { 6454 if (LispTreeEqual(cmp_left, cmp_right, test, expect) == NIL) 6455 return (NIL); 6456 } 6457 else { 6458 if (POINTERP(cmp_left) && 6459 (XQUOTEP(cmp_left) || XBACKQUOTEP(cmp_left))) { 6460 cmp_left = cmp_left->data.quote; 6461 cmp_right = cmp_right->data.quote; 6462 } 6463 else if (COMMAP(cmp_left)) { 6464 cmp_left = cmp_left->data.comma.eval; 6465 cmp_right = cmp_right->data.comma.eval; 6466 } 6467 if ((APPLY2(test, cmp_left, cmp_right) != NIL) != expect) 6468 return (NIL); 6469 } 6470 } 6471 if ((OBJECT_TYPE(left)) ^ (OBJECT_TYPE(right))) 6472 return (NIL); 6473 } 6474 6475 if (POINTERP(left) && (XQUOTEP(left) || XBACKQUOTEP(left))) { 6476 left = left->data.quote; 6477 right = right->data.quote; 6478 } 6479 else if (COMMAP(left)) { 6480 left = left->data.comma.eval; 6481 right = right->data.comma.eval; 6482 } 6483 6484 return ((APPLY2(test, left, right) != NIL) == expect ? T : NIL); 6485} 6486 6487LispObj * 6488Lisp_TreeEqual(LispBuiltin *builtin) 6489/* 6490 tree-equal tree-1 tree-2 &key test test-not 6491 */ 6492{ 6493 int expect; 6494 LispObj *compare; 6495 6496 LispObj *tree_1, *tree_2, *test, *test_not; 6497 6498 test_not = ARGUMENT(3); 6499 test = ARGUMENT(2); 6500 tree_2 = ARGUMENT(1); 6501 tree_1 = ARGUMENT(0); 6502 6503 CHECK_TEST_0(); 6504 if (test_not != UNSPEC) { 6505 expect = 0; 6506 compare = test_not; 6507 } 6508 else { 6509 if (test == UNSPEC) 6510 test = Oeql; 6511 expect = 1; 6512 compare = test; 6513 } 6514 6515 return (LispTreeEqual(tree_1, tree_2, compare, expect)); 6516} 6517 6518LispObj * 6519Lisp_Typep(LispBuiltin *builtin) 6520/* 6521 typep object type 6522 */ 6523{ 6524 LispObj *result = NULL; 6525 6526 LispObj *object, *type; 6527 6528 type = ARGUMENT(1); 6529 object = ARGUMENT(0); 6530 6531 if (SYMBOLP(type)) { 6532 Atom_id atom = ATOMID(type); 6533 6534 if (OBJECT_TYPE(object) == LispStruct_t) 6535 result = ATOMID(CAR(object->data.struc.def)) == atom ? T : NIL; 6536 else if (type->data.atom->a_defstruct && 6537 type->data.atom->property->structure.function == STRUCT_NAME) 6538 result = NIL; 6539 else if (atom == Snil) 6540 result = object == NIL ? T : NIL; 6541 else if (atom == St) 6542 result = object == T ? T : NIL; 6543 else if (atom == Satom) 6544 result = !CONSP(object) ? T : NIL; 6545 else if (atom == Ssymbol) 6546 result = SYMBOLP(object) || object == NIL || object == T ? T : NIL; 6547 else if (atom == Sinteger) 6548 result = INTEGERP(object) ? T : NIL; 6549 else if (atom == Srational) 6550 result = RATIONALP(object) ? T : NIL; 6551 else if (atom == Scons || atom == Slist) 6552 result = CONSP(object) ? T : NIL; 6553 else if (atom == Sstring) 6554 result = STRINGP(object) ? T : NIL; 6555 else if (atom == Scharacter) 6556 result = SCHARP(object) ? T : NIL; 6557 else if (atom == Scomplex) 6558 result = COMPLEXP(object) ? T : NIL; 6559 else if (atom == Svector || atom == Sarray) 6560 result = ARRAYP(object) ? T : NIL; 6561 else if (atom == Skeyword) 6562 result = KEYWORDP(object) ? T : NIL; 6563 else if (atom == Sfunction) 6564 result = LAMBDAP(object) ? T : NIL; 6565 else if (atom == Spathname) 6566 result = PATHNAMEP(object) ? T : NIL; 6567 else if (atom == Sopaque) 6568 result = OPAQUEP(object) ? T : NIL; 6569 } 6570 else if (CONSP(type)) { 6571 if (OBJECT_TYPE(object) == LispStruct_t && 6572 SYMBOLP(CAR(type)) && ATOMID(CAR(type)) == Sstruct && 6573 SYMBOLP(CAR(CDR(type))) && CDR(CDR(type)) == NIL) { 6574 result = ATOMID(CAR(object->data.struc.def)) == 6575 ATOMID(CAR(CDR(type))) ? T : NIL; 6576 } 6577 } 6578 else if (type == NIL) 6579 result = object == NIL ? T : NIL; 6580 else if (type == T) 6581 result = object == T ? T : NIL; 6582 if (result == NULL) 6583 LispDestroy("%s: bad type specification %s", 6584 STRFUN(builtin), STROBJ(type)); 6585 6586 return (result); 6587} 6588 6589LispObj * 6590Lisp_Union(LispBuiltin *builtin) 6591/* 6592 union list1 list2 &key test test-not key 6593 */ 6594{ 6595 return (LispListSet(builtin, UNION)); 6596} 6597 6598LispObj * 6599Lisp_Nunion(LispBuiltin *builtin) 6600/* 6601 nunion list1 list2 &key test test-not key 6602 */ 6603{ 6604 return (LispListSet(builtin, NUNION)); 6605} 6606 6607LispObj * 6608Lisp_Unless(LispBuiltin *builtin) 6609/* 6610 unless test &rest body 6611 */ 6612{ 6613 LispObj *result, *test, *body; 6614 6615 body = ARGUMENT(1); 6616 test = ARGUMENT(0); 6617 6618 result = NIL; 6619 test = EVAL(test); 6620 RETURN_COUNT = 0; 6621 if (test == NIL) { 6622 for (; CONSP(body); body = CDR(body)) 6623 result = EVAL(CAR(body)); 6624 } 6625 6626 return (result); 6627} 6628 6629/* 6630 * ext::until 6631 */ 6632LispObj * 6633Lisp_Until(LispBuiltin *builtin) 6634/* 6635 until test &rest body 6636 */ 6637{ 6638 LispObj *result, *test, *body, *prog; 6639 6640 body = ARGUMENT(1); 6641 test = ARGUMENT(0); 6642 6643 result = NIL; 6644 for (;;) { 6645 if ((result = EVAL(test)) == NIL) { 6646 for (prog = body; CONSP(prog); prog = CDR(prog)) 6647 (void)EVAL(CAR(prog)); 6648 } 6649 else 6650 break; 6651 } 6652 6653 return (result); 6654} 6655 6656LispObj * 6657Lisp_UnwindProtect(LispBuiltin *builtin) 6658/* 6659 unwind-protect protect &rest cleanup 6660 */ 6661{ 6662 LispObj *result, **presult = &result; 6663 int did_jump, *pdid_jump = &did_jump, destroyed; 6664 LispBlock *block; 6665 6666 LispObj *protect, *cleanup, **pcleanup = &cleanup; 6667 6668 cleanup = ARGUMENT(1); 6669 protect = ARGUMENT(0); 6670 6671 /* run protected code */ 6672 *presult = NIL; 6673 *pdid_jump = 1; 6674 block = LispBeginBlock(NIL, LispBlockProtect); 6675 if (setjmp(block->jmp) == 0) { 6676 *presult = EVAL(protect); 6677 *pdid_jump = 0; 6678 } 6679 LispEndBlock(block); 6680 if (!lisp__data.destroyed && *pdid_jump) 6681 *presult = lisp__data.block.block_ret; 6682 6683 destroyed = lisp__data.destroyed; 6684 lisp__data.destroyed = 0; 6685 6686 /* run cleanup, unprotected code */ 6687 if (CONSP(*pcleanup)) 6688 for (; CONSP(cleanup); cleanup = CDR(cleanup)) 6689 (void)EVAL(CAR(cleanup)); 6690 6691 if (destroyed) { 6692 /* in case there is another unwind-protect */ 6693 LispBlockUnwind(NULL); 6694 /* if not, just return to the toplevel */ 6695 lisp__data.destroyed = 1; 6696 LispDestroy("."); 6697 } 6698 6699 return (result); 6700} 6701 6702static LispObj * 6703LispValuesList(LispBuiltin *builtin, int check_list) 6704{ 6705 long i, count; 6706 LispObj *result; 6707 6708 LispObj *list; 6709 6710 list = ARGUMENT(0); 6711 6712 count = LispLength(list) - 1; 6713 6714 if (count >= 0) { 6715 result = CAR(list); 6716 if ((RETURN_CHECK(count)) != count) 6717 LispDestroy("%s: too many values", STRFUN(builtin)); 6718 RETURN_COUNT = count; 6719 for (i = 0, list = CDR(list); count && CONSP(list); 6720 count--, i++, list = CDR(list)) 6721 RETURN(i) = CAR(list); 6722 if (check_list) { 6723 CHECK_LIST(list); 6724 } 6725 } 6726 else { 6727 RETURN_COUNT = -1; 6728 result = NIL; 6729 } 6730 6731 return (result); 6732} 6733 6734LispObj * 6735Lisp_Values(LispBuiltin *builtin) 6736/* 6737 values &rest objects 6738 */ 6739{ 6740 return (LispValuesList(builtin, 0)); 6741} 6742 6743LispObj * 6744Lisp_ValuesList(LispBuiltin *builtin) 6745/* 6746 values-list list 6747 */ 6748{ 6749 return (LispValuesList(builtin, 1)); 6750} 6751 6752LispObj * 6753Lisp_Vector(LispBuiltin *builtin) 6754/* 6755 vector &rest objects 6756 */ 6757{ 6758 LispObj *objects; 6759 6760 objects = ARGUMENT(0); 6761 6762 return (VECTOR(objects)); 6763} 6764 6765LispObj * 6766Lisp_When(LispBuiltin *builtin) 6767/* 6768 when test &rest body 6769 */ 6770{ 6771 LispObj *result, *test, *body; 6772 6773 body = ARGUMENT(1); 6774 test = ARGUMENT(0); 6775 6776 result = NIL; 6777 test = EVAL(test); 6778 RETURN_COUNT = 0; 6779 if (test != NIL) { 6780 for (; CONSP(body); body = CDR(body)) 6781 result = EVAL(CAR(body)); 6782 } 6783 6784 return (result); 6785} 6786 6787/* 6788 * ext::while 6789 */ 6790LispObj * 6791Lisp_While(LispBuiltin *builtin) 6792/* 6793 while test &rest body 6794 */ 6795{ 6796 LispObj *test, *body, *prog; 6797 6798 body = ARGUMENT(1); 6799 test = ARGUMENT(0); 6800 6801 for (;;) { 6802 if (EVAL(test) != NIL) { 6803 for (prog = body; CONSP(prog); prog = CDR(prog)) 6804 (void)EVAL(CAR(prog)); 6805 } 6806 else 6807 break; 6808 } 6809 6810 return (NIL); 6811} 6812 6813/* 6814 * ext::unsetenv 6815 */ 6816LispObj * 6817Lisp_Unsetenv(LispBuiltin *builtin) 6818/* 6819 unsetenv name 6820 */ 6821{ 6822 char *name; 6823 6824 LispObj *oname; 6825 6826 oname = ARGUMENT(0); 6827 6828 CHECK_STRING(oname); 6829 name = THESTR(oname); 6830 6831 unsetenv(name); 6832 6833 return (NIL); 6834} 6835 6836LispObj * 6837Lisp_XeditEltStore(LispBuiltin *builtin) 6838/* 6839 lisp::elt-store sequence index value 6840 */ 6841{ 6842 int length, offset; 6843 6844 LispObj *sequence, *oindex, *value; 6845 6846 value = ARGUMENT(2); 6847 oindex = ARGUMENT(1); 6848 sequence = ARGUMENT(0); 6849 6850 CHECK_INDEX(oindex); 6851 offset = FIXNUM_VALUE(oindex); 6852 length = LispLength(sequence); 6853 6854 if (offset >= length) 6855 LispDestroy("%s: index %d too large for sequence length %d", 6856 STRFUN(builtin), offset, length); 6857 6858 if (STRINGP(sequence)) { 6859 int ch; 6860 6861 CHECK_STRING_WRITABLE(sequence); 6862 CHECK_SCHAR(value); 6863 ch = SCHAR_VALUE(value); 6864 if (ch < 0 || ch > 255) 6865 LispDestroy("%s: cannot represent character %d", 6866 STRFUN(builtin), ch); 6867 THESTR(sequence)[offset] = ch; 6868 } 6869 else { 6870 if (ARRAYP(sequence)) 6871 sequence = sequence->data.array.list; 6872 6873 for (; offset > 0; offset--, sequence = CDR(sequence)) 6874 ; 6875 RPLACA(sequence, value); 6876 } 6877 6878 return (value); 6879} 6880 6881LispObj * 6882Lisp_XeditPut(LispBuiltin *builtin) 6883/* 6884 lisp::put symbol indicator value 6885 */ 6886{ 6887 LispObj *symbol, *indicator, *value; 6888 6889 value = ARGUMENT(2); 6890 indicator = ARGUMENT(1); 6891 symbol = ARGUMENT(0); 6892 6893 CHECK_SYMBOL(symbol); 6894 6895 return (CAR(LispPutAtomProperty(symbol->data.atom, indicator, value))); 6896} 6897 6898LispObj * 6899Lisp_XeditSetSymbolPlist(LispBuiltin *builtin) 6900/* 6901 lisp::set-symbol-plist symbol list 6902 */ 6903{ 6904 LispObj *symbol, *list; 6905 6906 list = ARGUMENT(1); 6907 symbol = ARGUMENT(0); 6908 6909 CHECK_SYMBOL(symbol); 6910 6911 return (LispReplaceAtomPropertyList(symbol->data.atom, list)); 6912} 6913 6914LispObj * 6915Lisp_XeditVectorStore(LispBuiltin *builtin) 6916/* 6917 lisp::vector-store array &rest values 6918 */ 6919{ 6920 LispObj *value, *list, *object; 6921 long rank, count, sequence, offset, accum; 6922 6923 LispObj *array, *values; 6924 6925 values = ARGUMENT(1); 6926 array = ARGUMENT(0); 6927 6928 /* check for errors */ 6929 for (rank = 0, list = values; 6930 CONSP(list) && CONSP(CDR(list)); 6931 list = CDR(list), rank++) { 6932 CHECK_INDEX(CAR(values)); 6933 } 6934 6935 if (rank == 0) 6936 LispDestroy("%s: too few subscripts", STRFUN(builtin)); 6937 value = CAR(list); 6938 6939 if (STRINGP(array) && rank == 1) { 6940 long ch; 6941 long length = STRLEN(array); 6942 long offset = FIXNUM_VALUE(CAR(values)); 6943 6944 CHECK_SCHAR(value); 6945 CHECK_STRING_WRITABLE(array); 6946 ch = SCHAR_VALUE(value); 6947 if (offset >= length) 6948 LispDestroy("%s: index %ld too large for sequence length %ld", 6949 STRFUN(builtin), offset, length); 6950 6951 if (ch < 0 || ch > 255) 6952 LispDestroy("%s: cannot represent character %ld", 6953 STRFUN(builtin), ch); 6954 THESTR(array)[offset] = ch; 6955 6956 return (value); 6957 } 6958 6959 CHECK_ARRAY(array); 6960 if (rank != array->data.array.rank) 6961 LispDestroy("%s: too %s subscripts", STRFUN(builtin), 6962 rank < array->data.array.rank ? "few" : "many"); 6963 6964 for (list = values, object = array->data.array.dim; 6965 CONSP(CDR(list)); 6966 list = CDR(list), object = CDR(object)) { 6967 if (FIXNUM_VALUE(CAR(list)) >= FIXNUM_VALUE(CAR(object))) 6968 LispDestroy("%s: %ld is out of range, index %ld", 6969 STRFUN(builtin), 6970 FIXNUM_VALUE(CAR(list)), 6971 FIXNUM_VALUE(CAR(object))); 6972 } 6973 6974 for (count = sequence = 0, list = values; 6975 CONSP(CDR(list)); 6976 list = CDR(list), sequence++) { 6977 for (offset = 0, object = array->data.array.dim; 6978 offset < sequence; object = CDR(object), offset++) 6979 ; 6980 for (accum = 1, object = CDR(object); CONSP(object); 6981 object = CDR(object)) 6982 accum *= FIXNUM_VALUE(CAR(object)); 6983 count += accum * FIXNUM_VALUE(CAR(list)); 6984 } 6985 6986 for (array = array->data.array.list; count > 0; array = CDR(array), count--) 6987 ; 6988 6989 RPLACA(array, value); 6990 6991 return (value); 6992} 6993 6994LispObj * 6995Lisp_XeditDocumentationStore(LispBuiltin *builtin) 6996/* 6997 lisp::documentation-store symbol type string 6998 */ 6999{ 7000 LispDocType_t doc_type; 7001 7002 LispObj *symbol, *type, *string; 7003 7004 string = ARGUMENT(2); 7005 type = ARGUMENT(1); 7006 symbol = ARGUMENT(0); 7007 7008 CHECK_SYMBOL(symbol); 7009 7010 /* type is checked in LispDocumentationType() */ 7011 doc_type = LispDocumentationType(builtin, type); 7012 7013 if (string == NIL) 7014 /* allow explicitly releasing memory used for documentation */ 7015 LispRemDocumentation(symbol, doc_type); 7016 else { 7017 CHECK_STRING(string); 7018 LispAddDocumentation(symbol, string, doc_type); 7019 } 7020 7021 return (string); 7022} 7023