home *** CD-ROM | disk | FTP | other *** search
- /* lispcmds.c -- Lots of standard Lisp functions
- Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
-
- This file is part of Jade.
-
- Jade is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- Jade is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Jade; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "jade.h"
- #include "jade_protos.h"
-
- #include <string.h>
-
- _PR void lispcmds_init(void);
-
- _PR VALUE sym_load_path;
- VALUE sym_load_path, sym_lisp_lib_dir;
- /*
- ::doc:load_path::
- A list of directory names. When `load' opens a lisp-file it searches each
- directory named in this list in turn until the file is found or the list
- is exhausted.
- ::end::
- ::doc:lisp_lib_dir::
- The name of the directory in which the standard lisp files live.
- ::end::
- */
-
- _PR VALUE cmd_quote(VALUE);
- DEFUN("quote", cmd_quote, subr_quote, (VALUE args), V_SF, DOC_quote) /*
- ::doc:quote::
- (quote ARG) <SPECIAL-FORM>
- 'ARG
- Returns ARG.
- ::end:: */
- {
- if(CONSP(args))
- return(VCAR(args));
- return(NULL);
- }
-
- _PR VALUE cmd_function(VALUE);
- DEFUN("function", cmd_function, subr_function, (VALUE args), V_SF, DOC_function) /*
- ::doc:function::
- (function ARG) <SPECIAL-FORM>
- #'ARG
- Normally the same as `quote'. When being compiled, if ARG is not a symbol
- it causes ARG to be compiled as a lambda expression.
- ::end:: */
- {
- if(CONSP(args))
- return(VCAR(args));
- return(NULL);
- }
-
- _PR VALUE cmd_defmacro(VALUE);
- DEFUN("defmacro", cmd_defmacro, subr_defmacro, (VALUE args), V_SF, DOC_defmacro) /*
- ::doc:defmacro::
- (defmacro NAME LAMBDA-LIST [DOC-STRING] BODY...)
- Defines a macro called NAME with argument spec. LAMBDA-LIST, documentation
- DOC-STRING (optional) and body BODY. The actual function value is
- `(macro lambda LAMBDA-LIST [DOC-STRING] BODY...)'
- Macros are called with their arguments un-evaluated, they are expected to
- return a form which will be executed to provide the result of the expression.
-
- A pathetic example could be,
- (defmacro foo (x) (list 'cons nil x))
- => foo
- (foo 'bar)
- => (nil . bar)
- This makes `(foo X)' a pseudonym for `(cons nil X)'.
-
- Note that macros are expanded at *compile-time* (unless, of course, the Lisp
- code has not been compiled).
- ::end:: */
- {
- if(CONSP(args))
- return(cmd_fset(VCAR(args), cmd_cons(sym_macro, cmd_cons(sym_lambda, VCDR(args)))));
- else
- return(NULL);
- }
-
- _PR VALUE cmd_defun(VALUE);
- DEFUN("defun", cmd_defun, subr_defun, (VALUE args), V_SF, DOC_defun) /*
- ::doc:defun::
- (defun NAME LAMBDA-LIST [DOC-STRING] BODY...)
- Defines a function called NAME with argument specification LAMBDA-LIST,
- documentation DOC-STRING (optional) and body BODY. The actual function
- value is,
- `(lambda LAMBDA-LIST [DOC-STRING] BODY...)'
- ::end:: */
- {
- if(CONSP(args))
- return(cmd_fset(VCAR(args), cmd_cons(sym_lambda, VCDR(args))));
- else
- return(NULL);
- }
-
- _PR VALUE cmd_car(VALUE);
- DEFUN("car", cmd_car, subr_car, (VALUE cons), V_Subr1, DOC_car) /*
- ::doc:car::
- (car CONS-CELL)
- Returns the value stored in the car slot of CONS-CELL, or nil if CONS-CELL
- is nil.
- ::end:: */
- {
- if(CONSP(cons))
- return(VCAR(cons));
- return(sym_nil);
- }
- _PR VALUE cmd_cdr(VALUE);
- DEFUN("cdr", cmd_cdr, subr_cdr, (VALUE cons), V_Subr1, DOC_cdr) /*
- ::doc:cdr::
- (cdr CONS-CELL)
- Returns the value stored in the cdr slot of CONS-CELL, or nil if CONS-CELL
- is nil.
- ::end:: */
- {
- if(CONSP(cons))
- return(VCDR(cons));
- return(sym_nil);
- }
-
- _PR VALUE cmd_list(VALUE);
- DEFUN("list", cmd_list, subr_list, (VALUE args), V_SubrN, DOC_list) /*
- ::doc:list::
- (list ARGS...)
- Returns a new list with members ARGS...
- ::end:: */
- {
- return(args);
- }
-
- _PR VALUE cmd_copy_list(VALUE);
- DEFUN("copy-list", cmd_copy_list, subr_copy_list, (VALUE list), V_Subr1, DOC_copy_list) /*
- ::doc:copy_list::
- (copy-list LIST)
- Returns a new list which is identical to LIST except that the cons cells
- which it is made from are different, all elements are shared however.
- ::end:: */
- {
- VALUE res = sym_nil;
- VALUE *last = &res;
- while(CONSP(list))
- {
- if(!(*last = cmd_cons(VCAR(list), sym_nil)))
- return(NULL);
- last = &VCDR(*last);
- list = VCDR(list);
- }
- return(res);
- }
-
- _PR VALUE cmd_make_list(VALUE, VALUE);
- DEFUN("make-list", cmd_make_list, subr_make_list, (VALUE len, VALUE init), V_Subr2, DOC_make_list) /*
- ::doc:make_list::
- (make-list LENGTH [INITIAL-VALUE])
- Returns a new list with LENGTH members, each of which is initialised to
- INITIAL-VALUE, or nil.
- ::end:: */
- {
- int i;
- VALUE res = sym_nil;
- VALUE *last;
- DECLARE1(len, NUMBERP);
- last = &res;
- for(i = 0; i < VNUM(len); i++)
- {
- if(!(*last = cmd_cons(init, sym_nil)))
- return(NULL);
- last = &VCDR(*last);
- }
- return(res);
- }
-
- _PR VALUE cmd_append(VALUE);
- DEFUN("append", cmd_append, subr_append, (VALUE args), V_SubrN, DOC_append) /*
- ::doc:append::
- (append LISTS...)
- Non-destructively concatenates each of it's argument LISTS... into one
- new list which is returned.
- ::end:: */
- {
- VALUE res = sym_nil;
- VALUE *resend = &res;
- while(CONSP(args))
- {
- if(CONSP(VCAR(args)))
- *resend = copylist(VCONS(args)->cn_Car);
- else
- *resend = VCAR(args);
- while(CONSP(*resend))
- resend = &(VCDR(*resend));
- args = VCDR(args);
- }
- return(res);
- }
-
- _PR VALUE cmd_nconc(VALUE);
- DEFUN("nconc", cmd_nconc, subr_nconc, (VALUE args), V_SubrN, DOC_nconc) /*
- ::doc:nconc::
- (nconc LISTS... )
- Destructively concatenates each of it's argument LISTS... into one new
- list. Every LIST but the last is modified so that it's last cdr points
- to the beginning of the next list. Returns the new list.
- ::end:: */
- {
- VALUE res = sym_nil;
- VALUE *resend = &res;
- while(CONSP(args))
- {
- VALUE tmp = VCAR(args);
- if(CONSP(tmp))
- {
- *resend = tmp;
- while(CONSP(VCDR(tmp)))
- tmp = VCDR(tmp);
- resend = &VCDR(tmp);
- }
- args = VCDR(args);
- }
- return(res);
- }
-
- _PR VALUE cmd_rplaca(VALUE, VALUE);
- DEFUN("rplaca", cmd_rplaca, subr_rplaca, (VALUE cons, VALUE car), V_Subr2, DOC_rplaca) /*
- ::doc:rplaca::
- (rplaca CONS-CELL NEW-CAR)
- Sets the value of the car slot in CONS-CELL to NEW-CAR. Returns the new
- value.
- ::end:: */
- {
- DECLARE1(cons, CONSP);
- VCAR(cons) = car;
- return(car);
- }
- _PR VALUE cmd_rplacd(VALUE, VALUE);
- DEFUN("rplacd", cmd_rplacd, subr_rplacd, (VALUE cons, VALUE cdr), V_Subr2, DOC_rplacd) /*
- ::doc:rplacd::
- (rplacd CONS-CELL NEW-CDR)
- Sets the value of the cdr slot in CONS-CELL to NEW-CAR. Returns the new
- value.
- ::end:: */
- {
- DECLARE1(cons, CONSP);
- VCDR(cons) = cdr;
- return(cdr);
- }
-
- _PR VALUE cmd_reverse(VALUE);
- DEFUN("reverse", cmd_reverse, subr_reverse, (VALUE head), V_Subr1, DOC_reverse) /*
- ::doc:reverse::
- (reverse LIST)
- Returns a new list which is a copy of LIST except that the members are in
- reverse order.
- ::end:: */
- {
- VALUE res = sym_nil;
- while(CONSP(head))
- {
- VALUE new;
- if(!(new = cmd_cons(VCAR(head), res)))
- return(NULL);
- head = VCDR(head);
- }
- return(res);
- }
-
- _PR VALUE cmd_nreverse(VALUE);
- DEFUN("nreverse", cmd_nreverse, subr_nreverse, (VALUE head), V_Subr1, DOC_nreverse) /*
- ::doc:nreverse::
- (nreverse LIST)
- Returns LIST altered so that it's members are in reverse order to what they
- were. This function is destructive towards it's argument.
- ::end:: */
- {
- VALUE res = sym_nil;
- VALUE nxt;
- if(!CONSP(head))
- return(sym_nil);
- do {
- if(CONSP(VCDR(head)))
- nxt = VCDR(head);
- else
- nxt = NULL;
- VCDR(head) = res;
- res = head;
- } while((head = nxt));
- return(res);
- }
-
- _PR VALUE cmd_assoc(VALUE, VALUE);
- DEFUN("assoc", cmd_assoc, subr_assoc, (VALUE elt, VALUE list), V_Subr2, DOC_assoc) /*
- ::doc:assoc::
- (assoc ELT ASSOC-LIST)
- Searches ASSOC-LIST for a list whose first element is ELT. `assoc' uses
- `equal' to compare elements. Returns the sub-list starting from the first
- matching association.
- ::end:: */
- {
- while(CONSP(list))
- {
- VALUE car = VCAR(list);
- if(CONSP(car) && (!valuecmp(elt, VCAR(car))))
- return(car);
- list = VCDR(list);
- }
- return(sym_nil);
- }
- _PR VALUE cmd_assq(VALUE, VALUE);
- DEFUN("assq", cmd_assq, subr_assq, (VALUE elt, VALUE list), V_Subr2, DOC_assq) /*
- ::doc:assq::
- (assq ELT ASSOC-LIST)
- Searches ASSOC-LIST for a list whose first element is ELT. `assq' uses `eq'
- to compare elements. Returns the sub-list starting from the first matching
- association.
- ::end:: */
- {
- while(CONSP(list))
- {
- VALUE car = VCAR(list);
- if(CONSP(car) && (elt == VCAR(car)))
- return(car);
- list = VCDR(list);
- }
- return(sym_nil);
- }
-
- _PR VALUE cmd_nth(VALUE, VALUE);
- DEFUN("nth", cmd_nth, subr_nth, (VALUE index, VALUE list), V_Subr2, DOC_nth) /*
- ::doc:nth::
- (nth INDEX LIST)
- Returns the INDEXth element of LIST. The first element has an INDEX of zero.
- ::end:: */
- {
- int i;
- DECLARE1(index, NUMBERP);
- i = VNUM(index);
- while(i && CONSP(list))
- {
- list = VCDR(list);
- i--;
- }
- if((!i) && CONSP(list))
- return(VCAR(list));
- return(sym_nil);
- }
-
- _PR VALUE cmd_nthcdr(VALUE index, VALUE list);
- DEFUN("nthcdr", cmd_nthcdr, subr_nthcdr, (VALUE index, VALUE list), V_Subr2, DOC_nthcdr) /*
- ::doc:nthcdr::
- (nthcdr INDEX LIST)
- Returns the INDEXth cdr of LIST. The first is INDEX zero.
- ::end:: */
- {
- int i;
- DECLARE1(index, NUMBERP);
- i = VNUM(index);
- while(i && CONSP(list))
- {
- list = VCDR(list);
- i--;
- }
- if(!i)
- return(list);
- return(sym_nil);
- }
-
- _PR VALUE cmd_last(VALUE);
- DEFUN("last", cmd_last, subr_last, (VALUE list), V_Subr1, DOC_last) /*
- ::doc:last::
- (last LIST)
- Returns the last element of LIST.
- ::end:: */
- {
- if(CONSP(list))
- {
- while(CONSP(VCDR(list)))
- list = VCDR(list);
- return(list);
- }
- return(sym_nil);
- }
-
- _PR VALUE cmd_mapcar(VALUE, VALUE);
- DEFUN("mapcar", cmd_mapcar, subr_mapcar, (VALUE fun, VALUE list), V_Subr2, DOC_mapcar) /*
- ::doc:mapcar::
- (mapcar FUNCTION LIST)
- Calls FUNCTION-NAME with each element of LIST as an argument in turn and
- returns a new list constructed from the results, ie,
- (mapcar (function (lambda (x) (1+ x))) '(1 2 3))
- => (2 3 4)
- ::end:: */
- {
- VALUE res = sym_nil;
- VALUE *last = &res;
- GCVAL gcv_list, gcv_argv, gcv_res;
- VALUE argv = cmd_cons(fun, cmd_cons(sym_nil, sym_nil));
- if(argv)
- {
- PUSHGC(gcv_res, res);
- PUSHGC(gcv_argv, argv);
- PUSHGC(gcv_list, list);
- while(res && CONSP(list))
- {
- if(!(*last = cmd_cons(sym_nil, sym_nil)))
- return(NULL);
- VCAR(VCDR(argv)) = VCAR(list);
- if(!(VCAR(*last) = cmd_funcall(argv)))
- res = NULL;
- else
- {
- last = &VCDR(*last);
- list = VCDR(list);
- }
- }
- POPGC; POPGC; POPGC;
- }
- return(res);
- }
-
- _PR VALUE cmd_mapc(VALUE, VALUE);
- DEFUN("mapc", cmd_mapc, subr_mapc, (VALUE fun, VALUE list), V_Subr2, DOC_mapc) /*
- ::doc:mapc::
- (mapc FUNCTION LIST)
- Applies FUNCTION to each element in LIST, discards the results.
- ::end:: */
- {
- VALUE argv, res = sym_nil;
- GCVAL gcv_argv, gcv_list;
- if(!(argv = cmd_cons(fun, cmd_cons(sym_nil, sym_nil))))
- return(NULL);
- PUSHGC(gcv_argv, argv);
- PUSHGC(gcv_list, list);
- while(res && CONSP(list))
- {
- VCAR(VCDR(argv)) = VCAR(list);
- res = cmd_funcall(argv);
- list = VCDR(list);
- }
- POPGC; POPGC;
- return(res);
- }
-
- _PR VALUE cmd_member(VALUE, VALUE);
- DEFUN("member", cmd_member, subr_member, (VALUE elt, VALUE list), V_Subr2, DOC_member) /*
- ::doc:member::
- (member ELT LIST)
- If ELT is a member of list LIST then return the tail of the list starting
- from the matched ELT, ie,
- (member 1 '(2 1 3))
- => (1 3)
- `member' uses `equal' to compare atoms.
- ::end:: */
- {
- while(CONSP(list))
- {
- if(!valuecmp(elt, VCAR(list)))
- return(list);
- list = VCDR(list);
- }
- return(sym_nil);
- }
- _PR VALUE cmd_memq(VALUE, VALUE);
- DEFUN("memq", cmd_memq, subr_memq, (VALUE elt, VALUE list), V_Subr2, DOC_memq) /*
- ::doc:memq::
- (memq ELT LIST)
- If ELT is a member of list LIST then return the tail of the list starting
- from the matched ELT, ie,
- (memq 1 '(2 1 3))
- => (1 3)
- `memq' uses `eq' to compare atoms.
- ::end:: */
- {
- while(CONSP(list))
- {
- if(elt == VCAR(list))
- return(list);
- list = VCDR(list);
- }
- return(sym_nil);
- }
-
- _PR VALUE cmd_delete(VALUE, VALUE);
- DEFUN("delete", cmd_delete, subr_delete, (VALUE elt, VALUE list), V_Subr2, DOC_delete) /*
- ::doc:delete::
- (delete ELT LIST)
- Returns LIST with any members `equal' to ELT destructively removed.
- ::end:: */
- {
- VALUE *head = &list;
- while(CONSP(*head))
- {
- if(!valuecmp(elt, VCAR(*head)))
- *head = VCDR(*head);
- else
- head = &VCDR(*head);
- }
- return(list);
- }
- _PR VALUE cmd_delq(VALUE, VALUE);
- DEFUN("delq", cmd_delq, subr_delq, (VALUE elt, VALUE list), V_Subr2, DOC_delq) /*
- ::doc:delq::
- (delq ELT LIST)
- Returns LIST with any members `eq' to ELT destructively removed.
- ::end:: */
- {
- VALUE *head = &list;
- while(CONSP(*head))
- {
- if(elt == VCAR(*head))
- *head = VCDR(*head);
- else
- head = &VCDR(*head);
- }
- return(list);
- }
-
- _PR VALUE cmd_delete_if(VALUE, VALUE);
- DEFUN("delete-if", cmd_delete_if, subr_delete_if, (VALUE pred, VALUE list), V_Subr2, DOC_delete_if) /*
- ::doc:delete_if::
- (delete-if FUNCTION LIST)
- Similar to `delete' except that a predicate function, FUNCTION-NAME, is
- used to decide which elements to delete (remove destructively).
- `delete-if' deletes an element if FUNCTION-NAME returns non-nil when
- applied to that element, ie,
- (delete-if '(lambda (x) (= x 1)) '(1 2 3 4 1 2))
- => (2 3 4 2)
- ::end:: */
- {
- VALUE *head = &list;
- VALUE tmp;
- while(CONSP(*head))
- {
- if(!(tmp = calllisp1(pred, VCAR(*head))))
- return(NULL);
- if(!NILP(tmp))
- *head = VCDR(*head);
- else
- head = &VCDR(*head);
- }
- return(list);
- }
- _PR VALUE cmd_delete_if_not(VALUE, VALUE);
- DEFUN("delete-if-not", cmd_delete_if_not, subr_delete_if_not, (VALUE pred, VALUE list), V_Subr2, DOC_delete_if_not) /*
- ::doc:delete_if_not::
- (delete-if-not FUNCTION LIST)
- Similar to `delete' except that a predicate function, FUNCTION-NAME, is
- used to decide which elements to delete (remove destructively).
- `delete-if-not' deletes an element if FUNCTION-NAME returns nil when
- applied to that element, ie,
- (delete-if-not '(lambda (x) (= x 1)) '(1 2 3 4 1 2))
- => (1 1)
- ::end:: */
- {
- VALUE *head = &list;
- VALUE tmp;
- while(CONSP(*head))
- {
- if(!(tmp = calllisp1(pred, VCAR(*head))))
- return(NULL);
- if(NILP(tmp))
- *head = VCDR(*head);
- else
- head = &VCDR(*head);
- }
- return(list);
- }
-
- _PR VALUE cmd_vector(VALUE);
- DEFUN("vector", cmd_vector, subr_vector, (VALUE args), V_SubrN, DOC_vector) /*
- ::doc:vector::
- (vector ARGS...)
- Returns a new vector with ARGS... as its elements.
- ::end:: */
- {
- VALUE res = newvector(listlen(args));
- if(res)
- {
- int i = 0;
- while(CONSP(args))
- {
- VVECT(res)->vc_Array[i] = VCAR(args);
- args = VCDR(args);
- i++;
- }
- }
- return(res);
- }
-
- _PR VALUE cmd_make_vector(VALUE, VALUE);
- DEFUN("make-vector", cmd_make_vector, subr_make_vector, (VALUE size, VALUE init), V_Subr2, DOC_make_vector) /*
- ::doc:make_vector::
- (make-vector SIZE [INITIAL-VALUE])
- Creates a new vector of size SIZE. If INITIAL-VALUE is provided each element
- will be set to that value, else they will all be nil.
- ::end:: */
- {
- int len;
- VALUE res;
- DECLARE1(size, NUMBERP);
- len = VNUM(size);
- res = newvector(len);
- if(res)
- {
- int i;
- for(i = 0; i < len; i++)
- VVECT(res)->vc_Array[i] = init;
- }
- return(res);
- }
-
- _PR VALUE cmd_aset(VALUE, VALUE, VALUE);
- DEFUN("aset", cmd_aset, subr_aset, (VALUE seq, VALUE index, VALUE new), V_Subr3, DOC_aset) /*
- ::doc:aset::
- (aset SEQUENCE INDEX NEW-VALUE)
- Sets element number INDEX (a positive integer) of SEQUENCE (can be a list,
- vector or string) to NEW-VALUE, returning NEW-VALUE. Note that strings
- can only contain characters (ie, integers).
- ::end:: */
- {
- DECLARE2(index, NUMBERP);
- switch(VTYPE(seq))
- {
- case V_StaticString:
- case V_String:
- if(VNUM(index) < strlen(VSTR(seq)))
- {
- DECLARE3(new, NUMBERP);
- VSTR(seq)[VNUM(index)] = (u_char)VCHAR(new);
- return(new);
- }
- break;
- case V_Vector:
- if(VNUM(index) < VVECT(seq)->vc_Size)
- {
- VVECT(seq)->vc_Array[VNUM(index)] = new;
- return(new);
- }
- break;
- default:
- cmd_signal(sym_bad_arg, list_2(seq, newnumber(1)));
- return(NULL);
- }
- return(sym_nil);
- }
-
- _PR VALUE cmd_aref(VALUE, VALUE);
- DEFUN("aref", cmd_aref, subr_aref, (VALUE seq, VALUE index), V_Subr2, DOC_aref) /*
- ::doc:aref::
- (aref SEQUENCE INDEX)
- Returns the INDEXth (a non-negative integer) element of SEQUENCE, which
- can be a list, vector or string. INDEX starts at zero.
- ::end:: */
- {
- VALUE res = sym_nil;
- DECLARE2(index, NUMBERP);
- switch(VTYPE(seq))
- {
- case V_StaticString:
- case V_String:
- if(VNUM(index) < strlen(VSTR(seq)))
- res = newnumber(VSTR(seq)[VNUM(index)]);
- break;
- case V_Vector:
- if(VNUM(index) < VVECT(seq)->vc_Size)
- res = VVECT(seq)->vc_Array[VNUM(index)];
- break;
- default:
- cmd_signal(sym_bad_arg, list_2(seq, newnumber(1)));
- res = NULL;
- }
- return(res);
- }
-
- _PR VALUE cmd_make_string(VALUE, VALUE);
- DEFUN("make-string", cmd_make_string, subr_make_string, (VALUE len, VALUE init), V_Subr2, DOC_make_string) /*
- ::doc:make_string::
- (make-string LENGTH [INITIAL-VALUE])
- Returns a new string of length LENGTH, each character is initialised to
- INITIAL-VALUE, or to space if INITIAL-VALUE is not given.
- ::end:: */
- {
- VALUE res;
- DECLARE1(len, NUMBERP);
- res = valstralloc(VNUM(len) + 1);
- if(res)
- {
- memset(VSTR(res), NUMBERP(init) ? (u_char)VCHAR(init) : ' ', VNUM(len));
- VSTR(res)[VNUM(len)] = 0;
- }
- return(res);
- }
-
- static INLINE int
- extendconcat(u_char **buf, int *bufLen, int i, int addLen)
- {
- u_char *newbuf;
- int newbuflen;
- if((i + addLen) < *bufLen)
- return(TRUE);
- newbuflen = *bufLen * 2;
- newbuf = mystralloc(newbuflen);
- if(newbuf)
- {
- memcpy(newbuf, *buf, i);
- mystrfree(*buf);
- *buf = newbuf;
- *bufLen = newbuflen;
- return(TRUE);
- }
- return(FALSE);
- }
- _PR VALUE cmd_concat(VALUE);
- DEFUN("concat", cmd_concat, subr_concat, (VALUE args), V_SubrN, DOC_concat) /*
- ::doc:concat::
- (concat ARGS...)
- Concatenates all ARGS... into a single string, each argument can be a string,
- a character or a list or vector of characters.
- ::end:: */
- {
- int buflen = 128;
- u_char *buf = mystralloc(buflen);
- if(buf)
- {
- VALUE res = NULL;
- int i = 0;
- while(CONSP(args))
- {
- VALUE arg = VCAR(args);
- switch(VTYPE(arg))
- {
- int slen, j;
- case V_StaticString:
- case V_String:
- slen = strlen(VSTR(arg));
- if(!extendconcat(&buf, &buflen, i, slen))
- goto error;
- memcpy(buf + i, VSTR(arg), slen);
- i += slen;
- break;
- case V_Char:
- if(!extendconcat(&buf, &buflen, i, 1))
- goto error;
- buf[i++] = VCHAR(arg);
- break;
- case V_Symbol:
- if(arg != sym_nil)
- break;
- /* FALL THROUGH */
- case V_Cons:
- while(CONSP(arg))
- {
- VALUE ch = VCAR(arg);
- if(VTYPEP(ch, V_Char))
- {
- if(!extendconcat(&buf, &buflen, i, 1))
- goto error;
- buf[i++] = VCHAR(ch);
- }
- arg = VCDR(arg);
- }
- break;
- case V_Vector:
- for(j = 0; j < VVECT(arg)->vc_Size; j++)
- {
- if(VTYPEP(VVECT(arg)->vc_Array[j], V_Char))
- {
- if(!extendconcat(&buf, &buflen, i, 1))
- goto error;
- buf[i++] = VCHAR(VVECT(arg)->vc_Array[j]);
- }
- }
- break;
- }
- args = VCDR(args);
- }
- res = valstrdupn(buf, i);
- if(res)
- error:
- mystrfree(buf);
- return(res);
- }
- return(NULL);
- }
-
- _PR VALUE cmd_length(VALUE);
- DEFUN("length", cmd_length, subr_length, (VALUE sequence), V_Subr1, DOC_length) /*
- ::doc:length::
- (length SEQUENCE)
- Returns the number of elements in SEQUENCE (a string, list or vector).
- ::end:: */
- {
- switch(VTYPE(sequence))
- {
- int i;
- case V_StaticString:
- case V_String:
- return(newnumber(strlen(VSTR(sequence))));
- break;
- case V_Vector:
- return(newnumber(VVECT(sequence)->vc_Size));
- break;
- case V_Cons:
- i = 0;
- while(CONSP(sequence))
- {
- sequence = VCDR(sequence);
- i++;
- }
- return(newnumber(i));
- break;
- case V_Symbol:
- if(sequence == sym_nil)
- return(newnumber(0));
- /* FALL THROUGH */
- default:
- cmd_signal(sym_bad_arg, list_2(sequence, newnumber(1)));
- return(NULL);
- }
- }
-
- _PR VALUE cmd_prog1(VALUE);
- DEFUN("prog1", cmd_prog1, subr_prog1, (VALUE args), V_SF, DOC_prog1) /*
- ::doc:prog1::
- (prog1 FORM1 FORMS... ) <SPECIAL-FORM>
- First evals FORM1 then FORMS, returns the value that FORM1 gave.
- ::end:: */
- {
- if(CONSP(args))
- {
- VALUE res;
- GCVAL gcv_args, gcv_res;
- PUSHGC(gcv_args, args);
- res = cmd_eval(VCAR(args));
- if(res)
- {
- PUSHGC(gcv_res, res);
- if(!cmd_progn(VCDR(args)))
- res = NULL;
- POPGC;
- }
- POPGC;
- return(res);
- }
- return(NULL);
- }
-
- _PR VALUE cmd_prog2(VALUE);
- DEFUN("prog2", cmd_prog2, subr_prog2, (VALUE args), V_SF, DOC_prog2) /*
- ::doc:prog2::
- (prog2 FORM1 FORM2 FORMS...) <SPECIAL-FORM>
- Evals FORM1 then FORM2 then the rest. Returns whatever FORM2 gave.
- ::end:: */
- {
- if(CONSP(args) && CONSP(VCDR(args)))
- {
- VALUE res;
- GCVAL gcv_args, gcv_res;
- PUSHGC(gcv_args, args);
- if(cmd_eval(VCAR(args)))
- {
- res = cmd_eval(VCAR(VCDR(args)));
- if(res)
- {
- PUSHGC(gcv_res, res);
- if(!cmd_progn(VCDR(VCDR(args))))
- res = NULL;
- POPGC;
- }
- }
- else
- res = NULL;
- POPGC;
- return(res);
- }
- return(NULL);
- }
-
- _PR VALUE cmd_while(VALUE);
- DEFUN("while", cmd_while, subr_while, (VALUE args), V_SF, DOC_while) /*
- ::doc:while::
- (while CONDITION FORMS... ) <SPECIAL-FORM>
- Eval CONDITION, if it is non-nil then execute FORMS and repeat the
- procedure, else return nil.
- ::end:: */
- {
- if(CONSP(args))
- {
- GCVAL gcv_args;
- VALUE cond = VCAR(args), wval, body = VCDR(args);
- PUSHGC(gcv_args, args);
- while((wval = cmd_eval(cond)) && !NILP(wval))
- {
- if(!cmd_progn(body))
- {
- wval = NULL;
- break;
- }
- }
- POPGC;
- if(!wval)
- return(NULL);
- return(sym_nil);
- }
- return(NULL);
- }
-
- _PR VALUE cmd_if(VALUE);
- DEFUN("if", cmd_if, subr_if, (VALUE args), V_SF, DOC_if) /*
- ::doc:if::
- (if CONDITION THEN-FORM [ELSE-FORMS...] ) <SPECIAL-FORM>
- Eval CONDITION, if it is non-nil then eval THEN-FORM and return it's
- result, else do an implicit progn with the ELSE-FORMS returning its value.
- ::end:: */
- {
- if(CONSP(args) && CONSP(VCDR(args)))
- {
- VALUE res;
- GCVAL gcv_args;
- PUSHGC(gcv_args, args);
- res = cmd_eval(VCAR(args));
- if(res)
- {
- if(!NILP(res))
- res = cmd_eval(VCAR(VCDR(args)));
- else
- res = cmd_progn(VCDR(VCDR(args)));
- }
- POPGC;
- return(res);
- }
- return(NULL);
- }
-
- _PR VALUE cmd_when(VALUE);
- DEFUN("when", cmd_when, subr_when, (VALUE args), V_SF, DOC_when) /*
- ::doc:when::
- (when CONDITION FORMS... ) <SPECIAL-FORM>
- Evaluates CONDITION, if it is non-nil evaluates FORMS.
- ::end:: */
- {
- VALUE res = sym_nil;
- if(CONSP(args))
- {
- GCVAL gcv_args;
- PUSHGC(gcv_args, args);
- if((res = cmd_eval(VCAR(args))) && !NILP(res))
- res = cmd_progn(VCDR(args));
- POPGC;
- }
- return(res);
- }
-
- _PR VALUE cmd_unless(VALUE);
- DEFUN("unless", cmd_unless, subr_unless, (VALUE args), V_SF, DOC_unless) /*
- ::doc:unless::
- (unless CONDITION FORMS... ) <SPECIAL-FORM>
- Evaluates CONDITION, if it is nil evaluates FORMS.
- ::end:: */
- {
- VALUE res = sym_nil;
- if(CONSP(args))
- {
- GCVAL gcv_args;
- PUSHGC(gcv_args, args);
- if((res = cmd_eval(VCAR(args))) && NILP(res))
- res = cmd_progn(VCDR(args));
- POPGC;
- }
- return(res);
- }
-
- _PR VALUE cmd_cond(VALUE);
- DEFUN("cond", cmd_cond, subr_cond, (VALUE args), V_SF, DOC_cond) /*
- ::doc:cond::
- (cond (CONDITION FORMS... ) ... ) <SPECIAL-FORM>
- Find the first CONDITION which has a value of t when eval'ed, then perform
- a progn on its associated FORMS. If there are no FORMS with the CONDITION
- then the value of the CONDITION is returned. If no CONDITION is t then
- return nil.
- An example,
- (cond
- ((stringp foo)
- (title "foo is a string"))
- ((numberp foo)
- (setq bar foo)
- (title "foo is a number"))
- (t
- (title "foo is something else...")))
- Note the use of plain `t' on it's own for the last CONDITION, this is
- like the last else in an else-if statement in C.
- ::end:: */
- {
- VALUE res = sym_nil;
- GCVAL gcv_args;
- PUSHGC(gcv_args, args);
- while(CONSP(args) && CONSP(VCAR(args)))
- {
- VALUE cndlist = VCAR(args);
- if(!(res = cmd_eval(VCAR(cndlist))))
- break;
- if(!NILP(res))
- {
- if(CONSP(VCDR(cndlist)))
- {
- if(!(res = cmd_progn(VCDR(cndlist))))
- break;
- }
- break;
- }
- args = VCDR(args);
- }
- POPGC;
- return(res);
- }
-
- _PR VALUE cmd_apply(VALUE);
- DEFUN("apply", cmd_apply, subr_apply, (VALUE args), V_SubrN, DOC_apply) /*
- ::doc:apply::
- (apply FUNCTION ARGS... ARG-LIST)
- Calls FUNCTION passing all of ARGS to it as well as all elements in ARG-LIST.
- ie,
- (apply '+ 1 2 3 '(4 5 6))
- => 21
- ::end:: */
- {
- VALUE list = sym_nil, *last;
- last = &list;
- if(CONSP(args))
- {
- while(CONSP(VCDR(args)))
- {
- if(!(*last = cmd_cons(VCAR(args), sym_nil)))
- return(NULL);
- last = &VCDR(*last);
- args = VCDR(args);
- }
- if(CONSP(VCAR(args)))
- *last = VCAR(args);
- return(cmd_funcall(list));
- }
- return(NULL);
- }
-
- _PR VALUE cmd_load(VALUE file, VALUE noerr_p, VALUE nopath_p, VALUE nosuf_p);
- DEFUN("load", cmd_load, subr_load, (VALUE file, VALUE noerr_p, VALUE nopath_p, VALUE nosuf_p), V_Subr4, DOC_load) /*
- ::doc:load::
- (load FILE [NO-ERROR-P] [NO-PATH-P] [NO-SUFFIX-P])
- Attempt to open and then read-and-eval the file of Lisp code FILE.
-
- For each directory named in the variable `load-path' tries the value of
- FILE with `.jlc' (compiled-lisp) appended to it, then with `.jl' appended
- to it, finally tries FILE without modification.
-
- If NO-ERROR-P is non-nil no error is signalled if FILE can't be found.
- If NO-PATH-P is non-nil the `load-path' variable is not used, just the value
- of FILE.
- If NO-SUFFIX-P is non-nil no suffixes are appended to FILE.
-
- If the compiled version is older than it's source code, the source code is
- loaded and a warning is displayed.
- ::end:: */
- {
- VALUE name = NULL, stream, path;
- DECLARE1(file, STRINGP);
- if(NILP(nopath_p))
- {
- if(!(path = cmd_symbol_value(sym_load_path)) || !CONSP(path))
- return(cmd_signal(sym_void_value, LIST_1(sym_load_path)));
- }
- else
- path = cmd_cons(MKSTR(""), sym_nil);
- while(!name && CONSP(path))
- {
- u_char *dir = STRINGP(VCAR(path)) ? VSTR(VCAR(path)) : (u_char *)"";
- if(NILP(nosuf_p))
- {
- bool jl_p = fileexists3(dir, VSTR(file), ".jl");
- if(fileexists3(dir, VSTR(file), ".jlc"))
- {
- name = concat3(dir, VSTR(file), ".jlc");
- if(jl_p)
- {
- VALUE tmp = concat3(dir, VSTR(file), ".jl");
- if(filemodtime(VSTR(tmp)) > filemodtime(VSTR(name)))
- {
- settitlefmt("Warning: %s newer than %s, using .jl",
- VSTR(tmp), VSTR(name));
- name = tmp;
- }
- }
- }
- else if(jl_p)
- name = concat3(dir, VSTR(file), ".jl");
- }
- if(!name && fileexists2(dir, VSTR(file)))
- name = concat2(dir, VSTR(file));
- path = VCDR(path);
- }
- if(!name)
- {
- if(NILP(noerr_p))
- return(cmd_signal(sym_file_error,
- list_2(MKSTR("Can't open lisp-file"), file)));
- else
- return(sym_nil);
- }
- if((stream = cmd_open(name, MKSTR("r"), sym_nil)) && FILEP(stream))
- {
- VALUE obj;
- int c;
- GCVAL gcv_stream;
- PUSHGC(gcv_stream, stream);
- c = streamgetc(stream);
- while((c != EOF) && (obj = readlispexp(stream, &c)))
- {
- if(!cmd_eval(obj))
- {
- POPGC;
- return(NULL);
- }
- }
- POPGC;
- return(sym_t);
- }
- return(NULL);
- }
-
- /*
- * some arithmetic commands
- */
-
- #define APPLY_OP( op ) \
- if(CONSP(args) && NUMBERP(VCAR(args))) \
- { \
- long sum = VNUM(VCAR(args)); \
- args = VCDR(args); \
- while(CONSP(args) && NUMBERP(VCAR(args))) \
- { \
- sum = sum op VNUM(VCAR(args)); \
- args = VCDR(args); \
- } \
- return(newnumber(sum)); \
- } \
- return(NULL);
-
- _PR VALUE cmd_plus(VALUE);
- DEFUN("+", cmd_plus, subr_plus, (VALUE args), V_SubrN, DOC_plus) /*
- ::doc:plus::
- (+ NUMBERS...)
- Adds all NUMBERS together.
- ::end:: */
- {
- APPLY_OP( + )
- }
-
- _PR VALUE cmd_minus(VALUE);
- DEFUN("-", cmd_minus, subr_minus, (VALUE args), V_SubrN, DOC_minus) /*
- ::doc:minus::
- (- NUMBER [NUMBERS...])
- Either returns the negation of NUMBER or the value of NUMBER minus
- NUMBERS
- ::end:: */
- {
- if(CONSP(args))
- {
- if(!CONSP(VCDR(args)))
- return(newnumber(-VNUM(VCAR(args))));
- else
- APPLY_OP( - )
- }
- return(NULL);
- }
-
- _PR VALUE cmd_product(VALUE);
- DEFUN("*", cmd_product, subr_product, (VALUE args), V_SubrN, DOC_product) /*
- ::doc:product::
- (* NUMBERS...)
- Multiplies all NUMBERS together
- ::end:: */
- {
- APPLY_OP( * )
- }
-
- _PR VALUE cmd_divide(VALUE);
- DEFUN("/", cmd_divide, subr_divide, (VALUE args), V_SubrN, DOC_divide) /*
- ::doc:divide::
- (/ NUMBERS...)
- Divides NUMBERS (in left-to-right order), ie,
- (/ 100 2
- => 10
- ::end:: */
- {
- APPLY_OP( / )
- }
-
- _PR VALUE cmd_mod(VALUE);
- DEFUN("mod", cmd_mod, subr_mod, (VALUE args), V_SubrN, DOC_mod) /*
- ::doc:mod::
- (mod NUMBERS...)
- Applies the modulus operator between each of NUMBERS.
- ::end:: */
- {
- APPLY_OP( % )
- }
-
- _PR VALUE cmd_bit_not(VALUE);
- DEFUN("bit-not", cmd_bit_not, subr_bit_not, (VALUE num), V_Subr1, DOC_bit_not) /*
- ::doc:bit_not::
- (bit-not NUMBER)
- Returns the bitwise not of NUMBER.
- ::end:: */
- {
- DECLARE1(num, NUMBERP);
- return(newnumber(~VNUM(num)));
- }
-
- _PR VALUE cmd_not(VALUE);
- DEFUN("not", cmd_not, subr_not, (VALUE arg), V_Subr1, DOC_not) /*
- ::doc:not::
- (not ARG)
- If ARG is nil returns t, else returns nil.
- ::end:: */
- {
- if(NILP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_bit_or(VALUE);
- DEFUN("bit-or", cmd_bit_or, subr_bit_or, (VALUE args), V_SubrN, DOC_bit_or) /*
- ::doc:bit_or::
- (bit-or NUMBERS...)
- Bitwise ORs all NUMBERS together.
- ::end:: */
- {
- APPLY_OP( | )
- }
-
- _PR VALUE cmd_or(VALUE);
- DEFUN("or", cmd_or, subr_or, (VALUE args), V_SF, DOC_or) /*
- ::doc:or::
- (or FORMS...) <SPECIAL-FORM>
- Evals each FORM while they return nil, returns the first non-nil result or
- nil if all FORMS return nil.
- ::end:: */
- {
- VALUE res = sym_nil;
- GCVAL gcv_args, gcv_res;
- PUSHGC(gcv_args, args);
- PUSHGC(gcv_res, res);
- while(res && CONSP(args) && NILP(res))
- {
- res = cmd_eval(VCAR(args));
- args = VCDR(args);
- }
- POPGC;
- POPGC;
- return(res);
- }
-
- _PR VALUE cmd_bit_and(VALUE);
- DEFUN("bit-and", cmd_bit_and, subr_bit_and, (VALUE args), V_SubrN, DOC_bit_and) /*
- ::doc:bit_and::
- (bit-and NUMBERS...)
- Bitwise AND all NUMBERS together.
- ::end:: */
- {
- APPLY_OP( & )
- }
-
- _PR VALUE cmd_and(VALUE);
- DEFUN("and", cmd_and, subr_and, (VALUE args), V_SF, DOC_and) /*
- ::doc:and::
- (and FORMS... ) <SPECIAL-FORM>
- Evals each FORM until one returns nil, it returns that value, or t if all
- FORMS return t.
- ::end:: */
- {
- VALUE res = sym_t;
- GCVAL gcv_args, gcv_res;
- PUSHGC(gcv_args, args);
- PUSHGC(gcv_res, res);
- while(res && CONSP(args) && !NILP(res))
- {
- res = cmd_eval(VCAR(args));
- args = VCDR(args);
- }
- POPGC;
- POPGC;
- return(res);
- }
-
- _PR VALUE cmd_equal(VALUE, VALUE);
- DEFUN("equal", cmd_equal, subr_equal, (VALUE val1, VALUE val2), V_Subr2, DOC_equal) /*
- ::doc:equal::
- (equal VALUE1 VALUE2)
- Compares VALUE1 and VALUE2, compares the actual structure of the objects not
- just whether the objects are one and the same. ie, will return t for two
- strings built from the same characters in the same order even if the strings'
- location in memory is different.
- ::end:: */
- {
- if(valuecmp(val1, val2))
- return(sym_nil);
- return(sym_t);
- }
-
- _PR VALUE cmd_eq(VALUE, VALUE);
- DEFUN("eq", cmd_eq, subr_eq, (VALUE val1, VALUE val2), V_Subr2, DOC_eq) /*
- ::doc:eq::
- (eq VALUE1 VALUE2)
- Returns t if VALUE1 and VALUE2 are one and the same object. Note that
- (eq 1 1)
- => nil
- ::end:: */
- {
- if(val1 == val2)
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_string_head_eq(VALUE, VALUE);
- DEFUN("string-head-eq", cmd_string_head_eq, subr_string_head_eq, (VALUE str1, VALUE str2), V_Subr2, DOC_string_head_eq) /*
- ::doc:string_head_eq::
- (string-head-eq STRING1 STRING2)
- Returns t if STRING2 matches the beginning of STRING1, ie,
- (string-head-eq "foobar" "foo")
- => t
- (string-head-eq "foo" "foobar")
- => nil
- ::end:: */
- {
- u_char *s1, *s2;
- DECLARE1(str1, STRINGP);
- DECLARE2(str2, STRINGP);
- s1 = VSTR(str1);
- s2 = VSTR(str2);
- while(*s1 && *s2)
- {
- if(*s1++ != *s2++)
- return(sym_nil);
- }
- if(*s1 || (*s1 == *s2))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_num_eq(VALUE num1, VALUE num2);
- DEFUN("=", cmd_num_eq, subr_num_eq, (VALUE num1, VALUE num2), V_Subr2, DOC_num_eq) /*
- ::doc:num_eq::
- (= NUMBER1 NUMBER2)
- Returns t if NUMBER1 and NUMBER2 are equal.
- ::end:: */
- {
- DECLARE1(num1, NUMBERP);
- DECLARE2(num2, NUMBERP);
- if(VNUM(num1) == VNUM(num2))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_num_noteq(VALUE num1, VALUE num2);
- DEFUN("/=", cmd_num_noteq, subr_num_noteq, (VALUE num1, VALUE num2), V_Subr2, DOC_num_noteq) /*
- ::doc:num_noteq::
- (/= NUMBER1 NUMBER2)
- Returns t if NUMBER1 and NUMBER2 are unequal.
- ::end:: */
- {
- DECLARE1(num1, NUMBERP);
- DECLARE2(num2, NUMBERP);
- if(VNUM(num1) != VNUM(num2))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_gtthan(VALUE, VALUE);
- DEFUN(">", cmd_gtthan, subr_gtthan, (VALUE arg1, VALUE arg2), V_Subr2, DOC_gtthan) /*
- ::doc:gtthan::
- (> ARG1 ARG2)
- Returns t if ARG1 is greater than ARG2. Note that this command isn't
- limited to numbers, it can do strings, positions, marks, etc as well.
- ::end:: */
- {
- if(valuecmp(arg1, arg2) > 0)
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_gethan(VALUE, VALUE);
- DEFUN(">=", cmd_gethan, subr_gethan, (VALUE arg1, VALUE arg2), V_Subr2, DOC_gethan) /*
- ::doc:gethan::
- (>= ARG1 ARG2)
- Returns t if ARG1 is greater-or-equal than ARG2. Note that this command
- isn't limited to numbers, it can do strings, positions, marks, etc as well.
- ::end:: */
- {
- if(valuecmp(arg1, arg2) >= 0)
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_ltthan(VALUE, VALUE);
- DEFUN("<", cmd_ltthan, subr_ltthan, (VALUE arg1, VALUE arg2), V_Subr2, DOC_ltthan) /*
- ::doc:ltthan::
- (< ARG1 ARG2)
- Returns t if ARG1 is less than ARG2. Note that this command isn't limited to
- numbers, it can do strings, positions, marks, etc as well.
- ::end:: */
- {
- if(valuecmp(arg1, arg2) < 0)
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_lethan(VALUE, VALUE);
- DEFUN("<=", cmd_lethan, subr_lethan, (VALUE arg1, VALUE arg2), V_Subr2, DOC_lethan) /*
- ::doc:lethan::
- (<= ARG1 ARG2)
- Returns t if ARG1 is less-or-equal than ARG2. Note that this command isn't
- limited to numbers, it can do strings, positions, marks, etc as well.
- ::end:: */
- {
- if(valuecmp(arg1, arg2) <= 0)
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_plus1(VALUE);
- DEFUN("1+", cmd_plus1, subr_plus1, (VALUE num), V_Subr1, DOC_plus1) /*
- ::doc:plus1::
- (1+ NUMBER)
- Return NUMBER plus 1.
- ::end:: */
- {
- DECLARE1(num, NUMBERP);
- return(newnumber(VNUM(num) + 1));
- }
-
- _PR VALUE cmd_sub1(VALUE);
- DEFUN("1-", cmd_sub1, subr_sub1, (VALUE num), V_Subr1, DOC_sub1) /*
- ::doc:sub1::
- (1- NUMBER)
- Return NUMBER minus 1.
- ::end:: */
- {
- DECLARE1(num, NUMBERP);
- return(newnumber(VNUM(num) - 1));
- }
-
- _PR VALUE cmd_lsh(VALUE, VALUE);
- DEFUN("lsh", cmd_lsh, subr_lsh, (VALUE num, VALUE shift), V_Subr2, DOC_lsh) /*
- ::doc:lsh::
- (lsh NUMBER COUNT)
- Shift the bits in NUMBER by COUNT bits to the left, a negative COUNT means
- shift right.
- ::end:: */
- {
- DECLARE1(num, NUMBERP);
- DECLARE2(shift, NUMBERP);
- if(VNUM(shift) > 0)
- return(newnumber(VNUM(num) << VNUM(shift)));
- return(newnumber(VNUM(num) >> -VNUM(shift)));
- }
-
- _PR VALUE cmd_zerop(VALUE);
- DEFUN("zerop", cmd_zerop, subr_zerop, (VALUE num), V_Subr1, DOC_zerop) /*
- ::doc:zerop::
- (zerop NUMBER)
- t if NUMBER is zero.
- ::end:: */
- {
- if(NUMBERP(num) && (VNUM(num) == 0))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_null(VALUE);
- DEFUN("null", cmd_null, subr_null, (VALUE arg), V_Subr1, DOC_null) /*
- ::doc:null::
- (null ARG)
- Returns t if ARG is nil.
- ::end:: */
- {
- if(NILP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_atom(VALUE);
- DEFUN("atom", cmd_atom, subr_atom, (VALUE arg), V_Subr1, DOC_atom) /*
- ::doc:atom::
- (atom ARG)
- Returns t if ARG is not a cons-cell.
- ::end:: */
- {
- if(!CONSP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_consp(VALUE);
- DEFUN("consp", cmd_consp, subr_consp, (VALUE arg), V_Subr1, DOC_consp) /*
- ::doc:consp::
- (consp ARG)
- Returns t if ARG is a cons-cell.
- ::end:: */
- {
- if(CONSP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_listp(VALUE);
- DEFUN("listp", cmd_listp, subr_listp, (VALUE arg), V_Subr1, DOC_listp) /*
- ::doc:listp::
- (listp ARG)
- Returns t if ARG is a list, (either a cons-cell or nil).
- ::end:: */
- {
- if(NILP(arg) || CONSP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_numberp(VALUE);
- DEFUN("numberp", cmd_numberp, subr_numberp, (VALUE arg), V_Subr1, DOC_numberp) /*
- ::doc:numberp::
- (numberp ARG)
- Return t if ARG is a number.
- ::end:: */
- {
- if(NUMBERP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_stringp(VALUE);
- DEFUN("stringp", cmd_stringp, subr_stringp, (VALUE arg), V_Subr1, DOC_stringp) /*
- ::doc:stringp::
- (stringp ARG)
- Returns t is ARG is a string.
- ::end:: */
- {
- if(STRINGP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_vectorp(VALUE);
- DEFUN("vectorp", cmd_vectorp, subr_vectorp, (VALUE arg), V_Subr1, DOC_vectorp) /*
- ::doc:vectorp::
- (vectorp ARG)
- Returns t if ARG is a vector.
- ::end:: */
- {
- if(VECTORP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_functionp(VALUE);
- DEFUN("functionp", cmd_functionp, subr_functionp, (VALUE arg), V_Subr1, DOC_functionp) /*
- ::doc:functionp::
- (functionp ARG)
- Returns t if ARG is a function (ie, a symbol or a list whose car is the
- symbol `lambda'
- ::end:: */
- {
- if(SYMBOLP(arg))
- {
- if(!(arg = VSYM(arg)->sym_Function))
- return(sym_nil);
- }
- switch(VTYPE(arg))
- {
- case V_Subr0:
- case V_Subr1:
- case V_Subr2:
- case V_Subr3:
- case V_Subr4:
- case V_Subr5:
- case V_SubrN:
- return(sym_t);
- case V_Cons:
- arg = VCAR(arg);
- if((arg == sym_lambda) || (arg == sym_autoload))
- return(sym_t);
- /* FALL THROUGH */
- default:
- return(sym_nil);
- }
- }
-
- _PR VALUE cmd_special_form_p(VALUE);
- DEFUN("special-form-p", cmd_special_form_p, subr_special_form_p, (VALUE arg), V_Subr1, DOC_special_form_p) /*
- ::doc:special_form_p::
- (special-form-p ARG)
- Returns t if ARG is a special-form.
- ::end:: */
- {
- if(SYMBOLP(arg))
- {
- if(!(arg = VSYM(arg)->sym_Function))
- return(sym_nil);
- }
- if(VTYPEP(arg, V_SF))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_keymapp(VALUE);
- DEFUN("keymapp", cmd_keymapp, subr_keymapp, (VALUE arg), V_Subr1, DOC_keymapp) /*
- ::doc:keymapp::
- (keymapp ARG)
- Returns t if ARG is a keytab or a keylist.
- ::end:: */
- {
- if(VTYPEP(arg, V_Keytab) || VTYPEP(arg, V_Keylist))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_subr_p(VALUE arg);
- DEFUN("subr-p", cmd_subr_p, subr_subr_p, (VALUE arg), V_Subr1, DOC_subr_p) /*
- ::doc:subr_p::
- (subr-p ARG)
- Returns t if arg is a primitive function.
- ::end:: */
- {
- switch(VTYPE(arg))
- {
- case V_Subr0:
- case V_Subr1:
- case V_Subr2:
- case V_Subr3:
- case V_Subr4:
- case V_Subr5:
- case V_SubrN:
- case V_SF:
- case V_Var:
- return(sym_t);
- default:
- return(sym_nil);
- }
- }
-
- _PR VALUE cmd_subr_documentation(VALUE subr, VALUE useVar);
- DEFUN("subr-documentation", cmd_subr_documentation, subr_subr_documentation, (VALUE subr, VALUE useVar), V_Subr2, DOC_subr_documentation) /*
- ::doc:subr_documentation::
- (subr-documentation SUBR [USE-VAR])
- Returns the doc-string associated with SUBR.
- ::end:: */
- {
- if(SYMBOLP(subr))
- {
- if(NILP(useVar))
- {
- if(VSYM(subr)->sym_Function)
- subr = VSYM(subr)->sym_Function;
- }
- else
- {
- if(VSYM(subr)->sym_Value)
- subr = VSYM(subr)->sym_Value;
- }
- }
- switch(VTYPE(subr))
- {
- case V_Subr0:
- case V_Subr1:
- case V_Subr2:
- case V_Subr3:
- case V_Subr4:
- case V_Subr5:
- case V_SubrN:
- case V_SF:
- case V_Var:
- return(cmd_read_file_from_to(MKSTR(DOC_FILE),
- newnumber(VSUBR(subr)->subr_DocIndex),
- newnumber((int)'\f')));
- default:
- return(sym_nil);
- }
- }
-
- _PR VALUE cmd_subr_name(VALUE subr, VALUE useVar);
- DEFUN("subr-name", cmd_subr_name, subr_subr_name, (VALUE subr, VALUE useVar), V_Subr2, DOC_subr_name) /*
- ::doc:subr_name::
- (subr-name SUBR [USE-VAR])
- Returns the name (a string) associated with SUBR.
- ::end:: */
- {
- if(SYMBOLP(subr))
- {
- if(NILP(useVar))
- {
- if(VSYM(subr)->sym_Function)
- subr = VSYM(subr)->sym_Function;
- }
- else
- {
- if(VSYM(subr)->sym_Value)
- subr = VSYM(subr)->sym_Value;
- }
- }
- switch(VTYPE(subr))
- {
- case V_Subr0:
- case V_Subr1:
- case V_Subr2:
- case V_Subr3:
- case V_Subr4:
- case V_Subr5:
- case V_SubrN:
- case V_SF:
- case V_Var:
- return(VSUBR(subr)->subr_Name);
- default:
- return(sym_nil);
- }
- }
-
- _PR VALUE cmd_eval_hook(VALUE);
- DEFUN("eval-hook", cmd_eval_hook, subr_eval_hook, (VALUE args), V_SubrN, DOC_eval_hook) /*
- ::doc:eval_hook::
- (eval-hook HOOK ARGS...)
- Evaluate the hook, HOOK (a symbol), with arguments ARGS
-
- The way hooks work is that the hook-symbol's value is a list of functions
- to call. Each function in turn is called with ARGS until one returns non-nil,
- this non-nil value is then the result of `eval-hook'. If all functions return
- nil then `eval-hook' returns nil.
- ::end:: */
- {
- if(CONSP(args))
- {
- VALUE hook = VCAR(args);
- VALUE alist = VCDR(args);
- VALUE res = sym_nil;
- GCVAL gcv_alist, gcv_hook;
- PUSHGC(gcv_alist, alist);
- switch(VTYPE(hook))
- {
- case V_StaticString:
- case V_String:
- if(!(hook = cmd_find_symbol(hook, sym_nil)))
- goto end;
- /* FALL THROUGH */
- case V_Symbol:
- if(!(hook = cmd_symbol_value(hook)))
- goto end;
- break;
- }
- PUSHGC(gcv_hook, hook);
- while(res && NILP(res) && CONSP(hook))
- {
- res = funcall(VCAR(hook), alist);
- hook = VCDR(hook);
- }
- POPGC;
- end:
- POPGC;
- return(res);
- }
- return(NULL);
- }
- _PR VALUE cmd_eval_hook2(VALUE hook, VALUE arg);
- DEFUN("eval-hook2", cmd_eval_hook2, subr_eval_hook2, (VALUE hook, VALUE arg), V_Subr2, DOC_eval_hook2) /*
- ::doc:eval_hook2::
- (eval-hook2 HOOK ARG)
- Similar to `eval-hook', the only reason this function exists is because it
- is easier to call a 2-argument function from C than an N-argument function.
- ::end:: */
- {
- VALUE res = sym_nil, alist;
- /* Not possible to use GCVAL's since this is often called from C code
- which may not be protected. */
- int oldgci = GCinhibit;
- if(!(alist = cmd_cons(arg, sym_nil)))
- return(NULL);
- GCinhibit = TRUE;
- switch(VTYPE(hook))
- {
- case V_StaticString:
- case V_String:
- if(!(hook = cmd_find_symbol(hook, sym_nil)))
- goto end;
- /* FALL THROUGH */
- case V_Symbol:
- if(!(hook = cmd_symbol_value(hook)))
- goto end;
- break;
- }
- while(res && NILP(res) && CONSP(hook))
- {
- res = funcall(VCAR(hook), alist);
- hook = VCDR(hook);
- }
- end:
- GCinhibit = oldgci;
- return(res);
- }
-
- _PR VALUE cmd_catch(VALUE);
- DEFUN("catch", cmd_catch, subr_catch, (VALUE args), V_SF, DOC_catch) /*
- ::doc:catch::
- (catch TAG FORMS...) <SPECIAL-FORM>
- Evaluates FORMS, non-local exits are allowed with `(throw TAG)'.
- The value of `catch' is either the value of the last FORM or the
- value given to the throw command.
-
- There are several pre-defined `catch'es which are,
- 'defun
- Around all defuns, the `return' command uses this, it basically does
- (throw 'defun X).
- 'exit
- Exits one level of recursive-editing (but doesn't work in the top
- level.
- 'top-level
- At the top-level recursive-edit (ie, the one which you're in when
- the editor is started).
- 'quit
- Kills the editor.
- ::end:: */
- /* Non-local exits don't bother with jmp_buf's and the like, they just
- unwind normally through all levels of recursion with a NULL result.
- This is slow but it's easy to work with. */
- {
- if(CONSP(args))
- {
- VALUE tag, res = NULL;
- GCVAL gcv_args, gcv_tag;
- PUSHGC(gcv_args, args);
- tag = cmd_eval(VCAR(args));
- if(tag)
- {
- PUSHGC(gcv_tag, tag);
- if(!(res = cmd_progn(VCDR(args))))
- {
- if(ThrowValue && (VCAR(ThrowValue) == tag))
- {
- res = VCDR(ThrowValue);
- ThrowValue = NULL;
- }
- }
- POPGC;
- }
- POPGC;
- return(res);
- }
- return(NULL);
- }
-
- _PR VALUE cmd_throw(VALUE, VALUE);
- DEFUN("throw", cmd_throw, subr_throw, (VALUE tag, VALUE val), V_Subr2, DOC_throw) /*
- ::doc:throw::
- (throw TAG VALUE)
- Performs a non-local exit to the `catch' waiting for TAG and return
- VALUE from it. TAG and VALUE are both evaluated fully.
- ::end:: */
- {
- /* Only one thing can use `ThrowValue' at once. */
- if(!ThrowValue)
- ThrowValue = cmd_cons(tag, val);
- return(NULL);
- }
-
- _PR VALUE cmd_return(VALUE);
- DEFUN("return", cmd_return, subr_return, (VALUE arg), V_Subr1, DOC_return) /*
- ::doc:return::
- (return VALUE)
- Arranges it so that the innermost defun returns VALUE as its result, this
- is achieved by doing what amounts to `(throw 'defun VALUE)'.
- ::end:: */
- {
- if(!ThrowValue)
- ThrowValue = cmd_cons(sym_defun, arg);
- return(NULL);
- }
-
- _PR VALUE cmd_unwind_protect(VALUE);
- DEFUN("unwind-protect", cmd_unwind_protect, subr_unwind_protect, (VALUE args), V_SF, DOC_unwind_protect) /*
- ::doc:unwind_protect::
- (unwind-protect BODY CLEANUP-FORMS...) <SPECIAL-FORM>
- Eval and return the value of BODY guaranteeing that the CLEANUP-FORMS will
- be evalled no matter what happens (ie, error, non-local exit, etc) while
- BODY is being evaluated.
- ::end:: */
- {
- if(CONSP(args))
- {
- VALUE res;
- GCVAL gcv_args, gcv_res;
- PUSHGC(gcv_args, args);
- res = cmd_eval(VCAR(args));
- PUSHGC(gcv_res, res);
- if(!cmd_progn(VCDR(args)))
- res = NULL;
- POPGC; POPGC;
- return(res);
- }
- return(NULL);
- }
-
- void
- lispcmds_init(void)
- {
- ADD_SUBR(subr_quote);
- ADD_SUBR(subr_function);
- ADD_SUBR(subr_defmacro);
- ADD_SUBR(subr_defun);
- ADD_SUBR(subr_car);
- ADD_SUBR(subr_cdr);
- ADD_SUBR(subr_list);
- ADD_SUBR(subr_copy_list);
- ADD_SUBR(subr_make_list);
- ADD_SUBR(subr_append);
- ADD_SUBR(subr_nconc);
- ADD_SUBR(subr_rplaca);
- ADD_SUBR(subr_rplacd);
- ADD_SUBR(subr_reverse);
- ADD_SUBR(subr_nreverse);
- ADD_SUBR(subr_assoc);
- ADD_SUBR(subr_assq);
- ADD_SUBR(subr_nth);
- ADD_SUBR(subr_nthcdr);
- ADD_SUBR(subr_last);
- ADD_SUBR(subr_mapcar);
- ADD_SUBR(subr_mapc);
- ADD_SUBR(subr_member);
- ADD_SUBR(subr_memq);
- ADD_SUBR(subr_delete);
- ADD_SUBR(subr_delq);
- ADD_SUBR(subr_delete_if);
- ADD_SUBR(subr_delete_if_not);
- ADD_SUBR(subr_vector);
- ADD_SUBR(subr_make_vector);
- ADD_SUBR(subr_aset);
- ADD_SUBR(subr_aref);
- ADD_SUBR(subr_make_string);
- ADD_SUBR(subr_concat);
- ADD_SUBR(subr_length);
- ADD_SUBR(subr_prog1);
- ADD_SUBR(subr_prog2);
- ADD_SUBR(subr_while);
- ADD_SUBR(subr_if);
- ADD_SUBR(subr_when);
- ADD_SUBR(subr_unless);
- ADD_SUBR(subr_cond);
- ADD_SUBR(subr_apply);
- ADD_SUBR(subr_load);
- ADD_SUBR(subr_plus);
- ADD_SUBR(subr_minus);
- ADD_SUBR(subr_product);
- ADD_SUBR(subr_divide);
- ADD_SUBR(subr_mod);
- ADD_SUBR(subr_bit_not);
- ADD_SUBR(subr_not);
- ADD_SUBR(subr_bit_or);
- ADD_SUBR(subr_or);
- ADD_SUBR(subr_bit_and);
- ADD_SUBR(subr_and);
- ADD_SUBR(subr_equal);
- ADD_SUBR(subr_eq);
- ADD_SUBR(subr_string_head_eq);
- ADD_SUBR(subr_num_eq);
- ADD_SUBR(subr_num_noteq);
- ADD_SUBR(subr_gtthan);
- ADD_SUBR(subr_gethan);
- ADD_SUBR(subr_ltthan);
- ADD_SUBR(subr_lethan);
- ADD_SUBR(subr_plus1);
- ADD_SUBR(subr_sub1);
- ADD_SUBR(subr_lsh);
- ADD_SUBR(subr_zerop);
- ADD_SUBR(subr_null);
- ADD_SUBR(subr_atom);
- ADD_SUBR(subr_consp);
- ADD_SUBR(subr_listp);
- ADD_SUBR(subr_numberp);
- ADD_SUBR(subr_stringp);
- ADD_SUBR(subr_vectorp);
- ADD_SUBR(subr_functionp);
- ADD_SUBR(subr_special_form_p);
- ADD_SUBR(subr_keymapp);
- ADD_SUBR(subr_subr_p);
- ADD_SUBR(subr_subr_documentation);
- ADD_SUBR(subr_subr_name);
- ADD_SUBR(subr_eval_hook);
- ADD_SUBR(subr_eval_hook2);
- ADD_SUBR(subr_catch);
- ADD_SUBR(subr_throw);
- ADD_SUBR(subr_return);
- ADD_SUBR(subr_unwind_protect);
- INTERN(sym_load_path, "load-path");
- VSYM(sym_load_path)->sym_Value = list_2(NullString, MKSTR(LISP_LIB_DIR));
- DOC_VAR(sym_load_path, DOC_load_path);
- INTERN(sym_lisp_lib_dir, "lisp-lib-dir");
- VSYM(sym_lisp_lib_dir)->sym_Value = MKSTR(LISP_LIB_DIR);
- DOC_VAR(sym_lisp_lib_dir, DOC_lisp_lib_dir);
- }
-